Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
deba0cb
Handle basic await scenarios (#76121)
333fred Feb 18, 2025
212d206
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Feb 18, 2025
b2779fc
Merge main to runtime async branch (#77265)
333fred Feb 19, 2025
69855b8
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Mar 11, 2025
c641c52
Merge main to runtime async branch (#77533)
333fred Mar 11, 2025
f372b6e
Add RuntimeAsyncMethodGenerationAttribute (#77543)
333fred Mar 19, 2025
84a299c
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Mar 20, 2025
f35162b
Semantic search info
333fred Mar 20, 2025
fdb50d3
Merge main to runtime async branch (#77700)
333fred Mar 20, 2025
d299b26
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Apr 11, 2025
4b0e79e
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Apr 11, 2025
23aa61f
Merge main to runtime async branch (#78114)
333fred Apr 12, 2025
2acef7e
Implement custom awaitable support (#78071)
333fred Apr 22, 2025
e272201
Move runtime async method validation into initial binding (#78310)
333fred May 2, 2025
1030397
Merge remote-tracking branch 'upstream/main' into merge-main
333fred May 8, 2025
1422076
React to main changes https://github.com/dotnet/roslyn/pull/78246 and…
333fred May 8, 2025
91f097c
Merge main to runtime async branch (#78517)
333fred May 8, 2025
1e6abef
Switch MethodImplAttributes.Async to 0x2000 (#78536)
333fred May 9, 2025
12f31f4
Ensure return local is the correct type for runtime async (#78603)
333fred May 19, 2025
b8e8216
Merge remote-tracking branch 'upstream/main' into merge-main
333fred May 28, 2025
31b2f02
Merge main to runtime async branch (#78740)
333fred May 29, 2025
057349d
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Jun 16, 2025
a98e3fd
Merge main (#78994)
333fred Jun 17, 2025
c2fff44
Exception Handler support (#78773)
333fred Jun 25, 2025
7de7718
Support using a simple overload resolution for finding Await helpers …
333fred Jul 8, 2025
0f7d644
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Jul 16, 2025
d5554f3
Merge main (#79424)
333fred Jul 17, 2025
a9c63d3
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Jul 24, 2025
caeac86
Merge main to runtime async branch (#79582)
333fred Jul 24, 2025
46064a0
Baseline struct lifting tests (#79505)
333fred Jul 25, 2025
1875f1b
Block `await dynamic`
333fred Aug 4, 2025
891f13b
Block hoisted variables from runtime async for now
333fred Aug 5, 2025
8ef2999
Update test baselines for block
333fred Aug 5, 2025
42bc8f1
Block arglist in runtime async
333fred Aug 5, 2025
1d4512e
Add IL baseline
333fred Aug 5, 2025
0625e2c
Handle an additional branch beyond the end of the method case.
333fred Aug 5, 2025
c579eda
Move prototype comments to issues.
333fred Aug 5, 2025
67e33d0
Remove entry point prototypes
333fred Aug 5, 2025
2482740
Add assert and comment
333fred Aug 6, 2025
77bd748
Add back assert
333fred Aug 6, 2025
9a25223
Report obsolete/experimental diagnostics on await helpers.
333fred Aug 6, 2025
c86fcf2
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Aug 7, 2025
9258795
Merge main (#79830)
333fred Aug 7, 2025
52a8a1f
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Aug 7, 2025
49a272a
Merge main (#79834)
333fred Aug 7, 2025
eea9ddc
Merge remote-tracking branch 'upstream/main' into merge-main
333fred Aug 19, 2025
01f170e
Fix ref safety analysis build error.
333fred Aug 19, 2025
ea241ef
Merge main to runtime async branch (#79961)
333fred Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/compilers/CSharp/Runtime Async Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace System.Runtime.CompilerServices;

public enum MethodImplOptions
{
Async = 1024
Async = 0x2000
}
```

Expand Down Expand Up @@ -135,9 +135,11 @@ For any `await expr` with where `expr` has type `E`, the compiler will attempt t
2. There is an identity or implicit reference conversion from `E` to the type of `P`.
4. Otherwise, if `Mi` has a generic arity of 1 with type param `Tm`, all of the following must be true, or `Mi` is removed:
1. The return type is `Tm`
2. There is an identity or implicit reference conversion from `E`'s unsubstituted definition to `P`
3. `E`'s type argument, `Te`, is valid to substitute for `Tm`
6. If only one `Mi` remains, that method is used for the following rewrites. Otherwise, we instead move to [await any other type].
2. The generic parameter of `E` is `Te`
3. `Ti` satisfies any constraints on `Tm`
4. `Mie` is `Mi` with `Te` substituted for `Tm`, and `Pe` is the resulting parameter of `Mie`
5. There is an identity or implicit reference conversion from `E` to the type of `Pe`
5. If only one `Mi` remains, that method is used for the following rewrites. Otherwise, we instead move to [await any other type].

We'll generally rewrite `await expr` into `System.Runtime.CompilerServices.AsyncHelpers.Await(expr)`. A number of different example scenarios for this are covered below. The
main interesting deviations are when `struct` rvalues need to be hoisted across an `await`, and exception handling rewriting.
Expand Down
4 changes: 4 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4708,6 +4708,10 @@ internal SafeContext GetValEscape(BoundExpression expr, SafeContext localScopeDe
// only possible in error cases (if possible at all)
return localScopeDepth;

case BoundKind.ArgList:
// Only possible in error scenarios in runtime async (arglist operators are disallowed in runtime async methods)
return localScopeDepth;

case BoundKind.ConvertedSwitchExpression:
case BoundKind.UnconvertedSwitchExpression:
var switchExpr = (BoundSwitchExpression)expr;
Expand Down
262 changes: 254 additions & 8 deletions src/Compilers/CSharp/Portable/Binder/Binder_Await.cs

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Bin
{
bool hasErrors = analyzedArguments.HasErrors;

if (IsInAsyncMethod() && Compilation.IsRuntimeAsyncEnabledIn(ContainingMemberOrLambda))
{
// Method '{0}' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
diagnostics.Add(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, node, ContainingMemberOrLambda);
}

// We allow names, oddly enough; M(__arglist(x : 123)) is legal. We just ignore them.
TypeSymbol objType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
for (int i = 0; i < analyzedArguments.Arguments.Count; ++i)
Expand Down
6 changes: 3 additions & 3 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1694,20 +1694,20 @@ NamespaceOrTypeOrAliasSymbolWithAnnotations convertToUnboundGenericType()
}
}

internal NamedTypeSymbol GetSpecialType(SpecialType typeId, BindingDiagnosticBag diagnostics, SyntaxNode node)
internal NamedTypeSymbol GetSpecialType(ExtendedSpecialType typeId, BindingDiagnosticBag diagnostics, SyntaxNode node)
{
return GetSpecialType(this.Compilation, typeId, node, diagnostics);
}

internal static NamedTypeSymbol GetSpecialType(CSharpCompilation compilation, SpecialType typeId, SyntaxNode node, BindingDiagnosticBag diagnostics)
internal static NamedTypeSymbol GetSpecialType(CSharpCompilation compilation, ExtendedSpecialType typeId, SyntaxNode node, BindingDiagnosticBag diagnostics)
{
NamedTypeSymbol typeSymbol = compilation.GetSpecialType(typeId);
Debug.Assert((object)typeSymbol != null, "Expect an error type if special type isn't found");
ReportUseSite(typeSymbol, diagnostics, node);
return typeSymbol;
}

internal static NamedTypeSymbol GetSpecialType(CSharpCompilation compilation, SpecialType typeId, Location location, BindingDiagnosticBag diagnostics)
internal static NamedTypeSymbol GetSpecialType(CSharpCompilation compilation, ExtendedSpecialType typeId, Location location, BindingDiagnosticBag diagnostics)
{
NamedTypeSymbol typeSymbol = compilation.GetSpecialType(typeId);
Debug.Assert((object)typeSymbol != null, "Expect an error type if special type isn't found");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno
var placeholder = new BoundAwaitableValuePlaceholder(expr, builder.MoveNextInfo?.Method.ReturnType ?? CreateErrorType());
awaitInfo = BindAwaitInfo(placeholder, expr, diagnostics, ref hasErrors);

if (!hasErrors && awaitInfo.GetResult?.ReturnType.SpecialType != SpecialType.System_Boolean)
if (!hasErrors && (awaitInfo.GetResult ?? awaitInfo.RuntimeAsyncAwaitCall?.Method)?.ReturnType.SpecialType != SpecialType.System_Boolean)
{
diagnostics.Add(ErrorCode.ERR_BadGetAsyncEnumerator, expr.Location, getEnumeratorMethod.ReturnTypeWithAnnotations, getEnumeratorMethod);
hasErrors = true;
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,11 @@ private void GetAwaitableInstancePlaceholders(ArrayBuilder<(BoundValuePlaceholde
{
placeholders.Add((placeholder, SafeContextAndLocation.Create(valEscapeScope)));
}

if (awaitableInfo.RuntimeAsyncAwaitCallPlaceholder is { } runtimePlaceholder)
{
placeholders.Add((runtimePlaceholder, SafeContextAndLocation.Create(valEscapeScope)));
}
}

public override BoundNode? VisitImplicitIndexerAccess(BoundImplicitIndexerAccess node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo

if (awaitableTypeOpt is null)
{
awaitOpt = new BoundAwaitableInfo(syntax, awaitableInstancePlaceholder: null, isDynamic: true, getAwaiter: null, isCompleted: null, getResult: null) { WasCompilerGenerated = true };
awaitOpt = new BoundAwaitableInfo(syntax, awaitableInstancePlaceholder: null, isDynamic: true, getAwaiter: null, isCompleted: null, getResult: null, runtimeAsyncAwaitCall: null, runtimeAsyncAwaitCallPlaceholder: null) { WasCompilerGenerated = true };
}
else
{
Expand Down
41 changes: 41 additions & 0 deletions src/Compilers/CSharp/Portable/BoundTree/BoundAwaitableInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp;

partial class BoundAwaitableInfo
{
private partial void Validate()
{
if (RuntimeAsyncAwaitCall is not null)
{
Debug.Assert(RuntimeAsyncAwaitCall.Method.ContainingType.ExtendedSpecialType == InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers);
Debug.Assert(RuntimeAsyncAwaitCallPlaceholder is not null);

switch (RuntimeAsyncAwaitCall.Method.Name)
{
case "Await":
Debug.Assert(GetAwaiter is null);
Debug.Assert(IsCompleted is null);
Debug.Assert(GetResult is null);
break;

case "AwaitAwaiter":
case "UnsafeAwaitAwaiter":
Debug.Assert(GetAwaiter is not null);
Debug.Assert(IsCompleted is not null);
Debug.Assert(GetResult is not null);
break;

default:
Debug.Fail($"Unexpected RuntimeAsyncAwaitCall: {RuntimeAsyncAwaitCall.Method.Name}");
break;
}
}

Debug.Assert(GetAwaiter is not null || RuntimeAsyncAwaitCall is not null || IsDynamic || HasErrors);
}
}
8 changes: 7 additions & 1 deletion src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -695,13 +695,19 @@
<Field Name="Expression" Type="BoundExpression"/>
</Node>

<Node Name="BoundAwaitableInfo" Base="BoundNode">
<Node Name="BoundAwaitableInfo" Base="BoundNode" HasValidate="true">
<!-- Used to refer to the awaitable expression in GetAwaiter -->
<Field Name="AwaitableInstancePlaceholder" Type="BoundAwaitableValuePlaceholder?" Null="allow" />
<Field Name="IsDynamic" Type="bool"/>
<Field Name="GetAwaiter" Type="BoundExpression?" Null="allow"/>
<Field Name="IsCompleted" Type="PropertySymbol?" Null="allow"/>
<Field Name="GetResult" Type="MethodSymbol?" Null="allow"/>
<!-- Refers to the runtime async helper call we use for awaiting. Either this is an instance of a BoundCall of an AsyncHelpers.Await method, and
GetAwaiter, IsCompleted, and GetResult are null, or this is an instance of a AsyncHelpers.AwaitAwaiter/UnsafeAwaitAwaiter BoundCall, and the other
fields are not null. -->
<Field Name="RuntimeAsyncAwaitCall" Type="BoundCall?" Null="allow"/>
<!-- Never null when RuntimeAsyncAwaitCall is not null -->
<Field Name="RuntimeAsyncAwaitCallPlaceholder" Type="BoundAwaitableValuePlaceholder?" Null="allow"/>
</Node>

<Node Name="BoundAwaitExpression" Base="BoundExpression">
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -8221,6 +8221,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_MemberNameSameAsExtendedType" xml:space="preserve">
<value>'{0}': extension member names cannot be the same as their extended type</value>
</data>
<data name="ERR_UnsupportedFeatureInRuntimeAsync" xml:space="preserve">
<value>Method '{0}' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.</value>
</data>
<data name="ERR_ExtensionBlockCollision" xml:space="preserve">
<value>This extension block collides with another extension block. They result in conflicting content-based type names in metadata, so must be in separate enclosing static classes.</value>
</data>
Expand Down
22 changes: 19 additions & 3 deletions src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,24 @@ private LocalDefinition LazyReturnTemp
? LocalSlotConstraints.None
: LocalSlotConstraints.ByRef;

var returnTypeWithAnnotations = _method.ReturnTypeWithAnnotations;
if (_method.IsAsync && _module.Compilation.IsRuntimeAsyncEnabledIn(_method))
{
// The return type of the method is either Task<T> or ValueTask<T>. The il of the method is
// actually going to appear to return a T, not the wrapper task type. So we need to
// translate the return type to the actual type that will be returned.

var returnType = returnTypeWithAnnotations.Type;
Debug.Assert(((InternalSpecialType)returnType.OriginalDefinition.ExtendedSpecialType) is InternalSpecialType.System_Threading_Tasks_ValueTask_T or InternalSpecialType.System_Threading_Tasks_Task_T);

returnTypeWithAnnotations = ((NamedTypeSymbol)returnType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0];
}

var bodySyntax = _methodBodySyntaxOpt;
if (_ilEmitStyle == ILEmitStyle.Debug && bodySyntax != null)
{
int syntaxOffset = _method.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(bodySyntax), bodySyntax.SyntaxTree);
var localSymbol = new SynthesizedLocal(_method, _method.ReturnTypeWithAnnotations, SynthesizedLocalKind.FunctionReturnValue, bodySyntax);
var localSymbol = new SynthesizedLocal(_method, returnTypeWithAnnotations, SynthesizedLocalKind.FunctionReturnValue, bodySyntax);

result = _builder.LocalSlotManager.DeclareLocal(
type: _module.Translate(localSymbol.Type, bodySyntax, _diagnostics.DiagnosticBag),
Expand All @@ -190,7 +203,7 @@ private LocalDefinition LazyReturnTemp
}
else
{
result = AllocateTemp(_method.ReturnType, _boundBody.Syntax, slotConstraints);
result = AllocateTemp(returnTypeWithAnnotations.Type, _boundBody.Syntax, slotConstraints);
}

_returnTemp = result;
Expand Down Expand Up @@ -308,7 +321,10 @@ private void HandleReturn()
{
_builder.MarkLabel(s_returnLabel);

Debug.Assert(_method.ReturnsVoid == (_returnTemp == null));
Debug.Assert(_method.ReturnsVoid == (_returnTemp == null)
|| (_method.IsAsync
&& _module.Compilation.IsRuntimeAsyncEnabledIn(_method)
&& ((InternalSpecialType)_method.ReturnType.ExtendedSpecialType) is InternalSpecialType.System_Threading_Tasks_Task or InternalSpecialType.System_Threading_Tasks_ValueTask));

if (_emitPdbSequencePoints && !_method.IsIterator && !_method.IsAsync)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp
/// <summary>
/// Structure containing all semantic information about an await expression.
/// </summary>
// https://github.com/dotnet/roslyn/issues/79818: Add runtime async info
public readonly struct AwaitExpressionInfo : IEquatable<AwaitExpressionInfo>
{
public IMethodSymbol? GetAwaiterMethod { get; }
Expand Down
49 changes: 45 additions & 4 deletions src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,42 @@ internal bool IsNullableAnalysisEnabledAlways
};
}

/// <summary>
/// Returns true if this method should be processed with runtime async handling instead
/// of compiler async state machine generation.
/// </summary>
internal bool IsRuntimeAsyncEnabledIn(Symbol? symbol)
{
if (!Assembly.RuntimeSupportsAsyncMethods)
{
return false;
}

if (symbol is not MethodSymbol method)
{
return false;
}

Debug.Assert(ReferenceEquals(method.ContainingAssembly, Assembly));

var methodReturn = method.ReturnType.OriginalDefinition;
if (((InternalSpecialType)methodReturn.ExtendedSpecialType) is not (
InternalSpecialType.System_Threading_Tasks_Task or
InternalSpecialType.System_Threading_Tasks_Task_T or
InternalSpecialType.System_Threading_Tasks_ValueTask or
InternalSpecialType.System_Threading_Tasks_ValueTask_T))
{
return false;
}

return symbol switch
{
SourceMethodSymbol { IsRuntimeAsyncEnabledInMethod: ThreeState.True } => true,
SourceMethodSymbol { IsRuntimeAsyncEnabledInMethod: ThreeState.False } => false,
_ => Feature("runtime-async") == "on"
};
}

/// <summary>
/// The language version that was used to parse the syntax trees of this compilation.
/// </summary>
Expand Down Expand Up @@ -2204,12 +2240,17 @@ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, BindingDiagnostic
var syntax = method.ExtractReturnTypeSyntax();
var dumbInstance = new BoundLiteral(syntax, ConstantValue.Null, namedType);
var binder = GetBinder(syntax);
BoundExpression? result;
var success = binder.GetAwaitableExpressionInfo(dumbInstance, out result, syntax, diagnostics);
var success = binder.GetAwaitableExpressionInfo(dumbInstance, out BoundExpression? result, out BoundCall? runtimeAwaitCall, syntax, diagnostics);

RoslynDebug.Assert(!namedType.IsDynamic());
return success &&
(result!.Type!.IsVoidType() || result.Type!.SpecialType == SpecialType.System_Int32);
if (!success)
{
return false;
}

Debug.Assert(result is { Type: not null } || runtimeAwaitCall is { Type: not null });
var returnType = result?.Type ?? runtimeAwaitCall!.Type;
return returnType.IsVoidType() || returnType.SpecialType == SpecialType.System_Int32;
}

/// <summary>
Expand Down
26 changes: 21 additions & 5 deletions src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -774,8 +774,15 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)

if (!loweredBody.HasErrors)
{
AsyncStateMachine asyncStateMachine;
loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);
AsyncStateMachine asyncStateMachine = null;
if (compilationState.Compilation.IsRuntimeAsyncEnabledIn(method))
{
loweredBody = RuntimeAsyncRewriter.Rewrite(loweredBody, method, compilationState, diagnosticsThisMethod);
}
else
{
loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);
}

Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null);
stateMachine = stateMachine ?? asyncStateMachine;
Expand Down Expand Up @@ -1577,10 +1584,19 @@ internal static BoundStatement LowerBodyOrInitializer(
return bodyWithoutIterators;
}

BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics,
out AsyncStateMachine asyncStateMachine);
BoundStatement bodyWithoutAsync;
AsyncStateMachine asyncStateMachine = null;
if (compilationState.Compilation.IsRuntimeAsyncEnabledIn(method))
{
bodyWithoutAsync = RuntimeAsyncRewriter.Rewrite(bodyWithoutIterators, method, compilationState, diagnostics);
}
else
{
bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics,
out asyncStateMachine);
}

Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null);
Debug.Assert(iteratorStateMachine is null || asyncStateMachine is null);
stateMachineTypeOpt = (StateMachineTypeSymbol)iteratorStateMachine ?? asyncStateMachine;

return bodyWithoutAsync;
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2422,6 +2422,7 @@ internal enum ErrorCode
ERR_InterpolatedStringHandlerArgumentDisallowed = 9325,
ERR_MemberNameSameAsExtendedType = 9326,
ERR_FeatureNotAvailableInVersion14 = 9327,
ERR_UnsupportedFeatureInRuntimeAsync = 9328,
ERR_ExtensionBlockCollision = 9329,

// Note: you will need to do the following after adding errors:
Expand Down
Loading