diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 4a515817c..0ec14e181 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1732,7 +1732,23 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitAwait(Await inst, TranslationContext context) { - var value = Translate(inst.Value); + IType expectedType = null; + if (inst.GetAwaiterMethod != null) { + if (inst.GetAwaiterMethod.IsStatic) { + expectedType = inst.GetAwaiterMethod.Parameters.FirstOrDefault()?.Type; + } else { + expectedType = inst.GetAwaiterMethod.DeclaringType; + } + } + + var value = Translate(inst.Value, typeHint: expectedType); + if (value.Expression is DirectionExpression) { + // we can deference the managed reference by stripping away the 'ref' + value = value.UnwrapChild(((DirectionExpression)value.Expression).Expression); + } + if (expectedType != null) { + value = value.ConvertTo(expectedType, this, allowImplicitConversion: true); + } return new UnaryOperatorExpression(UnaryOperatorType.Await, value.Expression) .WithILInstruction(inst) .WithRR(new ResolveResult(inst?.GetResultMethod.ReturnType ?? SpecialType.UnknownType)); diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs index 0f9a5531b..64614fddd 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs @@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow ILVariable doFinallyBodies; // These fields are set by AnalyzeStateMachine(): + int smallestAwaiterVarIndex; // For each block containing an 'await', stores the awaiter variable, and the field storing the awaiter // across the yield point. @@ -90,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow DetectAwaitPattern(function); context.Step("Translate fields to local accesses", function); + MarkGeneratedVariables(function); YieldReturnDecompiler.TranslateFieldsToLocalAccess(function, function, fieldToParameterMap); FinalizeInlineMoveNext(function); @@ -444,6 +446,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow void AnalyzeStateMachine(ILFunction function) { context.Step("AnalyzeStateMachine()", function); + smallestAwaiterVarIndex = int.MaxValue; foreach (var container in function.Descendants.OfType()) { // Use a separate state range analysis per container. var sra = new StateRangeAnalysis(StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar); @@ -464,6 +467,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow block.Instructions.Add(new InvalidBranch("Could not find block for state " + state)); } awaitBlocks.Add(block, (awaiterVar, awaiterField)); + if (awaiterVar.Index < smallestAwaiterVarIndex) { + smallestAwaiterVarIndex = awaiterVar.Index; + } } } } @@ -731,5 +737,16 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow return block.Instructions[pos].MatchBranch(completedBlock); } #endregion + + void MarkGeneratedVariables(ILFunction function) + { + // Variables after the awaiters are usually compiler-generated; + // so mark them as stack slots. + foreach (var v in function.Variables) { + if (v.Kind == VariableKind.Local && v.Index >= smallestAwaiterVarIndex) { + v.Kind = VariableKind.StackSlot; + } + } + } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 86469b622..de7f53dfe 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -240,8 +240,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms case OpCode.CallVirt: return !((CallVirt)parent).Method.IsStatic; case OpCode.LdFlda: - // TODO : Reimplement Await - //case OpCode.Await: + case OpCode.Await: return true; } } diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index ef4fa53a1..5e6e08e13 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -35,7 +35,9 @@ using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy { /// - /// Decompiler logic for C#. + /// C# decompiler integration into ILSpy. + /// Note: if you're interested in using the decompiler without the ILSpy UI, + /// please directly use the CSharpDecompiler class. /// [Export(typeof(Language))] public class CSharpLanguage : Language