350 lines
20 KiB
C#
350 lines
20 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using Microsoft.CodeAnalysis.CSharp.Emit.NoPia;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.CodeGen;
|
|
using Microsoft.CodeAnalysis.Emit;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal class AsyncMethodToStateMachineRewriter : MethodToStateMachineRewriter
|
|
{
|
|
protected readonly MethodSymbol _method;
|
|
|
|
protected readonly FieldSymbol _asyncMethodBuilderField;
|
|
|
|
protected readonly AsyncMethodBuilderMemberCollection _asyncMethodBuilderMemberCollection;
|
|
|
|
protected readonly LabelSymbol _exprReturnLabel;
|
|
|
|
private readonly LabelSymbol _exitLabel;
|
|
|
|
private readonly LocalSymbol? _exprRetValue;
|
|
|
|
private readonly LoweredDynamicOperationFactory _dynamicFactory;
|
|
|
|
private readonly Dictionary<TypeSymbol, FieldSymbol> _awaiterFields;
|
|
|
|
private int _nextAwaiterId;
|
|
|
|
private readonly Dictionary<BoundValuePlaceholderBase, BoundExpression> _placeholderMap;
|
|
|
|
protected sealed override string EncMissingStateMessage => CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod;
|
|
|
|
protected sealed override StateMachineState FirstIncreasingResumableState => (StateMachineState)0;
|
|
|
|
internal AsyncMethodToStateMachineRewriter(MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, FieldSymbol? instanceIdField, IReadOnlySet<Symbol> hoistedVariables, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder, VariableSlotAllocator? slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics)
|
|
: base(F, method, state, instanceIdField, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics)
|
|
{
|
|
_method = method;
|
|
_asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
|
|
_asyncMethodBuilderField = builder;
|
|
_exprReturnLabel = F.GenerateLabel("exprReturn");
|
|
_exitLabel = F.GenerateLabel("exitLabel");
|
|
_exprRetValue = (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, F.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)20) : null);
|
|
_dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal);
|
|
_awaiterFields = new Dictionary<TypeSymbol, FieldSymbol>(SymbolEqualityComparer.IgnoringDynamicTupleNamesAndNullability);
|
|
_nextAwaiterId = ((slotAllocatorOpt != null) ? slotAllocatorOpt.PreviousAwaiterSlotCount : 0);
|
|
_placeholderMap = new Dictionary<BoundValuePlaceholderBase, BoundExpression>();
|
|
}
|
|
|
|
private FieldSymbol GetAwaiterField(TypeSymbol awaiterType)
|
|
{
|
|
if (!_awaiterFields.TryGetValue(awaiterType, out FieldSymbol value))
|
|
{
|
|
int slotIndex = default(int);
|
|
if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousAwaiterSlotIndex(((PEModuleBuilder<CSharpCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, EmbeddedTypesManager, ModuleCompilationState>)F.ModuleBuilderOpt).Translate(awaiterType, F.Syntax, ((BindingDiagnosticBag)F.Diagnostics).DiagnosticBag), ((BindingDiagnosticBag)F.Diagnostics).DiagnosticBag, ref slotIndex))
|
|
{
|
|
slotIndex = _nextAwaiterId++;
|
|
}
|
|
string name = GeneratedNames.AsyncAwaiterFieldName(slotIndex);
|
|
value = F.StateMachineField(awaiterType, name, (SynthesizedLocalKind)256, slotIndex);
|
|
_awaiterFields.Add(awaiterType, value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
|
|
{
|
|
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
|
|
F.CurrentFunction = moveNextMethod;
|
|
BoundStatement statement = VisitBody(body);
|
|
MethodToStateMachineRewriter.TryUnwrapBoundStateMachineScope(ref statement, out var hoistedLocals);
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
instance.Add(F.HiddenSequencePoint());
|
|
instance.Add((BoundStatement)F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField)));
|
|
instance.Add(CacheThisIfNeeded());
|
|
LocalSymbol exceptionLocal = F.SynthesizedLocal(F.WellKnownType((WellKnownType)52), null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2));
|
|
instance.Add(GenerateTopLevelTry(F.Block(ImmutableArray<LocalSymbol>.Empty, F.HiddenSequencePoint(), Dispatch(isOutermost: true), statement), F.CatchBlocks(GenerateExceptionHandling(exceptionLocal, hoistedLocals))));
|
|
instance.Add((BoundStatement)F.Label(_exprReturnLabel));
|
|
BoundExpressionStatement boundExpressionStatement = F.Assignment(F.Field(F.This(), stateField), F.Literal((StateMachineState)(-2)));
|
|
if (!(body.Syntax is BlockSyntax blockSyntax))
|
|
{
|
|
instance.Add((BoundStatement)boundExpressionStatement);
|
|
}
|
|
else
|
|
{
|
|
SyntheticBoundNodeFactory f = F;
|
|
SyntaxToken closeBraceToken = blockSyntax.CloseBraceToken;
|
|
instance.Add(f.SequencePointWithSpan(blockSyntax, ((SyntaxToken)(ref closeBraceToken)).Span, boundExpressionStatement));
|
|
instance.Add(F.HiddenSequencePoint());
|
|
}
|
|
instance.Add(GenerateHoistedLocalsCleanup(hoistedLocals));
|
|
instance.Add(GenerateSetResultCall());
|
|
instance.Add((BoundStatement)F.Label(_exitLabel));
|
|
instance.Add((BoundStatement)F.Return());
|
|
ImmutableArray<BoundStatement> statements = instance.ToImmutableAndFree();
|
|
ArrayBuilder<LocalSymbol> instance2 = ArrayBuilder<LocalSymbol>.GetInstance();
|
|
instance2.Add(cachedState);
|
|
if ((object)cachedThis != null)
|
|
{
|
|
instance2.Add(cachedThis);
|
|
}
|
|
if ((object)_exprRetValue != null)
|
|
{
|
|
instance2.Add(_exprRetValue);
|
|
}
|
|
BoundStatement boundStatement = F.SequencePoint(body.Syntax, F.Block(instance2.ToImmutableAndFree(), statements));
|
|
if (hoistedLocals.Length > 0)
|
|
{
|
|
boundStatement = MakeStateMachineScope(hoistedLocals, boundStatement);
|
|
}
|
|
if (instrumentation != null)
|
|
{
|
|
boundStatement = F.Block(ImmutableArray.Create(instrumentation.Local), instrumentation.Prologue, F.Try(F.Block(boundStatement), ImmutableArray<BoundCatchBlock>.Empty, F.Block(instrumentation.Epilogue)));
|
|
}
|
|
F.CloseMethod(boundStatement);
|
|
}
|
|
|
|
protected virtual BoundStatement GenerateTopLevelTry(BoundBlock tryBlock, ImmutableArray<BoundCatchBlock> catchBlocks)
|
|
{
|
|
return F.Try(tryBlock, catchBlocks);
|
|
}
|
|
|
|
protected virtual BoundStatement GenerateSetResultCall()
|
|
{
|
|
return F.ExpressionStatement(F.Call(F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation) ? ImmutableArray.Create((BoundExpression)F.Local(_exprRetValue)) : ImmutableArray<BoundExpression>.Empty));
|
|
}
|
|
|
|
protected BoundCatchBlock GenerateExceptionHandling(LocalSymbol exceptionLocal, ImmutableArray<StateMachineFieldSymbol> hoistedLocals)
|
|
{
|
|
BoundStatement boundStatement = F.ExpressionStatement(F.AssignmentExpression(F.Field(F.This(), stateField), F.Literal((StateMachineState)(-2))));
|
|
BoundStatement boundStatement2 = GenerateSetExceptionCall(exceptionLocal);
|
|
return new BoundCatchBlock(F.Syntax, ImmutableArray.Create(exceptionLocal), F.Local(exceptionLocal), exceptionLocal.Type, null, null, F.Block(boundStatement, GenerateHoistedLocalsCleanup(hoistedLocals), boundStatement2, GenerateReturn(finished: false)), isSynthesizedAsyncCatchAll: true);
|
|
}
|
|
|
|
protected BoundStatement GenerateHoistedLocalsCleanup(ImmutableArray<StateMachineFieldSymbol> hoistedLocals)
|
|
{
|
|
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
ImmutableArray<StateMachineFieldSymbol>.Enumerator enumerator = hoistedLocals.GetEnumerator();
|
|
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = default(CompoundUseSiteInfo<AssemblySymbol>);
|
|
while (enumerator.MoveNext())
|
|
{
|
|
StateMachineFieldSymbol current = enumerator.Current;
|
|
useSiteInfo._002Ector((BindingDiagnosticBag<AssemblySymbol>)(object)F.Diagnostics, F.Compilation.Assembly);
|
|
bool num = current.Type.IsManagedType(ref useSiteInfo);
|
|
((BindingDiagnosticBag<AssemblySymbol>)(object)F.Diagnostics).Add(current.GetFirstLocationOrNone(), useSiteInfo);
|
|
if (num)
|
|
{
|
|
instance.Add((BoundStatement)F.Assignment(F.Field(F.This(), current), F.NullOrDefault(current.Type)));
|
|
}
|
|
}
|
|
return F.Block(instance.ToImmutableAndFree());
|
|
}
|
|
|
|
protected virtual BoundStatement GenerateSetExceptionCall(LocalSymbol exceptionLocal)
|
|
{
|
|
return F.ExpressionStatement(F.Call(F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetException, F.Local(exceptionLocal)));
|
|
}
|
|
|
|
protected sealed override BoundStatement GenerateReturn(bool finished)
|
|
{
|
|
return F.Goto(_exitLabel);
|
|
}
|
|
|
|
protected virtual BoundStatement VisitBody(BoundStatement body)
|
|
{
|
|
return (BoundStatement)Visit(body);
|
|
}
|
|
|
|
public sealed override BoundNode VisitExpressionStatement(BoundExpressionStatement node)
|
|
{
|
|
if (node.Expression.Kind == BoundKind.AwaitExpression)
|
|
{
|
|
return VisitAwaitExpression((BoundAwaitExpression)node.Expression, null);
|
|
}
|
|
if (node.Expression.Kind == BoundKind.AssignmentOperator)
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)node.Expression;
|
|
if (boundAssignmentOperator.Right.Kind == BoundKind.AwaitExpression)
|
|
{
|
|
return VisitAwaitExpression((BoundAwaitExpression)boundAssignmentOperator.Right, boundAssignmentOperator.Left);
|
|
}
|
|
}
|
|
BoundExpression boundExpression = (BoundExpression)Visit(node.Expression);
|
|
if (boundExpression == null)
|
|
{
|
|
return F.StatementList();
|
|
}
|
|
return node.Update(boundExpression);
|
|
}
|
|
|
|
public sealed override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs", 333);
|
|
}
|
|
|
|
public sealed override BoundNode VisitBadExpression(BoundBadExpression node)
|
|
{
|
|
return node;
|
|
}
|
|
|
|
private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
|
|
{
|
|
BoundExpression boundExpression = (BoundExpression)Visit(node.Expression);
|
|
BoundAwaitableValuePlaceholder awaitableInstancePlaceholder = node.AwaitableInfo.AwaitableInstancePlaceholder;
|
|
if (awaitableInstancePlaceholder != null)
|
|
{
|
|
_placeholderMap.Add(awaitableInstancePlaceholder, boundExpression);
|
|
}
|
|
BoundExpression boundExpression2 = (node.AwaitableInfo.IsDynamic ? MakeCallMaybeDynamic(boundExpression, null, "GetAwaiter") : ((BoundExpression)Visit(node.AwaitableInfo.GetAwaiter)));
|
|
resultPlace = (BoundExpression)Visit(resultPlace);
|
|
MethodSymbol methodSymbol = VisitMethodSymbol(node.AwaitableInfo.GetResult);
|
|
MethodSymbol getIsCompletedMethod = (((object)node.AwaitableInfo.IsCompleted != null) ? VisitMethodSymbol(node.AwaitableInfo.IsCompleted.GetMethod) : null);
|
|
TypeSymbol type = VisitType(node.Type);
|
|
if (awaitableInstancePlaceholder != null)
|
|
{
|
|
_placeholderMap.Remove(awaitableInstancePlaceholder);
|
|
}
|
|
LocalSymbol localSymbol = F.SynthesizedLocal(boundExpression2.Type, node.Syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)33);
|
|
BoundBlock boundBlock = F.Block(F.Assignment(F.Local(localSymbol), boundExpression2), F.HiddenSequencePoint(), F.If(F.Not(GenerateGetIsCompleted(localSymbol, getIsCompletedMethod)), GenerateAwaitForIncompleteTask(localSymbol, node.DebugInfo)));
|
|
BoundExpression boundExpression3 = MakeCallMaybeDynamic(F.Local(localSymbol), methodSymbol, "GetResult", resultPlace == null);
|
|
BoundStatement boundStatement = ((resultPlace != null && !type.IsVoidType()) ? F.Assignment(resultPlace, boundExpression3) : F.ExpressionStatement(boundExpression3));
|
|
return F.Block(ImmutableArray.Create(localSymbol), boundBlock, boundStatement);
|
|
}
|
|
|
|
public override BoundNode VisitAwaitableValuePlaceholder(BoundAwaitableValuePlaceholder node)
|
|
{
|
|
return _placeholderMap[node];
|
|
}
|
|
|
|
private BoundExpression MakeCallMaybeDynamic(BoundExpression receiver, MethodSymbol methodSymbol = null, string methodName = null, bool resultsDiscarded = false)
|
|
{
|
|
if ((object)methodSymbol != null)
|
|
{
|
|
if (!methodSymbol.IsStatic)
|
|
{
|
|
return F.Call(receiver, methodSymbol);
|
|
}
|
|
return F.StaticCall(methodSymbol.ContainingType, methodSymbol, receiver);
|
|
}
|
|
return _dynamicFactory.MakeDynamicMemberInvocation(methodName, receiver, ImmutableArray<TypeWithAnnotations>.Empty, ImmutableArray<BoundExpression>.Empty, ImmutableArray<string>.Empty, ImmutableArray<RefKind>.Empty, hasImplicitReceiver: false, resultsDiscarded).ToExpression();
|
|
}
|
|
|
|
private BoundExpression GenerateGetIsCompleted(LocalSymbol awaiterTemp, MethodSymbol getIsCompletedMethod)
|
|
{
|
|
if (awaiterTemp.Type.IsDynamic())
|
|
{
|
|
return _dynamicFactory.MakeDynamicConversion(_dynamicFactory.MakeDynamicGetMember(F.Local(awaiterTemp), "IsCompleted", resultIndexed: false).ToExpression(), isExplicit: true, isArrayIndex: false, isChecked: false, F.SpecialType((SpecialType)7)).ToExpression();
|
|
}
|
|
return F.Call(F.Local(awaiterTemp), getIsCompletedMethod);
|
|
}
|
|
|
|
private BoundBlock GenerateAwaitForIncompleteTask(LocalSymbol awaiterTemp, BoundAwaitExpressionDebugInfo debugInfo)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
|
|
SyntaxNode declaratorSyntax = awaiterTemp.GetDeclaratorSyntax();
|
|
AddResumableState(declaratorSyntax, debugInfo.AwaitId, out StateMachineState state, out GeneratedLabelSymbol resumeLabel);
|
|
TypeSymbol typeSymbol = (awaiterTemp.Type.IsVerifierReference() ? F.SpecialType((SpecialType)1) : awaiterTemp.Type);
|
|
FieldSymbol awaiterField = GetAwaiterField(typeSymbol);
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
instance.Add((BoundStatement)GenerateSetBothStates(state));
|
|
instance.Add(F.NoOp(NoOpStatementFlavor.AwaitYieldPoint));
|
|
instance.Add((BoundStatement)F.Assignment(F.Field(F.This(), awaiterField), TypeSymbol.Equals(awaiterField.Type, awaiterTemp.Type, (TypeCompareKind)0) ? F.Local(awaiterTemp) : F.Convert(typeSymbol, F.Local(awaiterTemp))));
|
|
instance.Add(awaiterTemp.Type.IsDynamic() ? GenerateAwaitOnCompletedDynamic(awaiterTemp) : GenerateAwaitOnCompleted(awaiterTemp.Type, awaiterTemp));
|
|
instance.Add(GenerateReturn(finished: false));
|
|
if (((CompilationOptions)F.Compilation.Options).EnableEditAndContinue)
|
|
{
|
|
for (int i = 0; i < debugInfo.ReservedStateMachineCount; i++)
|
|
{
|
|
AwaitDebugId awaitId = debugInfo.AwaitId;
|
|
AddResumableState(declaratorSyntax, new AwaitDebugId((byte)(((AwaitDebugId)(ref awaitId)).RelativeStateOrdinal + 1 + i)), out StateMachineState _, out GeneratedLabelSymbol resumeLabel2);
|
|
instance.Add((BoundStatement)F.Label(resumeLabel2));
|
|
}
|
|
}
|
|
instance.Add((BoundStatement)F.Label(resumeLabel));
|
|
instance.Add(F.NoOp(NoOpStatementFlavor.AwaitResumePoint));
|
|
instance.Add((BoundStatement)F.Assignment(F.Local(awaiterTemp), TypeSymbol.Equals(awaiterTemp.Type, awaiterField.Type, (TypeCompareKind)0) ? F.Field(F.This(), awaiterField) : F.Convert(awaiterTemp.Type, F.Field(F.This(), awaiterField))));
|
|
instance.Add((BoundStatement)F.Assignment(F.Field(F.This(), awaiterField), F.NullOrDefault(awaiterField.Type)));
|
|
instance.Add((BoundStatement)GenerateSetBothStates((StateMachineState)(-1)));
|
|
return F.Block(instance.ToImmutableAndFree());
|
|
}
|
|
|
|
private BoundStatement GenerateAwaitOnCompletedDynamic(LocalSymbol awaiterTemp)
|
|
{
|
|
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0055: Invalid comparison between Unknown and I4
|
|
LocalSymbol localSymbol = F.SynthesizedLocal(F.WellKnownType((WellKnownType)241), null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2));
|
|
LocalSymbol localSymbol2 = F.SynthesizedLocal(F.WellKnownType((WellKnownType)172), null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2));
|
|
LocalSymbol localSymbol3 = (((int)F.CurrentType.TypeKind == 2) ? F.SynthesizedLocal(F.CurrentType, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2)) : null);
|
|
ArrayBuilder<BoundStatement> instance = ArrayBuilder<BoundStatement>.GetInstance();
|
|
instance.Add((BoundStatement)F.Assignment(F.Local(localSymbol), F.As(F.Local(awaiterTemp), localSymbol.Type)));
|
|
if (localSymbol3 != null)
|
|
{
|
|
instance.Add((BoundStatement)F.Assignment(F.Local(localSymbol3), F.This()));
|
|
}
|
|
instance.Add(F.If(F.ObjectEqual(F.Local(localSymbol), F.Null(localSymbol.Type)), F.Block(ImmutableArray.Create(localSymbol2), F.Assignment(F.Local(localSymbol2), F.Convert(localSymbol2.Type, F.Local(awaiterTemp), Conversion.ExplicitReference)), F.ExpressionStatement(F.Call(F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.AwaitOnCompleted.Construct(localSymbol2.Type, F.This().Type), F.Local(localSymbol2), F.This(localSymbol3))), F.Assignment(F.Local(localSymbol2), F.NullOrDefault(localSymbol2.Type))), F.Block(F.ExpressionStatement(F.Call(F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.AwaitUnsafeOnCompleted.Construct(localSymbol.Type, F.This().Type), F.Local(localSymbol), F.This(localSymbol3))))));
|
|
instance.Add((BoundStatement)F.Assignment(F.Local(localSymbol), F.NullOrDefault(localSymbol.Type)));
|
|
return F.Block(SingletonOrPair(localSymbol, localSymbol3), instance.ToImmutableAndFree());
|
|
}
|
|
|
|
private BoundStatement GenerateAwaitOnCompleted(TypeSymbol loweredAwaiterType, LocalSymbol awaiterTemp)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0011: Invalid comparison between Unknown and I4
|
|
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
|
|
LocalSymbol localSymbol = (((int)F.CurrentType.TypeKind == 2) ? F.SynthesizedLocal(F.CurrentType, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2)) : null);
|
|
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
|
|
MethodSymbol method = (F.Compilation.Conversions.ClassifyImplicitConversionFromType(loweredAwaiterType, F.Compilation.GetWellKnownType((WellKnownType)241), ref useSiteInfo).IsImplicit ? _asyncMethodBuilderMemberCollection.AwaitUnsafeOnCompleted : _asyncMethodBuilderMemberCollection.AwaitOnCompleted).Construct(loweredAwaiterType, F.This().Type);
|
|
if (_asyncMethodBuilderMemberCollection.CheckGenericMethodConstraints)
|
|
{
|
|
method.CheckConstraints(new ConstraintsHelper.CheckConstraintsArgs(F.Compilation, F.Compilation.Conversions, includeNullability: false, F.Syntax.Location, Diagnostics));
|
|
}
|
|
BoundExpression boundExpression = F.Call(F.Field(F.This(), _asyncMethodBuilderField), method, F.Local(awaiterTemp), F.This(localSymbol));
|
|
if (localSymbol != null)
|
|
{
|
|
boundExpression = F.Sequence(ImmutableArray.Create(localSymbol), ImmutableArray.Create(F.AssignmentExpression(F.Local(localSymbol), F.This())), boundExpression);
|
|
}
|
|
return F.ExpressionStatement(boundExpression);
|
|
}
|
|
|
|
private static ImmutableArray<LocalSymbol> SingletonOrPair(LocalSymbol first, LocalSymbol secondOpt)
|
|
{
|
|
if (!(secondOpt == null))
|
|
{
|
|
return ImmutableArray.Create(first, secondOpt);
|
|
}
|
|
return ImmutableArray.Create(first);
|
|
}
|
|
|
|
public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node)
|
|
{
|
|
if (node.ExpressionOpt != null)
|
|
{
|
|
return F.Block(F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel));
|
|
}
|
|
return F.Goto(_exprReturnLabel);
|
|
}
|
|
}
|