diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index ce13976db5419..1d738e6b3517c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp @@ -37,7 +38,7 @@ private BoundAwaitExpression BindAwait(BoundExpression expression, SyntaxNode no // The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Thus, // if the return type of GetResult is void, the await-expression is classified as nothing. If it has a // non-void return type T, the await-expression is classified as a value of type T. - TypeSymbol awaitExpressionType = info.GetResult?.ReturnType ?? (hasErrors ? CreateErrorType() : Compilation.DynamicType); + TypeSymbol awaitExpressionType = (info.GetResult ?? info.RuntimeAsyncAwaitMethod)?.ReturnType ?? (hasErrors ? CreateErrorType() : Compilation.DynamicType); return new BoundAwaitExpression(node, expression, info, debugInfo: default, awaitExpressionType, hasErrors); } @@ -58,11 +59,12 @@ internal BoundAwaitableInfo BindAwaitInfo(BoundAwaitableValuePlaceholder placeho out PropertySymbol? isCompleted, out MethodSymbol? getResult, getAwaiterGetResultCall: out _, + out MethodSymbol? runtimeAsyncAwaitMethod, node, diagnostics); hasErrors |= hasGetAwaitableErrors; - return new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, hasErrors: hasGetAwaitableErrors) { WasCompilerGenerated = true }; + return new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitMethod, hasErrors: hasGetAwaitableErrors) { WasCompilerGenerated = true }; } /// @@ -123,7 +125,7 @@ private bool CouldBeAwaited(BoundExpression expression) return false; } - return GetAwaitableExpressionInfo(expression, getAwaiterGetResultCall: out _, + return GetAwaitableExpressionInfo(expression, getAwaiterGetResultCall: out _, runtimeAsyncAwaitMethod: out _, node: syntax, diagnostics: BindingDiagnosticBag.Discarded); } @@ -242,10 +244,11 @@ private bool ReportBadAwaitContext(SyntaxNodeOrToken nodeOrToken, BindingDiagnos internal bool GetAwaitableExpressionInfo( BoundExpression expression, out BoundExpression? getAwaiterGetResultCall, + out MethodSymbol? runtimeAsyncAwaitMethod, SyntaxNode node, BindingDiagnosticBag diagnostics) { - return GetAwaitableExpressionInfo(expression, expression, out _, out _, out _, out _, out getAwaiterGetResultCall, node, diagnostics); + return GetAwaitableExpressionInfo(expression, expression, out _, out _, out _, out _, out getAwaiterGetResultCall, out runtimeAsyncAwaitMethod, node, diagnostics); } private bool GetAwaitableExpressionInfo( @@ -256,6 +259,7 @@ private bool GetAwaitableExpressionInfo( out PropertySymbol? isCompleted, out MethodSymbol? getResult, out BoundExpression? getAwaiterGetResultCall, + out MethodSymbol? runtimeAsyncAwaitMethod, SyntaxNode node, BindingDiagnosticBag diagnostics) { @@ -266,6 +270,7 @@ private bool GetAwaitableExpressionInfo( isCompleted = null; getResult = null; getAwaiterGetResultCall = null; + runtimeAsyncAwaitMethod = null; if (!ValidateAwaitedExpression(expression, node, diagnostics)) { @@ -274,10 +279,21 @@ private bool GetAwaitableExpressionInfo( if (expression.HasDynamicType()) { + // PROTOTYPE: Handle runtime async here isDynamic = true; return true; } + var isRuntimeAsyncEnabled = Compilation.IsRuntimeAsyncEnabledIn(this.ContainingMemberOrLambda); + + // When RuntimeAsync is enabled, we first check for whether there is an AsyncHelpers.Await method that can handle the expression. + // PROTOTYPE: Do the full algorithm specified in https://github.com/dotnet/roslyn/pull/77957 + + if (isRuntimeAsyncEnabled && tryGetRuntimeAwaitHelper(expression, out runtimeAsyncAwaitMethod, diagnostics)) + { + return true; + } + if (!GetGetAwaiterMethod(getAwaiterArgument, node, diagnostics, out getAwaiter)) { return false; @@ -286,7 +302,90 @@ private bool GetAwaitableExpressionInfo( TypeSymbol awaiterType = getAwaiter.Type!; return GetIsCompletedProperty(awaiterType, node, expression.Type!, diagnostics, out isCompleted) && AwaiterImplementsINotifyCompletion(awaiterType, node, diagnostics) - && GetGetResultMethod(getAwaiter, node, expression.Type!, diagnostics, out getResult, out getAwaiterGetResultCall); + && GetGetResultMethod(getAwaiter, node, expression.Type!, diagnostics, out getResult, out getAwaiterGetResultCall) + && (!isRuntimeAsyncEnabled || getRuntimeAwaitAwaiter(awaiterType, out runtimeAsyncAwaitMethod, expression.Syntax, diagnostics)); + + bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runtimeAwaitHelper, BindingDiagnosticBag diagnostics) + { + var exprOriginalType = expression.Type!.OriginalDefinition; + SpecialMember awaitCall; + TypeWithAnnotations resultType = default; + if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task, diagnostics, expression.Syntax))) + { + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask; + } + else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T, diagnostics, expression.Syntax))) + { + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T; + resultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + } + else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask, diagnostics, expression.Syntax))) + { + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask; + } + else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T, diagnostics, expression.Syntax))) + { + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T; + resultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + } + else + { + runtimeAwaitHelper = null; + return false; + } + + runtimeAwaitHelper = (MethodSymbol)GetSpecialTypeMember(awaitCall, diagnostics, expression.Syntax); + + if (runtimeAwaitHelper is null) + { + return false; + } + + Debug.Assert(runtimeAwaitHelper.Arity == (resultType.HasType ? 1 : 0)); + + if (resultType.HasType) + { + runtimeAwaitHelper = runtimeAwaitHelper.Construct([resultType]); + ConstraintsHelper.CheckConstraints( + runtimeAwaitHelper, + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, expression.Syntax.Location, diagnostics)); + } + + return true; + } + + bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwaitAwaiterMethod, SyntaxNode syntax, BindingDiagnosticBag diagnostics) + { + // Use site info is discarded because we don't actually do this conversion, we just need to know which generic + // method to call. + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + var useUnsafeAwait = Compilation.Conversions.ClassifyImplicitConversionFromType( + awaiterType, + Compilation.GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_ICriticalNotifyCompletion), + ref discardedUseSiteInfo).IsImplicit; + + var awaitMethod = (MethodSymbol?)GetSpecialTypeMember( + useUnsafeAwait + ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter + : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter, + diagnostics, + syntax); + + if (awaitMethod is null) + { + runtimeAwaitAwaiterMethod = null; + return false; + } + + Debug.Assert(awaitMethod is { Arity: 1 }); + + runtimeAwaitAwaiterMethod = awaitMethod.Construct(awaiterType); + ConstraintsHelper.CheckConstraints( + runtimeAwaitAwaiterMethod, + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, syntax.Location, diagnostics)); + + return true; + } } /// diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 4dfb348e9845a..5781f9598c1e0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -1654,12 +1654,12 @@ 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"); @@ -1667,7 +1667,7 @@ internal static NamedTypeSymbol GetSpecialType(CSharpCompilation compilation, Sp 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"); diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index 9ccb48982189f..06d32f000e915 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -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, runtimeAsyncAwaitMethod: null) { WasCompilerGenerated = true }; } else { diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundAwaitableInfo.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundAwaitableInfo.cs new file mode 100644 index 0000000000000..f2e0914bf17da --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundAwaitableInfo.cs @@ -0,0 +1,38 @@ +// 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 (RuntimeAsyncAwaitMethod is not null) + { + Debug.Assert(RuntimeAsyncAwaitMethod.ContainingType.ExtendedSpecialType == InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers); + + switch (RuntimeAsyncAwaitMethod.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 RuntimeAsyncAwaitMethod: {RuntimeAsyncAwaitMethod.Name}"); + break; + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 663c321f9aada..a0e40e5b24e85 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -686,13 +686,18 @@ - + + + + diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 4c141a2d75f5a..00a6a79357d90 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -316,7 +316,7 @@ internal bool IsNullableAnalysisEnabledAlways /// Returns true if this method should be processed with runtime async handling instead /// of compiler async state machine generation. /// - internal bool IsRuntimeAsyncEnabledIn(MethodSymbol method) + internal bool IsRuntimeAsyncEnabledIn(Symbol? symbol) { // PROTOTYPE: EE tests fail this assert, handle and test //Debug.Assert(ReferenceEquals(method.ContainingAssembly, Assembly)); @@ -325,7 +325,22 @@ internal bool IsRuntimeAsyncEnabledIn(MethodSymbol method) return false; } - return method switch + if (symbol is not MethodSymbol method) + { + return false; + } + + 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, @@ -2210,12 +2225,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 MethodSymbol? runtimeAwaitMethod, 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 } || runtimeAwaitMethod is { ReturnType: not null }); + var returnType = result?.Type ?? runtimeAwaitMethod!.ReturnType; + return returnType.IsVoidType() || returnType.SpecialType == SpecialType.System_Int32; } /// diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 75640925c4062..1fe44dbcf48ab 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -2138,7 +2138,7 @@ public BoundArrayLength Update(BoundExpression expression, TypeSymbol type) internal sealed partial class BoundAwaitableInfo : BoundNode { - public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder, bool isDynamic, BoundExpression? getAwaiter, PropertySymbol? isCompleted, MethodSymbol? getResult, bool hasErrors = false) + public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder, bool isDynamic, BoundExpression? getAwaiter, PropertySymbol? isCompleted, MethodSymbol? getResult, MethodSymbol? runtimeAsyncAwaitMethod, bool hasErrors = false) : base(BoundKind.AwaitableInfo, syntax, hasErrors || awaitableInstancePlaceholder.HasErrors() || getAwaiter.HasErrors()) { this.AwaitableInstancePlaceholder = awaitableInstancePlaceholder; @@ -2146,22 +2146,28 @@ public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awa this.GetAwaiter = getAwaiter; this.IsCompleted = isCompleted; this.GetResult = getResult; + this.RuntimeAsyncAwaitMethod = runtimeAsyncAwaitMethod; + Validate(); } + [Conditional("DEBUG")] + private partial void Validate(); + public BoundAwaitableValuePlaceholder? AwaitableInstancePlaceholder { get; } public bool IsDynamic { get; } public BoundExpression? GetAwaiter { get; } public PropertySymbol? IsCompleted { get; } public MethodSymbol? GetResult { get; } + public MethodSymbol? RuntimeAsyncAwaitMethod { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitAwaitableInfo(this); - public BoundAwaitableInfo Update(BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder, bool isDynamic, BoundExpression? getAwaiter, PropertySymbol? isCompleted, MethodSymbol? getResult) + public BoundAwaitableInfo Update(BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder, bool isDynamic, BoundExpression? getAwaiter, PropertySymbol? isCompleted, MethodSymbol? getResult, MethodSymbol? runtimeAsyncAwaitMethod) { - if (awaitableInstancePlaceholder != this.AwaitableInstancePlaceholder || isDynamic != this.IsDynamic || getAwaiter != this.GetAwaiter || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(isCompleted, this.IsCompleted) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(getResult, this.GetResult)) + if (awaitableInstancePlaceholder != this.AwaitableInstancePlaceholder || isDynamic != this.IsDynamic || getAwaiter != this.GetAwaiter || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(isCompleted, this.IsCompleted) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(getResult, this.GetResult) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(runtimeAsyncAwaitMethod, this.RuntimeAsyncAwaitMethod)) { - var result = new BoundAwaitableInfo(this.Syntax, awaitableInstancePlaceholder, isDynamic, getAwaiter, isCompleted, getResult, this.HasErrors); + var result = new BoundAwaitableInfo(this.Syntax, awaitableInstancePlaceholder, isDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitMethod, this.HasErrors); result.CopyAttributes(this); return result; } @@ -11175,9 +11181,10 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { PropertySymbol? isCompleted = this.VisitPropertySymbol(node.IsCompleted); MethodSymbol? getResult = this.VisitMethodSymbol(node.GetResult); + MethodSymbol? runtimeAsyncAwaitMethod = this.VisitMethodSymbol(node.RuntimeAsyncAwaitMethod); BoundAwaitableValuePlaceholder? awaitableInstancePlaceholder = (BoundAwaitableValuePlaceholder?)this.Visit(node.AwaitableInstancePlaceholder); BoundExpression? getAwaiter = (BoundExpression?)this.Visit(node.GetAwaiter); - return node.Update(awaitableInstancePlaceholder, node.IsDynamic, getAwaiter, isCompleted, getResult); + return node.Update(awaitableInstancePlaceholder, node.IsDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitMethod); } public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node) { @@ -13133,9 +13140,10 @@ public NullabilityRewriter(ImmutableDictionary field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task); - } = null!; - - private NamedTypeSymbol TaskT - { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); - } = null!; - - private NamedTypeSymbol ValueTask - { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); - } = null!; - - private NamedTypeSymbol ValueTaskT - { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask_T); - } = null!; - [return: NotNullIfNotNull(nameof(node))] public BoundExpression? VisitExpression(BoundExpression? node) { @@ -70,53 +51,25 @@ private NamedTypeSymbol ValueTaskT { var nodeType = node.Expression.Type; Debug.Assert(nodeType is not null); - var originalType = nodeType.OriginalDefinition; - - WellKnownMember awaitCall; - TypeWithAnnotations? maybeNestedType = null; - if (ReferenceEquals(originalType, Task)) - { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask; - } - else if (ReferenceEquals(originalType, TaskT)) - { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T; - maybeNestedType = ((NamedTypeSymbol)nodeType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; - } - else if (ReferenceEquals(originalType, ValueTask)) - { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask; - } - else if (ReferenceEquals(originalType, ValueTaskT)) + var awaitableInfo = node.AwaitableInfo; + var runtimeAsyncAwaitMethod = awaitableInfo.RuntimeAsyncAwaitMethod; + Debug.Assert(runtimeAsyncAwaitMethod is not null); + Debug.Assert(ReferenceEquals( + runtimeAsyncAwaitMethod.ContainingType.OriginalDefinition, + _factory.Compilation.GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers))); + Debug.Assert(runtimeAsyncAwaitMethod.Name is "Await" or "UnsafeAwaitAwaiter" or "AwaitAwaiter"); + + if (runtimeAsyncAwaitMethod.Name == "Await") { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T; - maybeNestedType = ((NamedTypeSymbol)nodeType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + // This is the direct await case, with no need for the full pattern. + // System.Runtime.CompilerServices.RuntimeHelpers.Await(awaitedExpression) + return _factory.Call(receiver: null, runtimeAsyncAwaitMethod, VisitExpression(node.Expression)); } else { return RewriteCustomAwaiterAwait(node); } - - // PROTOTYPE: Make sure that we report an error in initial binding if these are missing - var awaitMethod = (MethodSymbol?)_compilation.GetWellKnownTypeMember(awaitCall); - Debug.Assert(awaitMethod is not null); - - if (maybeNestedType is { } nestedType) - { - Debug.Assert(awaitMethod.TypeParameters.Length == 1); - // PROTOTYPE: Check diagnostic - awaitMethod = awaitMethod.Construct([nestedType]); - } -#if DEBUG - else - { - Debug.Assert(awaitMethod.TypeParameters.Length == 0); - } -#endif - - // System.Runtime.CompilerServices.RuntimeHelpers.Await(awaitedExpression) - return _factory.Call(receiver: null, awaitMethod, VisitExpression(node.Expression)); } private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) @@ -125,7 +78,7 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) // becomes // var _tmp = expr.GetAwaiter(); // if (!_tmp.IsCompleted) - // UnsafeAwaitAwaiterFromRuntimeAsync(_tmp) OR AwaitAwaiterFromRuntimeAsync(_tmp); + // UnsafeAwaitAwaiter(_tmp) OR AwaitAwaiter(_tmp); // _tmp.GetResult() // PROTOTYPE: await dynamic will need runtime checks, see AsyncMethodToStateMachine.GenerateAwaitOnCompletedDynamic @@ -157,23 +110,11 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) Debug.Assert(isCompletedMethod is not null); var isCompletedCall = _factory.Call(tmp, isCompletedMethod); - // UnsafeAwaitAwaiterFromRuntimeAsync(_tmp) OR AwaitAwaiterFromRuntimeAsync(_tmp) - var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; - var useUnsafeAwait = _factory.Compilation.Conversions.ClassifyImplicitConversionFromType( - tmp.Type, - _factory.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion), - ref discardedUseSiteInfo).IsImplicit; - - // PROTOTYPE: Make sure that we report an error in initial binding if these are missing - var awaitMethod = (MethodSymbol?)_compilation.GetWellKnownTypeMember(useUnsafeAwait - ? WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter - : WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter); - - Debug.Assert(awaitMethod is { Arity: 1 }); - + // UnsafeAwaitAwaiter(_tmp) OR AwaitAwaiter(_tmp) + Debug.Assert(awaitableInfo.RuntimeAsyncAwaitMethod is not null); var awaitCall = _factory.Call( receiver: null, - awaitMethod.Construct(tmp.Type), + awaitableInfo.RuntimeAsyncAwaitMethod, tmp); // if (!_tmp.IsCompleted) awaitCall diff --git a/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs index 1e6b2dbb0a649..2a37596460fe3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs @@ -179,7 +179,7 @@ method.OriginalDefinition is ErrorMethodSymbol || { Name: nameof(VisitUnaryOperator) } => !method.IsExtensionMethod, // Expression tree context. At the moment an operator cannot be an extension method { Name: nameof(VisitUserDefinedConditionalLogicalOperator) } => !method.IsExtensionMethod, // Expression tree context. At the moment an operator cannot be an extension method { Name: nameof(VisitCollectionElementInitializer) } => !method.IsExtensionMethod, // Expression tree context. At the moment an extension method cannot be used in expression tree here. - { Name: nameof(VisitAwaitableInfo) } => method is { Name: "GetResult", IsExtensionMethod: false }, // Cannot be an extension method + { Name: nameof(VisitAwaitableInfo) } => method is { Name: "GetResult" or "Await" or "AwaitAwaiter" or "UnsafeAwaitAwaiter", IsExtensionMethod: false }, // Cannot be an extension method { Name: nameof(VisitMethodSymbolWithExtensionRewrite), DeclaringType: { } declaringType } => declaringType == typeof(ExtensionMethodReferenceRewriter), _ => false }); diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs index a870c8678eb7f..8a0d73bcea0d0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs @@ -268,10 +268,11 @@ public override BoundNode VisitAwaitableInfo(BoundAwaitableInfo node) var getAwaiter = (BoundExpression?)this.Visit(node.GetAwaiter); var isCompleted = VisitPropertySymbol(node.IsCompleted); var getResult = VisitMethodSymbol(node.GetResult); + var runtimeAsyncAwaitMethod = VisitMethodSymbol(node.RuntimeAsyncAwaitMethod); _placeholderMap.Remove(awaitablePlaceholder); - return node.Update(rewrittenPlaceholder, node.IsDynamic, getAwaiter, isCompleted, getResult); + return node.Update(rewrittenPlaceholder, node.IsDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitMethod); } public override BoundNode VisitAwaitableValuePlaceholder(BoundAwaitableValuePlaceholder node) diff --git a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs index b1397c8ab12e7..52fc241a7ebc0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs @@ -497,17 +497,9 @@ internal bool RuntimeSupportsByRefLikeGenerics } #nullable enable - // PROTOTYPE: Remove when we have a runtime with support - private bool _overrideRuntimeSupportsAsyncMethods; - internal void SetOverrideRuntimeSupportsAsyncMethods() - { - _overrideRuntimeSupportsAsyncMethods = true; - } - // Keep in sync with VB's AssemblySymbol.RuntimeSupportsAsyncMethods internal bool RuntimeSupportsAsyncMethods - => RuntimeSupportsFeature(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__Async) - || _overrideRuntimeSupportsAsyncMethods; + => GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers) is { TypeKind: TypeKind.Class, IsStatic: true }; #nullable disable protected bool RuntimeSupportsFeature(SpecialMember feature) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index fc86c841ab206..6a532a67902d4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -371,7 +371,8 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol c { WasCompilerGenerated = true }; // The diagnostics that would be produced here will already have been captured and returned. - var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _getAwaiterGetResultCall!, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded); + // PROTOTYPE: handle the runtime case + var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _getAwaiterGetResultCall!, runtimeAsyncAwaitMethod: out _, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded); Debug.Assert( ReturnType.IsVoidType() || @@ -489,7 +490,8 @@ internal override BoundBlock CreateBody(BindingDiagnosticBag diagnostics) Debug.Assert(!initializer.ReturnType.IsDynamic()); var initializeCall = CreateParameterlessCall(syntax, scriptLocal, receiverIsSubjectToCloning: ThreeState.False, initializer); BoundExpression getAwaiterGetResultCall; - if (!binder.GetAwaitableExpressionInfo(initializeCall, out getAwaiterGetResultCall, syntax, diagnostics)) + // PROTOTYPE: handle the runtime case + if (!binder.GetAwaitableExpressionInfo(initializeCall, out getAwaiterGetResultCall, runtimeAsyncAwaitMethod: out _, syntax, diagnostics)) { return new BoundBlock( syntax: syntax, diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 9db5670663bf0..9301c1b6853bb 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -47,6 +46,312 @@ private static CSharpCompilation CreateCompilation(string source, IEnumerable(T obj); + public delegate void Action(T1 arg1, T2 arg2); + public class ArgumentNullException : Exception + { + public ArgumentNullException(string message) : base(message) {} + } + public class Attribute {} + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + public sealed class AsyncMethodBuilderAttribute : Attribute + { + public AsyncMethodBuilderAttribute(Type builderType) {} + public Type BuilderType => null!; + } + public class AttributeUsageAttribute : Attribute + { + public AttributeUsageAttribute(AttributeTargets targets) {} + public bool AllowMultiple { get; set; } + public bool Inherited { get; set; } + } + public enum AttributeTargets + { + All = 0x1, + Class = 0x2, + Struct = 0x4, + Enum = 0x8, + Interface = 0x10, + Delegate = 0x20, + Method = 0x40, + Property = 0x80, + Field = 0x100, + Event = 0x200, + } + public struct Boolean {} + public static class Console + { + public static void Write(object i) {} + public static void Write(int i) {} + public static void WriteLine(string s) {} + public static void WriteLine(int i) {} + } + public class Delegate {} + public class Enum {} + public class Exception + { + public Exception() {} + public Exception(string message) {} + } + public delegate TResult Func(); + public delegate TResult Func(T arg); + public struct Int32 {} + public struct IntPtr {} + public class MulticastDelegate {} + public struct Nullable(T t) where T : struct {} + public class NullReferenceException : Exception + { + public NullReferenceException(string message) : base(message) {} + } + public class Object {} + public class String {} + public class Type {} + public class ValueType {} + public class Void {} + + namespace Threading + { + public class AutoResetEvent : EventWaitHandle + { + public AutoResetEvent(bool initialState) {} + } + public class EventWaitHandle + { + public bool Set() => default; + public bool WaitOne() => default; + public bool WaitOne(int millisecondsTimeout) => default; + } + public static class Interlocked + { + public static int Increment(ref int location) => default; + } + public static class Thread + { + public static void Sleep(int millisecondsTimeout) {} + } + namespace Tasks + { + using System.Runtime.CompilerServices; + public class Task + { + public Task() {} + public Task(Action action) {} + + public static Task CompletedTask => null!; + public TaskAwaiter GetAwaiter() => default; + public static TaskFactory Factory => null!; + public void Wait() {} + public bool Wait(int millisecondsTimeout) => false; + public static YieldAwaitable Yield() => default; + public static Task FromResult(TResult result) => default; + public Task ContinueWith(Action continuationAction) => default; + } + public class Task + { + public Task() {} + public Task(Func function) {} + public static Task FromResult(TResult result) => null; + public TaskAwaiter GetAwaiter() => default; + public void Wait() {} + public bool Wait(int millisecondsTimeout) => false; + public TResult Result => default; + } + [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))] + public struct ValueTask + { + public ValueTaskAwaiter GetAwaiter() => default; + public static ValueTask FromResult(TResult result) => default; + } + [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))] + public struct ValueTask + { + public ValueTask(TResult result) {} + public ValueTaskAwaiter GetAwaiter() => default; + public TResult Result => default; + } + public class TaskFactory + { + public TaskFactory() {} + public static TaskFactory Factory => default; + public Task StartNew(Action action) => default; + public Task StartNew(Func function) => default; + public ValueTask StartNew(Func function) => default; + public ValueTask StartNew(Func> function) => default; + } + public class TaskCompletionSource + { + public TaskCompletionSource() {} + public Task Task => default; + public void SetResult() {} + public void SetCanceled() {} + public void SetException(Exception exception) {} + } + public class TaskCompletionSource + { + public TaskCompletionSource() {} + public Task Task => default; + public void SetResult(TResult result) {} + public void SetCanceled() {} + public void SetException(Exception exception) {} + } + } + } + + namespace Runtime.CompilerServices + { + public class AsyncMethodBuilderAttribute : Attribute + { + public AsyncMethodBuilderAttribute(Type builderType) {} + } + public struct AsyncTaskMethodBuilder + { + public static AsyncTaskMethodBuilder Create() => default; + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {} + public void SetStateMachine(IAsyncStateMachine stateMachine) {} + public void SetException(Exception exception) {} + public void SetResult() {} + public Threading.Tasks.Task Task => default; + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine {} + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine {} + } + public struct AsyncTaskMethodBuilder + { + public static AsyncTaskMethodBuilder Create() => default; + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {} + public void SetStateMachine(IAsyncStateMachine stateMachine) {} + public void SetException(Exception exception) {} + public void SetResult(T result) {} + public Threading.Tasks.Task Task => default; + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine {} + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine {} + } + public struct AsyncValueTaskMethodBuilder + { + public static AsyncValueTaskMethodBuilder Create() => default; + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {} + public void SetStateMachine(IAsyncStateMachine stateMachine) {} + public void SetException(Exception exception) {} + public void SetResult() {} + public Threading.Tasks.ValueTask Task => default; + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine {} + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine {} + } + public struct AsyncValueTaskMethodBuilder + { + public static AsyncValueTaskMethodBuilder Create() => default; + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {} + public void SetStateMachine(IAsyncStateMachine stateMachine) {} + public void SetException(Exception exception) {} + public void SetResult(T result) {} + public Threading.Tasks.ValueTask Task => default; + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine {} + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine {} + } + public struct AsyncVoidMethodBuilder + { + public static AsyncVoidMethodBuilder Create() => default; + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {} + public void SetStateMachine(IAsyncStateMachine stateMachine) {} + public void SetException(Exception exception) {} + public void SetResult() {} + public Threading.Tasks.Task Task => default; + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine {} + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine {} + } + public class ExtensionAttribute : Attribute {} + public interface IAsyncStateMachine + { + void MoveNext(); + void SetStateMachine(IAsyncStateMachine stateMachine); + } + public interface INotifyCompletion + { + void OnCompleted(Action continuation); + } + public interface ICriticalNotifyCompletion : INotifyCompletion + { + void UnsafeOnCompleted(Action continuation); + } + public static class RuntimeFeature + { + public const string NumericIntPtr = nameof(NumericIntPtr); + } + public struct TaskAwaiter : ICriticalNotifyCompletion + { + public void OnCompleted(Action continuation) {} + public void UnsafeOnCompleted(Action continuation) {} + public bool IsCompleted => false; + public void GetResult() {} + } + public struct TaskAwaiter : ICriticalNotifyCompletion + { + public void OnCompleted(Action continuation) {} + public void UnsafeOnCompleted(Action continuation) {} + public bool IsCompleted => false; + public TResult GetResult() => default; + } + public struct ValueTaskAwaiter : ICriticalNotifyCompletion + { + public void OnCompleted(Action continuation) {} + public void UnsafeOnCompleted(Action continuation) {} + public bool IsCompleted => false; + public void GetResult() {} + } + public struct ValueTaskAwaiter : ICriticalNotifyCompletion + { + public void OnCompleted(Action continuation) {} + public void UnsafeOnCompleted(Action continuation) {} + public bool IsCompleted => false; + public TResult GetResult() => default; + } + public struct YieldAwaitable + { + public YieldAwaiter GetAwaiter() => default; + public struct YieldAwaiter : ICriticalNotifyCompletion + { + public void UnsafeOnCompleted(Action continuation) {} + public void OnCompleted(Action continuation) {} + public bool IsCompleted => false; + public void GetResult() {} + } + } + } + } + """; + + private static CSharpCompilation CreateRuntimeAsyncCompilation(CSharpTestSource source, IEnumerable references = null, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null, string runtimeAsyncAwaitHelpers = RuntimeAsyncAwaitHelpers) + { + // PROTOTYPE: Remove this helper and just use .NET 10 when we can + var corlib = CreateEmptyCompilation([RuntimeAsyncCoreLib, runtimeAsyncAwaitHelpers]); + + var compilation = CreateEmptyCompilation(source, references: [.. references ?? [], corlib.EmitToImageReference()], options: options, parseOptions: parseOptions ?? WithRuntimeAsync(TestOptions.RegularPreview)); + return compilation; + } + private CompilationVerifier CompileAndVerify(string source, string expectedOutput, IEnumerable references = null, CSharpCompilationOptions options = null, Verification verify = default) { var compilation = CreateCompilation(source, references: references, options: options); @@ -111,7 +416,6 @@ public void VoidReturningAsync() { var source = @" using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -146,6 +450,129 @@ public static void Main() 1 "; CompileAndVerify(source, expectedOutput: expected); + + var comp = CreateRuntimeAsyncCompilation(source); + var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); + verifier.VerifyIL("Test.F(System.Threading.AutoResetEvent)", """ + { + // Code size 43 (0x2b) + .maxstack 2 + .locals init (Test.d__1 V_0) + IL_0000: ldloca.s V_0 + IL_0002: call "System.Runtime.CompilerServices.AsyncVoidMethodBuilder System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create()" + IL_0007: stfld "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.d__1.<>t__builder" + IL_000c: ldloca.s V_0 + IL_000e: ldarg.0 + IL_000f: stfld "System.Threading.AutoResetEvent Test.d__1.handle" + IL_0014: ldloca.s V_0 + IL_0016: ldc.i4.m1 + IL_0017: stfld "int Test.d__1.<>1__state" + IL_001c: ldloca.s V_0 + IL_001e: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.d__1.<>t__builder" + IL_0023: ldloca.s V_0 + IL_0025: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Startd__1>(ref Test.d__1)" + IL_002a: ret + } + """); + + verifier.VerifyIL("Test.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """ + { + // Code size 200 (0xc8) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int Test.d__1.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: pop + IL_0009: nop + .try + { + IL_000a: ldloc.0 + IL_000b: brfalse.s IL_0065 + IL_000d: call "System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get" + IL_0012: ldsfld "System.Action Test.<>c.<>9__1_0" + IL_0017: dup + IL_0018: brtrue.s IL_0031 + IL_001a: pop + IL_001b: ldsfld "Test.<>c Test.<>c.<>9" + IL_0020: ldftn "void Test.<>c.b__1_0()" + IL_0026: newobj "System.Action..ctor(object, nint)" + IL_002b: dup + IL_002c: stsfld "System.Action Test.<>c.<>9__1_0" + IL_0031: callvirt "System.Threading.Tasks.Task System.Threading.Tasks.TaskFactory.StartNew(System.Action)" + IL_0036: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_003b: stloc.1 + IL_003c: ldloca.s V_1 + IL_003e: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_0043: brtrue.s IL_0081 + IL_0045: ldarg.0 + IL_0046: ldc.i4.0 + IL_0047: dup + IL_0048: stloc.0 + IL_0049: stfld "int Test.d__1.<>1__state" + IL_004e: ldarg.0 + IL_004f: ldloc.1 + IL_0050: stfld "System.Runtime.CompilerServices.TaskAwaiter Test.d__1.<>u__1" + IL_0055: ldarg.0 + IL_0056: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.d__1.<>t__builder" + IL_005b: ldloca.s V_1 + IL_005d: ldarg.0 + IL_005e: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Test.d__1)" + IL_0063: leave.s IL_00c7 + IL_0065: ldarg.0 + IL_0066: ldfld "System.Runtime.CompilerServices.TaskAwaiter Test.d__1.<>u__1" + IL_006b: stloc.1 + IL_006c: ldarg.0 + IL_006d: ldflda "System.Runtime.CompilerServices.TaskAwaiter Test.d__1.<>u__1" + IL_0072: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0078: ldarg.0 + IL_0079: ldc.i4.m1 + IL_007a: dup + IL_007b: stloc.0 + IL_007c: stfld "int Test.d__1.<>1__state" + IL_0081: ldloca.s V_1 + IL_0083: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0088: leave.s IL_009b + } + finally + { + IL_008a: ldloc.0 + IL_008b: ldc.i4.0 + IL_008c: bge.s IL_009a + IL_008e: ldarg.0 + IL_008f: ldfld "System.Threading.AutoResetEvent Test.d__1.handle" + IL_0094: callvirt "bool System.Threading.EventWaitHandle.Set()" + IL_0099: pop + IL_009a: endfinally + } + IL_009b: leave.s IL_00b4 + } + catch System.Exception + { + IL_009d: stloc.2 + IL_009e: ldarg.0 + IL_009f: ldc.i4.s -2 + IL_00a1: stfld "int Test.d__1.<>1__state" + IL_00a6: ldarg.0 + IL_00a7: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.d__1.<>t__builder" + IL_00ac: ldloc.2 + IL_00ad: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)" + IL_00b2: leave.s IL_00c7 + } + IL_00b4: ldarg.0 + IL_00b5: ldc.i4.s -2 + IL_00b7: stfld "int Test.d__1.<>1__state" + IL_00bc: ldarg.0 + IL_00bd: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.d__1.<>t__builder" + IL_00c2: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()" + IL_00c7: ret + } + """); } [Fact] @@ -179,8 +606,7 @@ public static void Main() "; CompileAndVerify(source, expectedOutput: expected); - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { @@ -203,7 +629,7 @@ .maxstack 3 IL_001e: dup IL_001f: stsfld "System.Action Test.<>c.<>9__1_0" IL_0024: callvirt "System.Threading.Tasks.Task System.Threading.Tasks.TaskFactory.StartNew(System.Action)" - IL_0029: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0029: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_002e: ret } """); @@ -246,8 +672,7 @@ public static async Task Main() }"; var expected = "42"; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { @@ -268,7 +693,7 @@ public static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.ValueTask Test.g__Impl|1_0()" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000a: ret } """); @@ -308,12 +733,11 @@ public static void Main() "; CompileAndVerify(source, expectedOutput: expected); - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { - ILVerifyMessage = "[F]: Unexpected type on the stack. { Offset = 0x2e, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' }", + ILVerifyMessage = "[F]: Unexpected type on the stack. { Offset = 0x2e, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' }", }, symbolValidator: verify); verifier.VerifyDiagnostics(); @@ -332,7 +756,7 @@ .maxstack 3 IL_001e: dup IL_001f: stsfld "System.Func Test.<>c.<>9__0_0" IL_0024: callvirt "System.Threading.Tasks.Task System.Threading.Tasks.TaskFactory.StartNew(System.Func)" - IL_0029: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0029: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_002e: ret } """); @@ -369,13 +793,12 @@ public static async Task Main() } }"; var expected = @"O brave new world..."; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = $$""" - [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0xf")}} """, }, symbolValidator: verify); @@ -386,7 +809,7 @@ public static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.ValueTask Test.g__Impl|0_0()" - IL_0005: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0005: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000a: ret } """); @@ -427,8 +850,7 @@ public static async Task Main() } } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -437,7 +859,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0x29, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0x29, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0xf")}} """, (true, false) => $$""" @@ -445,7 +867,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0xf")}} """, }; @@ -464,7 +886,7 @@ public static async Task Main() .maxstack 1 IL_0000: ldnull IL_0001: newobj "System.Threading.Tasks.Task..ctor(System.Action)" - IL_0006: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0006: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000b: ret } """, @@ -482,7 +904,7 @@ .maxstack 2 IL_0019: dup IL_001a: stsfld "System.Func Test.<>c.<>9__0_0" IL_001f: newobj "System.Threading.Tasks.Task..ctor(System.Func)" - IL_0024: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0024: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_0029: ret } """, @@ -494,7 +916,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 - IL_0009: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0009: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000e: ret } """, @@ -504,7 +926,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) .maxstack 1 IL_0000: ldstr "42" IL_0005: newobj "System.Threading.Tasks.ValueTask..ctor(string)" - IL_000a: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_000a: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000f: ret } """, @@ -567,8 +989,7 @@ public static async Task Main() } } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -577,7 +998,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x16")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xb, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0xb, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0x17")}} """, (true, false) => $$""" @@ -585,7 +1006,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x16")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0x13, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0x13, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0x18")}} """, }; @@ -604,7 +1025,7 @@ public static async Task Main() .maxstack 1 IL_0000: ldnull IL_0001: call "void Test.NoOp()" - IL_0006: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0006: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000b: ret } """, @@ -614,7 +1035,7 @@ .maxstack 1 .maxstack 1 IL_0000: ldnull IL_0001: call "void Test.NoOp()" - IL_0006: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0006: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000b: ret } """, @@ -627,7 +1048,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 IL_0009: call "void Test.NoOp()" - IL_000e: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_000e: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_0013: ret } """, @@ -640,7 +1061,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 IL_0009: call "void Test.NoOp()" - IL_000e: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_000e: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_0013: ret } """, @@ -692,8 +1113,7 @@ public static async Task Main() } } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -702,7 +1122,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x16")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0x6, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0x6, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0x17")}} """, (true, false) => $$""" @@ -710,7 +1130,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x16")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xe, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0xe, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0x18")}} """, }; @@ -728,7 +1148,7 @@ public static async Task Main() // Code size 7 (0x7) .maxstack 1 IL_0000: ldnull - IL_0001: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0001: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_0006: ret } """, @@ -737,7 +1157,7 @@ .maxstack 1 // Code size 7 (0x7) .maxstack 1 IL_0000: ldnull - IL_0001: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0001: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_0006: ret } """, @@ -749,7 +1169,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 - IL_0009: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0009: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000e: ret } """, @@ -761,7 +1181,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 - IL_0009: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0009: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000e: ret } """, @@ -806,8 +1226,7 @@ public static async Task Main() } } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -816,7 +1235,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0x1e, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0x1e, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0xf")}} """, (true, false) => $$""" @@ -824,7 +1243,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0x1e, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0x1e, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0xf")}} """, }; @@ -846,7 +1265,7 @@ .maxstack 1 IL_0003: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" IL_0008: br.s IL_000f IL_000a: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_000f: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_000f: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_0014: ret } """, @@ -861,7 +1280,7 @@ .maxstack 1 IL_000d: br.s IL_0019 IL_000f: ldstr "42" IL_0014: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(string)" - IL_0019: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0019: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_001e: ret } """, @@ -879,7 +1298,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_000e: ldloca.s V_0 IL_0010: initobj "System.Threading.Tasks.ValueTask" IL_0016: ldloc.0 - IL_0017: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0017: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_001c: ret } """, @@ -894,7 +1313,7 @@ .maxstack 1 IL_000d: br.s IL_0019 IL_000f: ldstr "42" IL_0014: newobj "System.Threading.Tasks.ValueTask..ctor(string)" - IL_0019: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0019: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_001e: ret } """, @@ -938,8 +1357,7 @@ public static async Task Main() } } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -948,7 +1366,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0xf")}} """, (true, false) => $$""" @@ -956,7 +1374,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0xf, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0xf")}} """, }; @@ -974,7 +1392,7 @@ public static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """, @@ -984,7 +1402,7 @@ .maxstack 1 .maxstack 1 IL_0000: ldstr "42" IL_0005: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(string)" - IL_000a: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_000a: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000f: ret } """, @@ -996,7 +1414,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "System.Threading.Tasks.ValueTask" IL_0008: ldloc.0 - IL_0009: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0009: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000e: ret } """, @@ -1006,7 +1424,7 @@ .locals init (System.Threading.Tasks.ValueTask V_0) .maxstack 1 IL_0000: ldstr "42" IL_0005: newobj "System.Threading.Tasks.ValueTask..ctor(string)" - IL_000a: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_000a: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000f: ret } """, @@ -1052,8 +1470,7 @@ public static async Task Main() public static {{retType}} Prop => {{baseExpr}}; } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var ilVerifyMessage = (useValueTask, useGeneric) switch { @@ -1062,7 +1479,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (false, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = ref 'System.Threading.Tasks.Task`1' } {{ReturnValueMissing("Main", "0xf")}} """, (true, false) => $$""" @@ -1070,7 +1487,7 @@ public static async Task Main() {{ReturnValueMissing("Main", "0x11")}} """, (true, true) => $$""" - [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1' } + [F]: Unexpected type on the stack. { Offset = 0xa, Found = ref 'string', Expected = value 'System.Threading.Tasks.ValueTask`1' } {{ReturnValueMissing("Main", "0xf")}} """, }; @@ -1088,7 +1505,7 @@ public static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task Test.Prop.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """, @@ -1097,7 +1514,7 @@ .maxstack 1 // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task Test.Prop.get" - IL_0005: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """, @@ -1106,7 +1523,7 @@ .maxstack 1 // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.ValueTask Test.Prop.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000a: ret } """, @@ -1115,7 +1532,7 @@ .maxstack 1 // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.ValueTask Test.Prop.get" - IL_0005: call "string System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.ValueTask)" + IL_0005: call "string System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)" IL_000a: ret } """, @@ -1149,7 +1566,7 @@ public MyTaskAwaiter GetAwaiter() return new MyTaskAwaiter(); } - public async void Run(U u) where U : MyTask, new() + public async System.Threading.Tasks.Task Run(U u) where U : MyTask, new() { try { @@ -1195,7 +1612,9 @@ class Driver public static AutoResetEvent CompletedSignal = new AutoResetEvent(false); static void Main() { + #pragma warning disable CS4014 // Task is unawaited new MyTask().Run>(new MyTask()); + #pragma warning restore CS4014 // Task is unawaited CompletedSignal.WaitOne(); @@ -1209,10 +1628,12 @@ static void Main() CompileAndVerify(source, "0"); - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); - var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.FailsPEVerify); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with + { + ILVerifyMessage = ReturnValueMissing("Run", "0x4e") + }); verifier.VerifyDiagnostics(); verifier.VerifyIL("MyTask.Run", $$""" @@ -1237,7 +1658,7 @@ .locals init (int V_0, //tests IL_0013: callvirt "bool MyTaskAwaiter.IsCompleted.get" IL_0018: brtrue.s IL_0020 IL_001a: ldloc.1 - IL_001b: call "void System.Runtime.CompilerServices.RuntimeHelpers.{{(useCritical ? "Unsafe" : "")}}AwaitAwaiterFromRuntimeAsync>(MyTaskAwaiter)" + IL_001b: call "void System.Runtime.CompilerServices.AsyncHelpers.{{(useCritical ? "Unsafe" : "")}}AwaitAwaiter>(MyTaskAwaiter)" IL_0020: ldloc.1 IL_0021: callvirt "int MyTaskAwaiter.GetResult()" IL_0026: brtrue.s IL_0034 @@ -2989,7 +3410,7 @@ public void MyTask_08() //Implementation of you own async pattern public class MyTask { - public async void Run() + public async System.Threading.Tasks.Task Run() { int tests = 0; @@ -3050,10 +3471,12 @@ static void Main() }"; CompileAndVerify(source, "0"); - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); - var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.FailsPEVerify); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with + { + ILVerifyMessage = ReturnValueMissing("Run", "0x4f") + }); verifier.VerifyIL("MyTask.Run", """ { // Code size 80 (0x50) @@ -3075,7 +3498,7 @@ .locals init (int V_0, //tests IL_0012: callvirt "bool MyTaskAwaiter.IsCompleted.get" IL_0017: brtrue.s IL_001f IL_0019: ldloc.1 - IL_001a: call "void System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync(MyTaskAwaiter)" + IL_001a: call "void System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter(MyTaskAwaiter)" IL_001f: ldloc.1 IL_0020: callvirt "int MyTaskAwaiter.GetResult()" IL_0025: ldc.i4.s 123 @@ -3118,7 +3541,7 @@ public MyTaskAwaiter GetAwaiter() return new MyTaskAwaiter(); } - public async void Run() + public async System.Threading.Tasks.Task Run() { int tests = 0; @@ -3177,10 +3600,12 @@ static void Main() }"; CompileAndVerify(source, "0"); - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); - var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.FailsPEVerify); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0", isRuntimeAsync: true), verify: Verification.Fails with + { + ILVerifyMessage = ReturnValueMissing("Run", "0x4f") + }); verifier.VerifyIL("MyTask.Run", """ { // Code size 80 (0x50) @@ -3202,7 +3627,7 @@ .locals init (int V_0, //tests IL_0012: callvirt "bool MyTaskBaseAwaiter.IsCompleted.get" IL_0017: brtrue.s IL_001f IL_0019: ldloc.1 - IL_001a: call "void System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync(MyTaskAwaiter)" + IL_001a: call "void System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter(MyTaskAwaiter)" IL_001f: ldloc.1 IL_0020: callvirt "int MyTaskBaseAwaiter.GetResult()" IL_0025: ldc.i4.s 123 @@ -6892,8 +7317,7 @@ static async Task Main() var expected = "StructAwaitable"; CompileAndVerify(comp, expectedOutput: expected); - comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("Main", "0x2a") @@ -6915,7 +7339,7 @@ .locals init (System.Runtime.CompilerServices.TaskAwaiter V_0, IL_0016: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" IL_001b: brtrue.s IL_0023 IL_001d: ldloc.0 - IL_001e: call "void System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync(System.Runtime.CompilerServices.TaskAwaiter)" + IL_001e: call "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter(System.Runtime.CompilerServices.TaskAwaiter)" IL_0023: ldloca.s V_0 IL_0025: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" IL_002a: ret @@ -6956,8 +7380,7 @@ static async Task Main() var expected = "StructAwaitable"; CompileAndVerify(comp, expectedOutput: expected); - comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput(expected, isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("Main", "0x2f") @@ -6980,7 +7403,7 @@ .locals init (StructAwaitable V_0, IL_001b: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" IL_0020: brtrue.s IL_0028 IL_0022: ldloc.1 - IL_0023: call "void System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync(System.Runtime.CompilerServices.TaskAwaiter)" + IL_0023: call "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter(System.Runtime.CompilerServices.TaskAwaiter)" IL_0028: ldloca.s V_1 IL_002a: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" IL_002f: ret @@ -7523,8 +7946,7 @@ public void RuntimeAsync_CompilerFeatureFlag_EnabledWithRuntimeAsync() await Task.CompletedTask; """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("
$", "0xa") }); @@ -7533,14 +7955,15 @@ public void RuntimeAsync_CompilerFeatureFlag_EnabledWithRuntimeAsync() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """); } - [Fact] - public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync() + [Theory] + [CombinatorialData] + public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync(bool withNonCoreLibSources) { var source = """ using System.Threading.Tasks; @@ -7548,8 +7971,7 @@ public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync() await Task.CompletedTask; """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - + var comp = CreateCompilation([source, withNonCoreLibSources ? RuntimeAsyncAwaitHelpers : ""], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("", """ @@ -7591,8 +8013,7 @@ public void RuntimeAsync_CompilerFeatureFlag_DisabledWithRuntimeAsync(bool expli parseOptions = parseOptions.WithFeature("runtime-async", "off"); } - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], targetFramework: TargetFramework.Net90, parseOptions: parseOptions); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source, parseOptions: parseOptions); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); @@ -7642,8 +8063,7 @@ static async Task Main() parseOptions = parseOptions.WithFeature("runtime-async", "off"); } - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: parseOptions); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition], parseOptions: parseOptions); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("Main", "0xa") }); @@ -7652,7 +8072,7 @@ static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """); @@ -7683,8 +8103,7 @@ static async Task Main() parseOptions = parseOptions.WithFeature("runtime-async", "off"); } - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: parseOptions); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition], parseOptions: parseOptions); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("Main", "0xa") }); @@ -7693,7 +8112,7 @@ static async Task Main() // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """); @@ -7746,8 +8165,7 @@ static async Task Main() parseOptions = parseOptions.WithFeature("runtime-async", "off"); } - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: parseOptions); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition], parseOptions: parseOptions); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("Main", "0x26") }); @@ -7756,7 +8174,7 @@ static async Task Main() // Code size 39 (0x27) .maxstack 2 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ldsfld "System.Func Program.<>c.<>9__0_0" IL_000f: brtrue.s IL_0026 IL_0011: ldsfld "Program.<>c Program.<>c.<>9" @@ -7806,8 +8224,7 @@ static async Task Main() } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition]); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); @@ -7852,8 +8269,7 @@ static async Task Main() } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition]); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("
g__LocalFunc|0_0", "0xa") }); @@ -7884,7 +8300,7 @@ .locals init (Program.
d__0 V_0) // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """); @@ -7908,8 +8324,7 @@ static async Task Main() } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers, RuntimeAsyncMethodGenerationAttributeDefinition], targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation([source, RuntimeAsyncMethodGenerationAttributeDefinition]); var verifier = CompileAndVerify(comp, verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("
b__0_0", "0xa") }); @@ -7940,7 +8355,7 @@ .locals init (Program.
d__0 V_0) // Code size 11 (0xb) .maxstack 1 IL_0000: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get" - IL_0005: call "void System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0005: call "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_000a: ret } """); @@ -7978,11 +8393,10 @@ public bool IsCompleted } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("42", isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("
$", "0x1f") }); - var expectedAwait = notifyType == "INotifyCompletion" ? "AwaitAwaiterFromRuntimeAsync" : "UnsafeAwaitAwaiterFromRuntimeAsync"; + var expectedAwait = notifyType == "INotifyCompletion" ? "AwaitAwaiter" : "UnsafeAwaitAwaiter"; verifier.VerifyIL("", $$""" { // Code size 32 (0x20) @@ -7995,7 +8409,7 @@ .locals init (C.Awaiter V_0) IL_000c: callvirt "bool C.Awaiter.IsCompleted.get" IL_0011: brtrue.s IL_0019 IL_0013: ldloc.0 - IL_0014: call "void System.Runtime.CompilerServices.RuntimeHelpers.{{expectedAwait}}(C.Awaiter)" + IL_0014: call "void System.Runtime.CompilerServices.AsyncHelpers.{{expectedAwait}}(C.Awaiter)" IL_0019: ldloc.0 IL_001a: callvirt "void C.Awaiter.GetResult()" IL_001f: ret @@ -8036,11 +8450,10 @@ public bool IsCompleted } """; - var comp = CreateCompilation([source, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(source); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("42", isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = ReturnValueMissing("
$", "0x24") }); - var expectedAwait = notifyType.Contains("Critical") ? "UnsafeAwaitAwaiterFromRuntimeAsync" : "AwaitAwaiterFromRuntimeAsync"; + var expectedAwait = notifyType.Contains("Critical") ? "UnsafeAwaitAwaiter" : "AwaitAwaiter"; verifier.VerifyIL("", $$""" { // Code size 37 (0x25) @@ -8053,7 +8466,7 @@ .locals init (C.Awaiter V_0) IL_000c: callvirt "bool C.Awaiter.IsCompleted.get" IL_0011: brtrue.s IL_0019 IL_0013: ldloc.0 - IL_0014: call "void System.Runtime.CompilerServices.RuntimeHelpers.{{expectedAwait}}(C.Awaiter)" + IL_0014: call "void System.Runtime.CompilerServices.AsyncHelpers.{{expectedAwait}}(C.Awaiter)" IL_0019: ldloc.0 IL_001a: callvirt "int C.Awaiter.GetResult()" IL_001f: call "void System.Console.WriteLine(int)" @@ -8096,14 +8509,13 @@ static async Task Fib(int i) } """; - var comp = CreateCompilation([code, RuntimeAsyncAwaitHelpers], parseOptions: WithRuntimeAsync(TestOptions.RegularPreview), targetFramework: TargetFramework.NetCoreApp); - comp.Assembly.SetOverrideRuntimeSupportsAsyncMethods(); + var comp = CreateRuntimeAsyncCompilation(code); var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("55", isRuntimeAsync: true), verify: Verification.Fails with { ILVerifyMessage = $$""" {{ReturnValueMissing("Main", "0x11")}} - [Fib]: Unexpected type on the stack. { Offset = 0x30, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } - [Fib]: Unexpected type on the stack. { Offset = 0x4e, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1' } + [Fib]: Unexpected type on the stack. { Offset = 0x30, Found = Int32, Expected = ref 'System.Threading.Tasks.Task`1' } + [Fib]: Unexpected type on the stack. { Offset = 0x4e, Found = Int32, Expected = ref 'System.Threading.Tasks.Task`1' } """ }); verifier.VerifyIL("C.Fib(int)", """ @@ -8127,7 +8539,7 @@ .locals init (int V_0, //i2 IL_001b: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" IL_0020: brtrue.s IL_0028 IL_0022: ldloc.1 - IL_0023: call "void System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync(System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter)" + IL_0023: call "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter(System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter)" IL_0028: ldloca.s V_1 IL_002a: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" IL_002f: ldc.i4.1 @@ -8136,12 +8548,12 @@ .locals init (int V_0, //i2 IL_0032: ldc.i4.1 IL_0033: sub IL_0034: call "System.Threading.Tasks.Task C.Fib(int)" - IL_0039: call "int System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0039: call "int System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_003e: ldarg.0 IL_003f: ldc.i4.2 IL_0040: sub IL_0041: call "System.Threading.Tasks.Task C.Fib(int)" - IL_0046: call "int System.Runtime.CompilerServices.RuntimeHelpers.Await(System.Threading.Tasks.Task)" + IL_0046: call "int System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)" IL_004b: stloc.0 IL_004c: ldloc.0 IL_004d: add @@ -8149,5 +8561,291 @@ .locals init (int V_0, //i2 } """); } + + [Fact] + public void MissingAwaitTask() + { + var code = """ + await System.Threading.Tasks.Task.CompletedTask; + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask); + comp.VerifyDiagnostics( + // (1,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.Await' + // await System.Threading.Tasks.Task.CompletedTask; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Threading.Tasks.Task.CompletedTask").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "Await").WithLocation(1, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void MissingAwaitTaskT() + { + var code = """ + await System.Threading.Tasks.Task.FromResult(0); + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T); + comp.VerifyDiagnostics( + // (1,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.Await' + // await System.Threading.Tasks.Task.FromResult(0); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Threading.Tasks.Task.FromResult(0)").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "Await").WithLocation(1, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void MissingAwaitValueTask() + { + var code = """ + await default(System.Threading.Tasks.ValueTask); + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask); + comp.VerifyDiagnostics( + // (1,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.Await' + // await default(System.Threading.Tasks.ValueTask); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "default(System.Threading.Tasks.ValueTask)").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "Await").WithLocation(1, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void MissingAwaitValueTaskT() + { + var code = """ + await default(System.Threading.Tasks.ValueTask); + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T); + comp.VerifyDiagnostics( + // (1,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.Await' + // await default(System.Threading.Tasks.ValueTask); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "default(System.Threading.Tasks.ValueTask)").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "Await").WithLocation(1, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void MissingUnsafeAwaitAwaiter() + { + var code = """ + await System.Threading.Tasks.Task.Yield(); + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter); + comp.VerifyDiagnostics( + // (1,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter' + // await System.Threading.Tasks.Task.Yield(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Threading.Tasks.Task.Yield()").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "UnsafeAwaitAwaiter").WithLocation(1, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void MissingAwaitAwaiter() + { + var code = """ + using System.Runtime.CompilerServices; + + await new C(); + + class C + { + public CAwaiter GetAwaiter() => new CAwaiter(); + } + + class CAwaiter : INotifyCompletion + { + public void OnCompleted(System.Action continuation) {} + public bool IsCompleted => true; + public void GetResult() {} + } + """; + + var comp = CreateRuntimeAsyncCompilation(code); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter); + comp.VerifyDiagnostics( + // (3,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter' + // await new C(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "new C()").WithArguments("System.Runtime.CompilerServices.AsyncHelpers", "AwaitAwaiter").WithLocation(3, 7) + ); + + // Runtime async not turned on, so we shouldn't care about the missing member + comp = CreateRuntimeAsyncCompilation(code, parseOptions: TestOptions.RegularPreview); + comp.MakeMemberMissing(SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); + } + + [Fact] + public void AwaitAwaiterConstraintsViolation() + { + var runtimeAsyncAwaitHelpers = """ + namespace System.Runtime.CompilerServices + { + public static class AsyncHelpers + { + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : struct, INotifyCompletion + {} + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion + {} + + public static void Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static void Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + } + } + """; + + var code = """ + using System.Runtime.CompilerServices; + + await new C(); + + class C + { + public CAwaiter GetAwaiter() => new CAwaiter(); + } + + class CAwaiter : INotifyCompletion + { + public void OnCompleted(System.Action continuation) {} + public bool IsCompleted => true; + public void GetResult() {} + } + """; + + var comp = CreateRuntimeAsyncCompilation(code, runtimeAsyncAwaitHelpers: runtimeAsyncAwaitHelpers); + comp.VerifyDiagnostics( + // (3,7): error CS0453: The type 'CAwaiter' must be a non-nullable value type in order to use it as parameter 'TAwaiter' in the generic type or method 'AsyncHelpers.AwaitAwaiter(TAwaiter)' + // await new C(); + Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "new C()").WithArguments("System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter(TAwaiter)", "TAwaiter", "CAwaiter").WithLocation(3, 7) + ); + } + + [Fact] + public void UnsafeAwaitAwaiterConstraintsViolation() + { + var runtimeAsyncAwaitHelpers = """ + namespace System.Runtime.CompilerServices + { + public static class AsyncHelpers + { + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion + {} + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : class, ICriticalNotifyCompletion + {} + + public static void Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static void Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + } + } + """; + + var code = """ + await System.Threading.Tasks.Task.Yield(); + """; + + var comp = CreateRuntimeAsyncCompilation(code, runtimeAsyncAwaitHelpers: runtimeAsyncAwaitHelpers); + comp.VerifyDiagnostics( + // (1,7): error CS0452: The type 'YieldAwaitable.YieldAwaiter' must be a reference type in order to use it as parameter 'TAwaiter' in the generic type or method 'AsyncHelpers.UnsafeAwaitAwaiter(TAwaiter)' + // await System.Threading.Tasks.Task.Yield(); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "System.Threading.Tasks.Task.Yield()").WithArguments("System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter(TAwaiter)", "TAwaiter", "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter").WithLocation(1, 7) + ); + } + + [Fact] + public void TaskTAwaitConstraintsViolation() + { + var runtimeAsyncAwaitHelpers = """ + namespace System.Runtime.CompilerServices + { + public static class AsyncHelpers + { + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion + {} + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : class, ICriticalNotifyCompletion + {} + + public static void Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static void Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.Task task) where T : class => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + } + } + """; + + var code = """ + await System.Threading.Tasks.Task.FromResult(1); + """; + + var comp = CreateRuntimeAsyncCompilation(code, runtimeAsyncAwaitHelpers: runtimeAsyncAwaitHelpers); + comp.VerifyDiagnostics( + // (1,7): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'AsyncHelpers.Await(Task)' + // await System.Threading.Tasks.Task.FromResult(1); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "System.Threading.Tasks.Task.FromResult(1)").WithArguments("System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)", "T", "int").WithLocation(1, 7) + ); + } + + [Fact] + public void ValueTaskTAwaitConstraintsViolation() + { + var runtimeAsyncAwaitHelpers = """ + namespace System.Runtime.CompilerServices + { + public static class AsyncHelpers + { + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion + {} + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : class, ICriticalNotifyCompletion + {} + + public static void Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static void Await(System.Threading.Tasks.ValueTask task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); + public static T Await(System.Threading.Tasks.ValueTask task) where T : class => task.GetAwaiter().GetResult(); + } + } + """; + + var code = """ + await default(System.Threading.Tasks.ValueTask); + """; + + var comp = CreateRuntimeAsyncCompilation(code, runtimeAsyncAwaitHelpers: runtimeAsyncAwaitHelpers); + comp.VerifyDiagnostics( + // (1,7): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'AsyncHelpers.Await(ValueTask)' + // await default(System.Threading.Tasks.ValueTask); + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "default(System.Threading.Tasks.ValueTask)").WithArguments("System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)", "T", "int").WithLocation(1, 7) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs index ec6de998246ec..12b502c04f786 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs @@ -55,18 +55,24 @@ public void PresentCorLib() MetadataOrSourceAssemblySymbol msCorLibRef = (MetadataOrSourceAssemblySymbol)assemblies[0]; - var knownMissingTypes = new HashSet() + var knownMissingSpecialTypes = new HashSet() { - (int)SpecialType.System_Runtime_CompilerServices_InlineArrayAttribute + SpecialType.System_Runtime_CompilerServices_InlineArrayAttribute, + }; + + var knownMissingInternalSpecialTypes = new HashSet() + { + InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, }; for (int i = 1; i <= (int)SpecialType.Count; i++) { - var t = msCorLibRef.GetSpecialType((SpecialType)i); - Assert.Equal((SpecialType)i, t.SpecialType); + var specialType = (SpecialType)i; + var t = msCorLibRef.GetSpecialType(specialType); + Assert.Equal(specialType, t.SpecialType); Assert.Equal((ExtendedSpecialType)i, t.ExtendedSpecialType); Assert.Same(msCorLibRef, t.ContainingAssembly); - if (knownMissingTypes.Contains(i)) + if (knownMissingSpecialTypes.Contains(specialType)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); @@ -79,11 +85,12 @@ public void PresentCorLib() for (int i = (int)InternalSpecialType.First; i < (int)InternalSpecialType.NextAvailable; i++) { - var t = msCorLibRef.GetSpecialType((InternalSpecialType)i); + var internalSpecialType = (InternalSpecialType)i; + var t = msCorLibRef.GetSpecialType(internalSpecialType); Assert.Equal(SpecialType.None, t.SpecialType); Assert.Equal((ExtendedSpecialType)i, t.ExtendedSpecialType); Assert.Same(msCorLibRef, t.ContainingAssembly); - if (knownMissingTypes.Contains(i)) + if (knownMissingInternalSpecialTypes.Contains(internalSpecialType)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); @@ -128,8 +135,8 @@ public void PresentCorLib() } } - Assert.Equal((int)SpecialType.Count, count + knownMissingTypes.Count); - Assert.Equal(knownMissingTypes.Any(), msCorLibRef.KeepLookingForDeclaredSpecialTypes); + Assert.Equal((int)SpecialType.Count, count + knownMissingSpecialTypes.Count); + Assert.Equal(knownMissingSpecialTypes.Any(), msCorLibRef.KeepLookingForDeclaredSpecialTypes); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 9846f57e88268..28013feccafbf 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -568,7 +568,13 @@ public void AllSpecialTypeMembers() || special == SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor || special == SpecialMember.System_Runtime_CompilerServices_InlineArrayAttribute__ctor || special == SpecialMember.System_ReadOnlySpan_T__ctor_Reference - || special == SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__Async) + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T + ) { Assert.Null(symbol); // Not available } @@ -917,7 +923,7 @@ public void AllWellKnownTypesBeforeCSharp7() } // There were 200 well-known types prior to CSharp7 - Assert.Equal(200, (int)(WellKnownType.CSharp7Sentinel - WellKnownType.First)); + Assert.Equal(200, (int)(WellKnownType.CSharp7Sentinel - WellKnownType.First - 1 /* WellKnownTypes.ExtSentinel is before CSharp7Sentinel */)); } [Fact] @@ -1023,12 +1029,6 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_Runtime_CompilerServices_Unsafe__AsRef_T: case WellKnownMember.System_Runtime_CompilerServices_RequiresLocationAttribute__ctor: case WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter: - case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter: // Not yet in the platform. continue; case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile: diff --git a/src/Compilers/Core/CodeAnalysisTest/Symbols/SpecialTypeTests.cs b/src/Compilers/Core/CodeAnalysisTest/Symbols/SpecialTypeTests.cs index 4689c2b19fc62..bd60fb5b790a0 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Symbols/SpecialTypeTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Symbols/SpecialTypeTests.cs @@ -17,8 +17,8 @@ public void ExtendedSpecialType_ToString() AssertEx.Equal("System_Runtime_CompilerServices_InlineArrayAttribute", ((ExtendedSpecialType)SpecialType.Count).ToString()); AssertEx.Equal("System_ReadOnlySpan_T", ((ExtendedSpecialType)InternalSpecialType.First).ToString()); AssertEx.Equal("System_ReadOnlySpan_T", ((ExtendedSpecialType)InternalSpecialType.System_ReadOnlySpan_T).ToString()); - AssertEx.Equal("System_Reflection_MethodInfo", ((ExtendedSpecialType)(InternalSpecialType.NextAvailable - 1)).ToString()); - AssertEx.Equal("52", ((ExtendedSpecialType)InternalSpecialType.NextAvailable).ToString()); + AssertEx.Equal("System_Runtime_CompilerServices_ICriticalNotifyCompletion", ((ExtendedSpecialType)(InternalSpecialType.NextAvailable - 1)).ToString()); + AssertEx.Equal("58", ((ExtendedSpecialType)InternalSpecialType.NextAvailable).ToString()); } } } diff --git a/src/Compilers/Core/Portable/ExtendedSpecialType.cs b/src/Compilers/Core/Portable/ExtendedSpecialType.cs index a5b5eb8212982..3cda91d247483 100644 --- a/src/Compilers/Core/Portable/ExtendedSpecialType.cs +++ b/src/Compilers/Core/Portable/ExtendedSpecialType.cs @@ -26,6 +26,7 @@ private ExtendedSpecialType(int value) public static explicit operator SpecialType(ExtendedSpecialType value) => value._value < (int)InternalSpecialType.First ? (SpecialType)value._value : SpecialType.None; public static implicit operator ExtendedSpecialType(InternalSpecialType value) => new ExtendedSpecialType((int)value); + public static explicit operator InternalSpecialType(ExtendedSpecialType value) => value._value is < (int)InternalSpecialType.First or >= (int)InternalSpecialType.NextAvailable ? InternalSpecialType.Unknown : (InternalSpecialType)value._value; public static explicit operator ExtendedSpecialType(int value) => new ExtendedSpecialType(value); public static explicit operator int(ExtendedSpecialType value) => value._value; @@ -56,6 +57,9 @@ public override int GetHashCode() return _value.GetHashCode(); } + /// + /// Returns a string representation of the ExtendedSpecialType. This exists only for debugging purposes. + /// public override string ToString() { if (_value > (int)SpecialType.None && _value <= (int)SpecialType.Count) @@ -63,7 +67,15 @@ public override string ToString() return ((SpecialType)_value).ToString(); } - if (_value >= (int)InternalSpecialType.First && _value < (int)InternalSpecialType.NextAvailable) + // When there are overlapping labels for a value in an enum, it is undefined which label is returned. + // ReadOnlySpan is the one we care about most from a debugging perspective. + Debug.Assert(InternalSpecialType.First == InternalSpecialType.System_ReadOnlySpan_T); + if (_value == (int)InternalSpecialType.System_ReadOnlySpan_T) + { + return nameof(InternalSpecialType.System_ReadOnlySpan_T); + } + + if (_value > (int)InternalSpecialType.First && _value < (int)InternalSpecialType.NextAvailable) { return ((InternalSpecialType)_value).ToString(); } diff --git a/src/Compilers/Core/Portable/InternalSpecialType.cs b/src/Compilers/Core/Portable/InternalSpecialType.cs index 23030db82f4ae..3483c6d11a9aa 100644 --- a/src/Compilers/Core/Portable/InternalSpecialType.cs +++ b/src/Compilers/Core/Portable/InternalSpecialType.cs @@ -63,6 +63,66 @@ internal enum InternalSpecialType : sbyte /// System_Reflection_MethodInfo, + /// + /// Indicates that the type is System.Runtime.CompilerServices.AsyncHelpers from the COR library. + /// + System_Runtime_CompilerServices_AsyncHelpers, + + /// + /// Indicates that the type is from the COR library. + /// + /// + /// Check for this special type cannot be used to find the "canonical" definition of + /// since it is fully legal for it to come from sources other than the COR library. + /// The should be used for that purpose instead. + /// This entry mostly exists so that compiler can tell this type apart when resolving other members of the COR library. + /// + System_Threading_Tasks_Task, + + /// + /// Indicates that the type is from the COR library. + /// + /// + /// Check for this special type cannot be used to find the "canonical" definition of + /// since it is fully legal for it to come from sources other than the COR library. + /// The should be used for that purpose instead. + /// This entry mostly exists so that compiler can tell this type apart when resolving other members of the COR library. + /// + System_Threading_Tasks_Task_T, + + /// + /// Indicates that the type is from the COR library. + /// + /// + /// Check for this special type cannot be used to find the "canonical" definition of + /// since it is fully legal for it to come from sources other than the COR library. + /// The should be used for that purpose instead. + /// This entry mostly exists so that compiler can tell this type apart when resolving other members of the COR library. + /// + System_Threading_Tasks_ValueTask, + + /// + /// Indicates that the type is from the COR library. + /// + /// + /// Check for this special type cannot be used to find the "canonical" definition of + /// since it is fully legal for it to come from sources other than the COR library. + /// The should be used for that purpose instead. + /// This entry mostly exists so that compiler can tell this type apart when resolving other members of the COR library. + /// + System_Threading_Tasks_ValueTask_T, + + /// + /// Indicates that the type is from the COR library. + /// + /// + /// Check for this special type cannot be used to find the "canonical" definition of + /// since it is fully legal for it to come from sources other than the COR library. + /// The should be used for that purpose instead. + /// This entry mostly exists so that compiler can tell this type apart when resolving other members of the COR library. + /// + System_Runtime_CompilerServices_ICriticalNotifyCompletion, + /// /// This item should be kept last and it doesn't represent any specific type. /// diff --git a/src/Compilers/Core/Portable/SpecialMember.cs b/src/Compilers/Core/Portable/SpecialMember.cs index 4fa34a9a51d36..ad4f9b0aa1c54 100644 --- a/src/Compilers/Core/Portable/SpecialMember.cs +++ b/src/Compilers/Core/Portable/SpecialMember.cs @@ -165,7 +165,6 @@ internal enum SpecialMember System_Runtime_CompilerServices_RuntimeFeature__NumericIntPtr, System_Runtime_CompilerServices_RuntimeFeature__ByRefFields, System_Runtime_CompilerServices_RuntimeFeature__ByRefLikeGenerics, - System_Runtime_CompilerServices_RuntimeFeature__Async, System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor, System_Runtime_CompilerServices_InlineArrayAttribute__ctor, @@ -195,6 +194,13 @@ internal enum SpecialMember System_Type__GetTypeFromHandle, + System_Runtime_CompilerServices_AsyncHelpers__AwaitTask, + System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T, + System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask, + System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T, + System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter, + System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter, + Count } } diff --git a/src/Compilers/Core/Portable/SpecialMembers.cs b/src/Compilers/Core/Portable/SpecialMembers.cs index 0d60f36df8f10..bd8eae02116e6 100644 --- a/src/Compilers/Core/Portable/SpecialMembers.cs +++ b/src/Compilers/Core/Portable/SpecialMembers.cs @@ -1141,12 +1141,6 @@ static SpecialMembers() 0, // Arity (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, // Field Signature - // System_Runtime_CompilerServices_RuntimeFeature__Async - (byte)(MemberFlags.Field | MemberFlags.Static), // Flags - (byte)SpecialType.System_Runtime_CompilerServices_RuntimeFeature, // DeclaringTypeId - 0, // Arity - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, // Field Signature - // System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor (byte)MemberFlags.Constructor, // Flags (byte)SpecialType.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute, // DeclaringTypeId @@ -1319,6 +1313,58 @@ static SpecialMembers() 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Type, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_RuntimeTypeHandle, + + // System_Runtime_CompilerServices_AsyncHelpers__AwaitTask + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Threading_Tasks_Task, + + // System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 1, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return Type + (byte)SignatureTypeCode.GenericTypeInstance, (byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Threading_Tasks_Task_T, + 1, + (byte)SignatureTypeCode.GenericMethodParameter, 0, + + // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Threading_Tasks_ValueTask, + + // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 1, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return Type + (byte)SignatureTypeCode.GenericTypeInstance, (byte)SignatureTypeCode.TypeHandle, (byte)InternalSpecialType.System_Threading_Tasks_ValueTask_T, + 1, + (byte)SignatureTypeCode.GenericMethodParameter, 0, + + // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 1, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.GenericMethodParameter, 0, + + // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId + 1, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.GenericMethodParameter, 0, }; string[] allNames = new string[(int)SpecialMember.Count] @@ -1458,7 +1504,6 @@ static SpecialMembers() "NumericIntPtr", // System_Runtime_CompilerServices_RuntimeFeature__NumericIntPtr "ByRefFields", // System_Runtime_CompilerServices_RuntimeFeature__ByRefFields "ByRefLikeGenerics", // System_Runtime_CompilerServices_RuntimeFeature__ByRefLikeGenerics - "Async", // System_Runtime_CompilerServices_RuntimeFeature__Async ".ctor", // System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor ".ctor", // System_Runtime_CompilerServices_InlineArrayAttribute__ctor ".ctor", // System_ReadOnlySpan_T__ctor_Reference @@ -1481,6 +1526,12 @@ static SpecialMembers() "Empty", // System_Array__Empty "SetValue", // System_Array__SetValue "GetTypeFromHandle", // System_Type__GetTypeFromHandle + "Await", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTask + "Await", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T + "Await", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask + "Await", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T + "AwaitAwaiter", // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter + "UnsafeAwaitAwaiter", // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter }; s_descriptors = MemberDescriptor.InitializeFromStream(new System.IO.MemoryStream(initializationBytes, writable: false), allNames); diff --git a/src/Compilers/Core/Portable/SpecialTypes.cs b/src/Compilers/Core/Portable/SpecialTypes.cs index d4bca2aef4b50..d3d9b9926b403 100644 --- a/src/Compilers/Core/Portable/SpecialTypes.cs +++ b/src/Compilers/Core/Portable/SpecialTypes.cs @@ -75,6 +75,12 @@ internal static class SpecialTypes "System.Type", "System.Reflection.MethodBase", "System.Reflection.MethodInfo", + "System.Runtime.CompilerServices.AsyncHelpers", + "System.Threading.Tasks.Task", + "System.Threading.Tasks.Task`1", + "System.Threading.Tasks.ValueTask", + "System.Threading.Tasks.ValueTask`1", + "System.Runtime.CompilerServices.ICriticalNotifyCompletion", }; private static readonly Dictionary s_nameToTypeIdMap; diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index fc768dcca4fb8..c3c78f3858415 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -150,12 +150,6 @@ internal enum WellKnownMember System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T, System_Runtime_CompilerServices_RuntimeHelpers__EnsureSufficientExecutionStack, - System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask, - System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T, - System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask, - System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T, - System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter, - System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter, System_Runtime_CompilerServices_Unsafe__Add_T, System_Runtime_CompilerServices_Unsafe__As_T, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 0cb65cceb46e4..300711917c75b 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -1033,56 +1033,6 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - // System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 0, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Threading_Tasks_Task, - - // System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 1, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return Type - (byte)SignatureTypeCode.GenericTypeInstance, (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Threading_Tasks_Task_T, 1, - (byte)SignatureTypeCode.GenericMethodParameter, 0, - - // System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 0, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Threading_Tasks_ValueTask - WellKnownType.ExtSentinel), - - // System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 1, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return Type - (byte)SignatureTypeCode.GenericTypeInstance, (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Threading_Tasks_ValueTask_T - WellKnownType.ExtSentinel), 1, - (byte)SignatureTypeCode.GenericMethodParameter, 0, - - // System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 1, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.GenericMethodParameter, 0, - - // System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter - (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId - 1, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.GenericMethodParameter, 0, - // System_Runtime_CompilerServices_Unsafe__Add_T (byte)(MemberFlags.Method | MemberFlags.Static), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_Unsafe - WellKnownType.ExtSentinel), // DeclaringTypeId @@ -2634,15 +2584,15 @@ static WellKnownMembers() // System_Windows_Forms_Application__RunForm (byte)(MemberFlags.Method | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Windows_Forms_Application, // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Windows_Forms_Application - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type - (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Windows_Forms_Form, + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Windows_Forms_Form - WellKnownType.ExtSentinel), // System_Environment__CurrentManagedThreadId (byte)(MemberFlags.Property | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Environment, // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Environment - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // Return Type @@ -2657,13 +2607,13 @@ static WellKnownMembers() // System_Runtime_GCLatencyMode__SustainedLowLatency (byte)(MemberFlags.Field | MemberFlags.Static), // Flags - (byte)WellKnownType.System_Runtime_GCLatencyMode, // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_GCLatencyMode - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity - (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Runtime_GCLatencyMode, // Field Signature + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_GCLatencyMode - WellKnownType.ExtSentinel), // Field Signature // System_ValueTuple_T1__Item1 (byte)MemberFlags.Field, // Flags - (byte)WellKnownType.System_ValueTuple_T1, // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ValueTuple_T1 - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity (byte)SignatureTypeCode.GenericTypeParameter, 0, // Field Signature @@ -2879,7 +2829,7 @@ static WellKnownMembers() // System_ValueTuple_T1__ctor (byte)MemberFlags.Constructor, // Flags - (byte)WellKnownType.System_ValueTuple_T1, // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ValueTuple_T1 - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type @@ -5375,12 +5325,6 @@ static WellKnownMembers() "get_OffsetToStringData", // System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData "GetSubArray", // System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T "EnsureSufficientExecutionStack", // System_Runtime_CompilerServices_RuntimeHelpers__EnsureSufficientExecutionStack - "Await", // System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask - "Await", // System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T - "Await", // System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask - "Await", // System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T - "AwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter - "UnsafeAwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter "Add", // System_Runtime_CompilerServices_Unsafe__Add_T "As", // System_Runtime_CompilerServices_Unsafe__As_T, "AsRef", // System_Runtime_CompilerServices_Unsafe__AsRef_T, diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index bf210b97a1ec2..d3cff714f0552 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -237,6 +237,8 @@ internal enum WellKnownType System_Runtime_CompilerServices_AsyncStateMachineAttribute, System_Runtime_CompilerServices_IteratorStateMachineAttribute, + ExtSentinel, // Not a real type, just a marker for types above 255 and strictly below 512 + System_Windows_Forms_Form, System_Windows_Forms_Application, @@ -249,9 +251,6 @@ internal enum WellKnownType System_ValueTuple, System_ValueTuple_T1, - - ExtSentinel, // Not a real type, just a marker for types above 255 and strictly below 512 - System_ValueTuple_T2, System_ValueTuple_T3, System_ValueTuple_T4, @@ -587,6 +586,8 @@ internal static class WellKnownTypes "System.Runtime.CompilerServices.AsyncStateMachineAttribute", "System.Runtime.CompilerServices.IteratorStateMachineAttribute", + "", // WellKnownType.ExtSentinel extension marker + "System.Windows.Forms.Form", "System.Windows.Forms.Application", @@ -595,10 +596,8 @@ internal static class WellKnownTypes "System.Runtime.GCLatencyMode", "System.ValueTuple", - "System.ValueTuple`1", - - "", // WellKnownType.ExtSentinel extension marker + "System.ValueTuple`1", "System.ValueTuple`2", "System.ValueTuple`3", "System.ValueTuple`4", @@ -758,8 +757,9 @@ private static void AssertEnumAndTableInSync() // Some compile time asserts { // We should not add new types to CSharp7 set - _ = new int[(int)WellKnownType.CSharp7Sentinel - 252]; - _ = new int[252 - (int)WellKnownType.CSharp7Sentinel]; + const int ExpectedCSharp7SentinelValue = 200 + (int)InternalSpecialType.NextAvailable + 1 /* Placeholder for ExtSentinel */; + _ = new int[(int)WellKnownType.CSharp7Sentinel - ExpectedCSharp7SentinelValue]; + _ = new int[ExpectedCSharp7SentinelValue - (int)WellKnownType.CSharp7Sentinel]; // The WellKnownType.ExtSentinel value must be 255 _ = new int[(int)WellKnownType.ExtSentinel - 255]; diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index f07cbf2354530..cdb65adb414d8 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -800,11 +800,11 @@ public CompilerLoweringPreserveAttribute() { } internal const string RuntimeAsyncAwaitHelpers = """ namespace System.Runtime.CompilerServices { - public static class RuntimeHelpers + public static class AsyncHelpers { - public static void AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion {} - public static void UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion {} public static void Await(System.Threading.Tasks.Task task) => task.GetAwaiter().GetResult(); diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb index f60df157f3480..0114324a7a43b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb @@ -426,7 +426,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Private ReadOnly Property RuntimeSupportsAsyncMethods As Boolean Get ' Keep in sync with C#'s AssemblySymbol.RuntimeSupportsAsyncMethods - Return RuntimeSupportsFeature(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__Async) + Dim asyncHelpers = GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers) + Return asyncHelpers IsNot Nothing AndAlso + asyncHelpers.IsClassType() AndAlso + asyncHelpers.IsMetadataAbstract AndAlso + asyncHelpers.IsMetadataSealed End Get End Property diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb index e6a81031b282d..329870724bda3 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb @@ -50,14 +50,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.CorLibrary Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetCoreApp.SystemRuntime}) Dim msCorLibRef As MetadataOrSourceAssemblySymbol = DirectCast(assemblies(0), MetadataOrSourceAssemblySymbol) - Dim knownMissingTypes As HashSet(Of Integer) = New HashSet(Of Integer) From {SpecialType.System_Runtime_CompilerServices_InlineArrayAttribute} + Dim knownMissingSpecialTypes As HashSet(Of SpecialType) = New HashSet(Of SpecialType) From {SpecialType.System_Runtime_CompilerServices_InlineArrayAttribute} + Dim knownMissingInternalSpecialTypes As HashSet(Of InternalSpecialType) = New HashSet(Of InternalSpecialType) From {InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers} For i As Integer = 1 To SpecialType.Count - Dim t = msCorLibRef.GetSpecialType(CType(i, SpecialType)) + Dim specialType = CType(i, SpecialType) + Dim t = msCorLibRef.GetSpecialType(specialType) Assert.Equal(CType(i, SpecialType), t.SpecialType) Assert.Equal(CType(i, ExtendedSpecialType), t.ExtendedSpecialType) Assert.Same(msCorLibRef, t.ContainingAssembly) - If knownMissingTypes.Contains(i) Then + If knownMissingSpecialTypes.Contains(specialType) Then ' not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind) Else @@ -66,11 +68,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.CorLibrary Next For i As Integer = InternalSpecialType.First To InternalSpecialType.NextAvailable - 1 - Dim t = msCorLibRef.GetSpecialType(CType(i, InternalSpecialType)) + Dim internalSpecialType = CType(i, InternalSpecialType) + Dim t = msCorLibRef.GetSpecialType(internalSpecialType) Assert.Equal(SpecialType.None, t.SpecialType) Assert.Equal(CType(i, ExtendedSpecialType), t.ExtendedSpecialType) Assert.Same(msCorLibRef, t.ContainingAssembly) - If knownMissingTypes.Contains(i) Then + If knownMissingInternalSpecialTypes.Contains(internalSpecialType) Then ' not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind) Else @@ -106,8 +109,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.CorLibrary Next End While - Assert.Equal(count + knownMissingTypes.Count, CType(SpecialType.Count, Integer)) - Assert.Equal(knownMissingTypes.Any(), msCorLibRef.KeepLookingForDeclaredSpecialTypes) + Assert.Equal(count + knownMissingSpecialTypes.Count, CType(SpecialType.Count, Integer)) + Assert.Equal(knownMissingSpecialTypes.Any(), msCorLibRef.KeepLookingForDeclaredSpecialTypes) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index c1c6cea34fcb9..2c9d1cb54f8c6 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -498,7 +498,12 @@ End Namespace special = SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor OrElse special = SpecialMember.System_Runtime_CompilerServices_InlineArrayAttribute__ctor OrElse special = SpecialMember.System_ReadOnlySpan_T__ctor_Reference OrElse - special = SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__Async Then + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T Then Assert.Null(symbol) ' Not available Else Assert.NotNull(symbol) @@ -759,13 +764,7 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle, WellKnownMember.System_Runtime_CompilerServices_RequiresLocationAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, @@ -976,13 +975,7 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle, WellKnownMember.System_Runtime_CompilerServices_RequiresLocationAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter, - WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,