From 351c3864d04953718ce7b5126667c09ee8237fa7 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 22 Apr 2025 15:16:20 -0700 Subject: [PATCH 01/15] Add AsyncHelpers as an internal special type --- src/Compilers/Core/Portable/InternalSpecialType.cs | 5 +++++ src/Compilers/Core/Portable/SpecialTypes.cs | 1 + src/Compilers/Core/Portable/WellKnownMembers.cs | 4 ++-- src/Compilers/Core/Portable/WellKnownTypes.cs | 10 +++++----- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Compilers/Core/Portable/InternalSpecialType.cs b/src/Compilers/Core/Portable/InternalSpecialType.cs index 23030db82f4ae..9d44908fabacc 100644 --- a/src/Compilers/Core/Portable/InternalSpecialType.cs +++ b/src/Compilers/Core/Portable/InternalSpecialType.cs @@ -63,6 +63,11 @@ internal enum InternalSpecialType : sbyte /// System_Reflection_MethodInfo, + /// + /// Indicates that the type is System.Runtime.CompilerServices.AsyncHelpers from the COR library. + /// + System_Runtime_CompilerServices_AsyncHelpers, + /// /// This item should be kept last and it doesn't represent any specific type. /// diff --git a/src/Compilers/Core/Portable/SpecialTypes.cs b/src/Compilers/Core/Portable/SpecialTypes.cs index d4bca2aef4b50..45236c0a9d006 100644 --- a/src/Compilers/Core/Portable/SpecialTypes.cs +++ b/src/Compilers/Core/Portable/SpecialTypes.cs @@ -75,6 +75,7 @@ internal static class SpecialTypes "System.Type", "System.Reflection.MethodBase", "System.Reflection.MethodInfo", + "System.Runtime.CompilerServices.AsyncHelpers", }; private static readonly Dictionary s_nameToTypeIdMap; diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 0cb65cceb46e4..4a192623e9d07 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -2663,7 +2663,7 @@ static WellKnownMembers() // 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 +2879,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 diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index bf210b97a1ec2..dcb43e6ce55fd 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -248,10 +248,9 @@ 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_T1, System_ValueTuple_T2, System_ValueTuple_T3, System_ValueTuple_T4, @@ -595,10 +594,10 @@ 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; + _ = 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]; From 442f9f8c16314f5c4364c1186b8948e491f2cec1 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 22 Apr 2025 17:55:00 -0700 Subject: [PATCH 02/15] Progress on moving the type definitions. --- .../AsyncRewriter/RuntimeAsyncRewriter.cs | 26 +++---- .../Core/Portable/InternalSpecialType.cs | 44 +++++++++++ src/Compilers/Core/Portable/SpecialMember.cs | 7 ++ src/Compilers/Core/Portable/SpecialMembers.cs | 58 +++++++++++++++ src/Compilers/Core/Portable/SpecialTypes.cs | 4 + .../Core/Portable/WellKnownMember.cs | 6 -- .../Core/Portable/WellKnownMembers.cs | 73 +------------------ src/Compilers/Core/Portable/WellKnownTypes.cs | 12 +-- 8 files changed, 137 insertions(+), 93 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs index bd3a09a78f228..c137d217b6afd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs @@ -41,22 +41,22 @@ private RuntimeAsyncRewriter(CSharpCompilation compilation, SyntheticBoundNodeFa private NamedTypeSymbol Task { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task); + get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task); } = null!; private NamedTypeSymbol TaskT { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); + get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T); } = null!; private NamedTypeSymbol ValueTask { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); + get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask); } = null!; private NamedTypeSymbol ValueTaskT { - get => field ??= _compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask_T); + get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T); } = null!; [return: NotNullIfNotNull(nameof(node))] @@ -72,25 +72,25 @@ private NamedTypeSymbol ValueTaskT Debug.Assert(nodeType is not null); var originalType = nodeType.OriginalDefinition; - WellKnownMember awaitCall; + SpecialMember awaitCall; TypeWithAnnotations? maybeNestedType = null; if (ReferenceEquals(originalType, Task)) { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTask; + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask; } else if (ReferenceEquals(originalType, TaskT)) { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitTaskT_T; + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T; maybeNestedType = ((NamedTypeSymbol)nodeType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else if (ReferenceEquals(originalType, ValueTask)) { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTask; + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask; } else if (ReferenceEquals(originalType, ValueTaskT)) { - awaitCall = WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__AwaitValueTaskT_T; + awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T; maybeNestedType = ((NamedTypeSymbol)nodeType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else @@ -99,7 +99,7 @@ private NamedTypeSymbol ValueTaskT } // PROTOTYPE: Make sure that we report an error in initial binding if these are missing - var awaitMethod = (MethodSymbol?)_compilation.GetWellKnownTypeMember(awaitCall); + var awaitMethod = (MethodSymbol?)_compilation.GetSpecialTypeMember(awaitCall); Debug.Assert(awaitMethod is not null); if (maybeNestedType is { } nestedType) @@ -165,9 +165,9 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) 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); + var awaitMethod = (MethodSymbol?)_compilation.GetSpecialTypeMember(useUnsafeAwait + ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter); Debug.Assert(awaitMethod is { Arity: 1 }); diff --git a/src/Compilers/Core/Portable/InternalSpecialType.cs b/src/Compilers/Core/Portable/InternalSpecialType.cs index 9d44908fabacc..4f9dce73393e0 100644 --- a/src/Compilers/Core/Portable/InternalSpecialType.cs +++ b/src/Compilers/Core/Portable/InternalSpecialType.cs @@ -68,6 +68,50 @@ internal enum InternalSpecialType : sbyte /// 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, + /// /// 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..b9fc9748d02ef 100644 --- a/src/Compilers/Core/Portable/SpecialMember.cs +++ b/src/Compilers/Core/Portable/SpecialMember.cs @@ -195,6 +195,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__AwaitAwaiterFromRuntimeAsync_TAwaiter, + System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter, + Count } } diff --git a/src/Compilers/Core/Portable/SpecialMembers.cs b/src/Compilers/Core/Portable/SpecialMembers.cs index 0d60f36df8f10..6d67a0d627d93 100644 --- a/src/Compilers/Core/Portable/SpecialMembers.cs +++ b/src/Compilers/Core/Portable/SpecialMembers.cs @@ -1319,6 +1319,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__AwaitAwaiterFromRuntimeAsync_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__UnsafeAwaitAwaiterFromRuntimeAsync_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] @@ -1481,6 +1533,12 @@ static SpecialMembers() "Empty", // System_Array__Empty "SetValue", // System_Array__SetValue "GetTypeFromHandle", // System_Type__GetTypeFromHandle + "AwaitTask", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTask + "AwaitTaskT", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T + "AwaitValueTask", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask + "AwaitValueTaskT", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T + "AwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter + "UnsafeAwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_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 45236c0a9d006..0eb00f80def4c 100644 --- a/src/Compilers/Core/Portable/SpecialTypes.cs +++ b/src/Compilers/Core/Portable/SpecialTypes.cs @@ -76,6 +76,10 @@ internal static class SpecialTypes "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", }; 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 4a192623e9d07..814cc81d8bbc2 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -1033,65 +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 - 1, // Arity - 2, // Method Signature - (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return type - (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericMethodParameter, 0, - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, - // System_Runtime_CompilerServices_Unsafe__As_T (byte)(MemberFlags.Method | MemberFlags.Static), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_Unsafe - WellKnownType.ExtSentinel), // DeclaringTypeId @@ -2634,7 +2575,7 @@ 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 @@ -2642,7 +2583,7 @@ static WellKnownMembers() // 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,9 +2598,9 @@ 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 @@ -5375,12 +5316,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 dcb43e6ce55fd..e3454e17a5531 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -238,6 +238,9 @@ internal enum WellKnownType System_Runtime_CompilerServices_IteratorStateMachineAttribute, System_Windows_Forms_Form, + + ExtSentinel, // Not a real type, just a marker for types above 255 and strictly below 512 + System_Windows_Forms_Application, System_Environment, @@ -248,8 +251,6 @@ internal enum WellKnownType System_ValueTuple, - ExtSentinel, // Not a real type, just a marker for types above 255 and strictly below 512 - System_ValueTuple_T1, System_ValueTuple_T2, System_ValueTuple_T3, @@ -587,6 +588,9 @@ internal static class WellKnownTypes "System.Runtime.CompilerServices.IteratorStateMachineAttribute", "System.Windows.Forms.Form", + + "", // WellKnownType.ExtSentinel extension marker + "System.Windows.Forms.Application", "System.Environment", @@ -595,8 +599,6 @@ internal static class WellKnownTypes "System.ValueTuple", - "", // WellKnownType.ExtSentinel extension marker - "System.ValueTuple`1", "System.ValueTuple`2", "System.ValueTuple`3", @@ -757,7 +759,7 @@ private static void AssertEnumAndTableInSync() // Some compile time asserts { // We should not add new types to CSharp7 set - const int ExpectedCSharp7SentinelValue = 200 + (int)InternalSpecialType.NextAvailable; + const int ExpectedCSharp7SentinelValue = 200 + (int)InternalSpecialType.NextAvailable + 1 /* Placeholder for ExtSentinel */; _ = new int[(int)WellKnownType.CSharp7Sentinel - ExpectedCSharp7SentinelValue]; _ = new int[ExpectedCSharp7SentinelValue - (int)WellKnownType.CSharp7Sentinel]; From 216d5c9d348ffdb1c6ab51b64765112df0017146 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Wed, 23 Apr 2025 17:10:05 -0700 Subject: [PATCH 03/15] Remove async feature flag --- .../CSharp/Portable/Symbols/AssemblySymbol.cs | 2 +- .../Symbol/Symbols/MissingSpecialMember.cs | 14 +++++------ src/Compilers/Core/Portable/SpecialMember.cs | 1 - src/Compilers/Core/Portable/SpecialMembers.cs | 7 ------ .../Portable/Symbols/AssemblySymbol.vb | 6 ++++- .../WellKnownTypeValidationTests.vb | 23 +++++++------------ 6 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs index b1397c8ab12e7..ac65818388a60 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs @@ -506,7 +506,7 @@ internal void SetOverrideRuntimeSupportsAsyncMethods() // Keep in sync with VB's AssemblySymbol.RuntimeSupportsAsyncMethods internal bool RuntimeSupportsAsyncMethods - => RuntimeSupportsFeature(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__Async) + => GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers) is { TypeKind: TypeKind.Class, IsStatic: true } || _overrideRuntimeSupportsAsyncMethods; #nullable disable diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 9846f57e88268..1d2eebf725a59 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__AwaitAwaiterFromRuntimeAsync_TAwaiter + || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_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 } @@ -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/Portable/SpecialMember.cs b/src/Compilers/Core/Portable/SpecialMember.cs index b9fc9748d02ef..4a48d21ebd114 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, diff --git a/src/Compilers/Core/Portable/SpecialMembers.cs b/src/Compilers/Core/Portable/SpecialMembers.cs index 6d67a0d627d93..712b8bafd389f 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 @@ -1510,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 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/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index c1c6cea34fcb9..0928eb456291e 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__AwaitAwaiterFromRuntimeAsync_TAwaiter OrElse + special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_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, From ff721e525776ccfd8a70539477b0b0f3538a0e9d Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 11:24:19 -0700 Subject: [PATCH 04/15] Readd missing signature --- src/Compilers/Core/Portable/WellKnownMembers.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 814cc81d8bbc2..f7b17b1f45df9 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -1033,6 +1033,15 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + // System_Runtime_CompilerServices_Unsafe__Add_T + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_Unsafe - WellKnownType.ExtSentinel), // DeclaringTypeId + 1, // Arity + 2, // Method Signature + (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return type + (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericMethodParameter, 0, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, + // System_Runtime_CompilerServices_Unsafe__As_T (byte)(MemberFlags.Method | MemberFlags.Static), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_Unsafe - WellKnownType.ExtSentinel), // DeclaringTypeId From 1f5aefc747f13ccf063599e627aea71f8d073557 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 13:17:31 -0700 Subject: [PATCH 05/15] Move to a fully mocked corelib for testing --- .../CSharp/Portable/Symbols/AssemblySymbol.cs | 10 +- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 498 ++++++++++++++---- src/Compilers/Core/Portable/SpecialMembers.cs | 8 +- .../Test/Utilities/CSharp/CSharpTestBase.cs | 2 +- 4 files changed, 389 insertions(+), 129 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AssemblySymbol.cs index ac65818388a60..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 - => GetSpecialType(InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers) is { TypeKind: TypeKind.Class, IsStatic: true } - || _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/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 9db5670663bf0..18948c78a78ec 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,302 @@ 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 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 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 static class RuntimeHelpers + { + public static void AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion {} + public static void UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion {} + } + 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) + { + // 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); @@ -179,8 +474,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 +497,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 +540,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 +561,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 +601,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 +624,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 +661,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 +677,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 +718,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 +727,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 +735,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 +754,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 +772,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 +784,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 +794,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 +857,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 +866,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 +874,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 +893,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 +903,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 +916,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 +929,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 +981,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 +990,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 +998,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 +1016,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 +1025,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 +1037,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 +1049,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 +1094,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 +1103,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 +1111,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 +1133,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 +1148,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 +1166,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 +1181,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 +1225,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 +1234,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 +1242,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 +1260,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 +1270,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 +1282,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 +1292,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 +1338,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 +1347,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 +1355,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 +1373,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 +1382,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 +1391,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 +1400,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 } """, @@ -1209,8 +1494,7 @@ 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); verifier.VerifyDiagnostics(); @@ -1237,7 +1521,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" : "")}}AwaitAwaiterFromRuntimeAsync>(MyTaskAwaiter)" IL_0020: ldloc.1 IL_0021: callvirt "int MyTaskAwaiter.GetResult()" IL_0026: brtrue.s IL_0034 @@ -3050,8 +3334,7 @@ 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); verifier.VerifyIL("MyTask.Run", """ @@ -3075,7 +3358,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.AwaitAwaiterFromRuntimeAsync(MyTaskAwaiter)" IL_001f: ldloc.1 IL_0020: callvirt "int MyTaskAwaiter.GetResult()" IL_0025: ldc.i4.s 123 @@ -3177,8 +3460,7 @@ 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); verifier.VerifyIL("MyTask.Run", """ @@ -3202,7 +3484,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.AwaitAwaiterFromRuntimeAsync(MyTaskAwaiter)" IL_001f: ldloc.1 IL_0020: callvirt "int MyTaskBaseAwaiter.GetResult()" IL_0025: ldc.i4.s 123 @@ -6892,8 +7174,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 +7196,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.UnsafeAwaitAwaiterFromRuntimeAsync(System.Runtime.CompilerServices.TaskAwaiter)" IL_0023: ldloca.s V_0 IL_0025: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" IL_002a: ret @@ -6956,8 +7237,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 +7260,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.UnsafeAwaitAwaiterFromRuntimeAsync(System.Runtime.CompilerServices.TaskAwaiter)" IL_0028: ldloca.s V_1 IL_002a: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" IL_002f: ret @@ -7523,8 +7803,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,7 +7812,7 @@ 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 } """); @@ -7548,8 +7827,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, targetFramework: TargetFramework.Net90, parseOptions: WithRuntimeAsync(TestOptions.RegularPreview)); var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("", """ @@ -7591,8 +7869,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 +7919,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 +7928,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 +7959,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 +7968,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 +8021,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 +8030,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 +8080,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 +8125,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 +8156,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 +8180,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 +8211,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,8 +8249,7 @@ 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"; @@ -7995,7 +8265,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,8 +8306,7 @@ 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"; @@ -8053,7 +8322,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 +8365,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 +8395,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.UnsafeAwaitAwaiterFromRuntimeAsync(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 +8404,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 diff --git a/src/Compilers/Core/Portable/SpecialMembers.cs b/src/Compilers/Core/Portable/SpecialMembers.cs index 712b8bafd389f..6aa6a5ff9481e 100644 --- a/src/Compilers/Core/Portable/SpecialMembers.cs +++ b/src/Compilers/Core/Portable/SpecialMembers.cs @@ -1526,10 +1526,10 @@ static SpecialMembers() "Empty", // System_Array__Empty "SetValue", // System_Array__SetValue "GetTypeFromHandle", // System_Type__GetTypeFromHandle - "AwaitTask", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTask - "AwaitTaskT", // System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T - "AwaitValueTask", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask - "AwaitValueTaskT", // System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T + "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 "AwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter "UnsafeAwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter }; diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index f07cbf2354530..730c61ca3f06b 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -800,7 +800,7 @@ 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 {} From 33a4423b99b256c60519121d04691016555d576f Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 13:55:13 -0700 Subject: [PATCH 06/15] Rename AwaitAwaiter apis from api review --- .../AsyncRewriter/RuntimeAsyncRewriter.cs | 8 +++---- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 21 +++++++------------ .../Symbol/Symbols/MissingSpecialMember.cs | 4 ++-- src/Compilers/Core/Portable/SpecialMember.cs | 4 ++-- src/Compilers/Core/Portable/SpecialMembers.cs | 16 +++++++------- .../Test/Utilities/CSharp/CSharpTestBase.cs | 4 ++-- .../WellKnownTypeValidationTests.vb | 4 ++-- 7 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs index c137d217b6afd..23f21f4218e04 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/RuntimeAsyncRewriter.cs @@ -125,7 +125,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,7 +157,7 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) Debug.Assert(isCompletedMethod is not null); var isCompletedCall = _factory.Call(tmp, isCompletedMethod); - // UnsafeAwaitAwaiterFromRuntimeAsync(_tmp) OR AwaitAwaiterFromRuntimeAsync(_tmp) + // UnsafeAwaitAwaiter(_tmp) OR AwaitAwaiter(_tmp) var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; var useUnsafeAwait = _factory.Compilation.Conversions.ClassifyImplicitConversionFromType( tmp.Type, @@ -166,8 +166,8 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) // PROTOTYPE: Make sure that we report an error in initial binding if these are missing var awaitMethod = (MethodSymbol?)_compilation.GetSpecialTypeMember(useUnsafeAwait - ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter - : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter); + ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter + : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter); Debug.Assert(awaitMethod is { Arity: 1 }); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 18948c78a78ec..258fe979aaac7 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -285,11 +285,6 @@ public static class RuntimeFeature { public const string NumericIntPtr = nameof(NumericIntPtr); } - public static class RuntimeHelpers - { - public static void AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion {} - public static void UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion {} - } public struct TaskAwaiter : ICriticalNotifyCompletion { public void OnCompleted(Action continuation) {} @@ -1521,7 +1516,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.AsyncHelpers.{{(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 @@ -3358,7 +3353,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.AsyncHelpers.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 @@ -3484,7 +3479,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.AsyncHelpers.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 @@ -7196,7 +7191,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.AsyncHelpers.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 @@ -7260,7 +7255,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.AsyncHelpers.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 @@ -8252,7 +8247,7 @@ public bool IsCompleted 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) @@ -8309,7 +8304,7 @@ public bool IsCompleted 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) @@ -8395,7 +8390,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.AsyncHelpers.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 diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 1d2eebf725a59..75db88124ced1 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -568,8 +568,8 @@ 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_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter - || special == SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + || 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 diff --git a/src/Compilers/Core/Portable/SpecialMember.cs b/src/Compilers/Core/Portable/SpecialMember.cs index 4a48d21ebd114..ad4f9b0aa1c54 100644 --- a/src/Compilers/Core/Portable/SpecialMember.cs +++ b/src/Compilers/Core/Portable/SpecialMember.cs @@ -198,8 +198,8 @@ internal enum SpecialMember System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T, System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTask, System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T, - System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter, - System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter, + 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 6aa6a5ff9481e..bd8eae02116e6 100644 --- a/src/Compilers/Core/Portable/SpecialMembers.cs +++ b/src/Compilers/Core/Portable/SpecialMembers.cs @@ -1350,7 +1350,7 @@ static SpecialMembers() 1, (byte)SignatureTypeCode.GenericMethodParameter, 0, - // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter + // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter (byte)(MemberFlags.Method | MemberFlags.Static), // Flags (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId 1, // Arity @@ -1358,7 +1358,7 @@ static SpecialMembers() (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.GenericMethodParameter, 0, - // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter (byte)(MemberFlags.Method | MemberFlags.Static), // Flags (byte)InternalSpecialType.System_Runtime_CompilerServices_AsyncHelpers, // DeclaringTypeId 1, // Arity @@ -1526,12 +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 - "AwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter - "UnsafeAwaitAwaiterFromRuntimeAsync", // System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter + "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/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 730c61ca3f06b..cdb65adb414d8 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -802,9 +802,9 @@ namespace System.Runtime.CompilerServices { 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/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 0928eb456291e..2c9d1cb54f8c6 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -498,8 +498,8 @@ 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_AsyncHelpers__AwaitAwaiterFromRuntimeAsync_TAwaiter OrElse - special = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiterFromRuntimeAsync_TAwaiter OrElse + 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 From 79183193d0e7e00b519a1643cd78409181d67f99 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 16:22:57 -0700 Subject: [PATCH 07/15] Move method construction and validation into initial binding, and actually perform constraint validation on generically-constructed runtime helper methods. --- .../CSharp/Portable/Binder/Binder_Await.cs | 149 ++++++++- .../CSharp/Portable/Binder/Binder_Symbols.cs | 6 +- .../Portable/Binder/UsingStatementBinder.cs | 2 +- .../CSharp/Portable/BoundTree/BoundNodes.xml | 4 + .../Portable/Compilation/CSharpCompilation.cs | 23 +- .../Generated/BoundNodes.xml.Generated.cs | 17 +- .../AsyncRewriter/RuntimeAsyncRewriter.cs | 91 +----- .../ExtensionMethodReferenceRewriter.cs | 2 +- .../Lowering/MethodToClassRewriter.cs | 3 +- .../SynthesizedEntryPointSymbol.cs | 6 +- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 285 +++++++++++++++++- .../Core/Portable/InternalSpecialType.cs | 11 + src/Compilers/Core/Portable/SpecialTypes.cs | 1 + .../Core/Portable/WellKnownMembers.cs | 2 +- src/Compilers/Core/Portable/WellKnownTypes.cs | 6 +- 15 files changed, 496 insertions(+), 112 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index ce13976db5419..447ebb1d4d8b9 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? runtimeAsyncAwaitCall, 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, runtimeAsyncAwaitCall, 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 _, runtimeAsyncAwaitCall: 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? runtimeAsyncAwaitCall, 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 runtimeAsyncAwaitCall, node, diagnostics); } private bool GetAwaitableExpressionInfo( @@ -256,6 +259,7 @@ private bool GetAwaitableExpressionInfo( out PropertySymbol? isCompleted, out MethodSymbol? getResult, out BoundExpression? getAwaiterGetResultCall, + out MethodSymbol? runtimeAsyncAwaitCall, SyntaxNode node, BindingDiagnosticBag diagnostics) { @@ -266,6 +270,7 @@ private bool GetAwaitableExpressionInfo( isCompleted = null; getResult = null; getAwaiterGetResultCall = null; + runtimeAsyncAwaitCall = 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 (tryGetRuntimeAwaitHelper(out runtimeAsyncAwaitCall)) + { + return true; + } + if (!GetGetAwaiterMethod(getAwaiterArgument, node, diagnostics, out getAwaiter)) { return false; @@ -286,7 +302,130 @@ 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 runtimeAsyncAwaitCall)); + + bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) + { + if (!isRuntimeAsyncEnabled) + { + runtimeAwaitHelper = null; + return false; + } + + var exprOriginalType = expression.Type!.OriginalDefinition; + SpecialMember awaitCall; + TypeWithAnnotations? maybeNestedType = null; + 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; + maybeNestedType = ((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; + maybeNestedType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + } + else + { + runtimeAwaitHelper = null; + return false; + } + + runtimeAwaitHelper = (MethodSymbol)GetSpecialTypeMember(awaitCall, diagnostics, expression.Syntax); + + if (runtimeAwaitHelper is null) + { + return false; + } + + if (maybeNestedType is { } nestedType) + { + Debug.Assert(runtimeAwaitHelper.TypeParameters.Length == 1); + runtimeAwaitHelper = runtimeAwaitHelper.Construct([nestedType]); + checkMethodGenericConstraints(expression, diagnostics, runtimeAwaitHelper); + } +#if DEBUG + else + { + Debug.Assert(runtimeAwaitHelper.TypeParameters.Length == 0); + } +#endif + + return true; + } + + bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwaitAwaiterMethod) + { + // 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, + expression.Syntax); + + if (awaitMethod is null) + { + runtimeAwaitAwaiterMethod = null; + return false; + } + + Debug.Assert(awaitMethod is { Arity: 1 }); + + runtimeAwaitAwaiterMethod = awaitMethod.Construct(awaiterType); + checkMethodGenericConstraints(expression, diagnostics, runtimeAwaitAwaiterMethod); + + return true; + } + + void checkMethodGenericConstraints(BoundExpression expression, BindingDiagnosticBag diagnostics, MethodSymbol method) + { + var diagnosticsBuilder = ArrayBuilder.GetInstance(); + ArrayBuilder? useSiteDiagnosticsBuilder = null; + ConstraintsHelper.CheckMethodConstraints( + method, + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, location: expression.Syntax.Location, diagnostics: null), + diagnosticsBuilder, + nullabilityDiagnosticsBuilderOpt: null, + ref useSiteDiagnosticsBuilder); + + foreach (var pair in diagnosticsBuilder) + { + if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) + { + diagnostics.Add(diagnosticInfo, expression.Syntax.Location); + } + diagnosticsBuilder.Free(); + } + + if (useSiteDiagnosticsBuilder is { }) + { + foreach (var pair in useSiteDiagnosticsBuilder) + { + if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) + { + diagnostics.Add(diagnosticInfo, expression.Syntax.Location); + } + } + useSiteDiagnosticsBuilder.Free(); + } + } } /// 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/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 663c321f9aada..3db4e012a84cd 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -693,6 +693,10 @@ + + diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 4c141a2d75f5a..85728aab85b1c 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,21 @@ internal bool IsRuntimeAsyncEnabledIn(MethodSymbol method) return false; } - return method switch + if (symbol is not MethodSymbol method) + { + return false; + } + + var methodReturn = method.ReturnType.OriginalDefinition; + if (!ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task)) + && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T)) + && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask)) + && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T))) + { + return false; + } + + return symbol switch { SourceMethodSymbol { IsRuntimeAsyncEnabledInMethod: ThreeState.True } => true, SourceMethodSymbol { IsRuntimeAsyncEnabledInMethod: ThreeState.False } => false, @@ -2211,11 +2225,12 @@ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, BindingDiagnostic 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 result, out MethodSymbol? runtimeAwaitMethod, syntax, diagnostics); RoslynDebug.Assert(!namedType.IsDynamic()); + Debug.Assert(result is { Type: not null } || runtimeAwaitMethod is { ReturnType: not null }); return success && - (result!.Type!.IsVoidType() || result.Type!.SpecialType == SpecialType.System_Int32); + ((result?.Type ?? runtimeAwaitMethod!.ReturnType)!.IsVoidType() || result.Type!.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..ddefa3c2ab738 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,6 +2146,7 @@ public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awa this.GetAwaiter = getAwaiter; this.IsCompleted = isCompleted; this.GetResult = getResult; + this.RuntimeAsyncAwaitMethod = runtimeAsyncAwaitMethod; } public BoundAwaitableValuePlaceholder? AwaitableInstancePlaceholder { get; } @@ -2153,15 +2154,16 @@ public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awa 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 +11177,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 +13136,10 @@ public NullabilityRewriter(ImmutableDictionary field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task); - } = null!; - - private NamedTypeSymbol TaskT - { - get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T); - } = null!; - - private NamedTypeSymbol ValueTask - { - get => field ??= _compilation.GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask); - } = null!; - - private NamedTypeSymbol ValueTaskT - { - get => field ??= _compilation.GetSpecialType(InternalSpecialType.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; - - SpecialMember awaitCall; - TypeWithAnnotations? maybeNestedType = null; - if (ReferenceEquals(originalType, Task)) - { - awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask; - } - else if (ReferenceEquals(originalType, TaskT)) - { - awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T; - maybeNestedType = ((NamedTypeSymbol)nodeType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; - } - else if (ReferenceEquals(originalType, ValueTask)) - { - awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__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 = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__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.GetSpecialTypeMember(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) @@ -158,22 +111,10 @@ private BoundExpression RewriteCustomAwaiterAwait(BoundAwaitExpression node) var isCompletedCall = _factory.Call(tmp, isCompletedMethod); // UnsafeAwaitAwaiter(_tmp) OR AwaitAwaiter(_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.GetSpecialTypeMember(useUnsafeAwait - ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter - : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter); - - Debug.Assert(awaitMethod is { Arity: 1 }); - + 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/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index fc86c841ab206..ac668411c2d52 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!, runtimeAsyncAwaitCall: 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, runtimeAsyncAwaitCall: 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 258fe979aaac7..5f68388f53fcf 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -154,7 +154,7 @@ 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; @@ -328,10 +328,10 @@ public void GetResult() {} } """; - private static CSharpCompilation CreateRuntimeAsyncCompilation(CSharpTestSource source, IEnumerable references = null, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) + 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 corlib = CreateEmptyCompilation([RuntimeAsyncCoreLib, runtimeAsyncAwaitHelpers]); var compilation = CreateEmptyCompilation(source, references: [.. references ?? [], corlib.EmitToImageReference()], options: options, parseOptions: parseOptions ?? WithRuntimeAsync(TestOptions.RegularPreview)); return compilation; @@ -1429,7 +1429,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 { @@ -1475,7 +1475,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(); @@ -1491,7 +1493,10 @@ static void Main() 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", $$""" @@ -3268,7 +3273,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; @@ -3331,7 +3336,10 @@ static void Main() 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) @@ -3396,7 +3404,7 @@ public MyTaskAwaiter GetAwaiter() return new MyTaskAwaiter(); } - public async void Run() + public async System.Threading.Tasks.Task Run() { int tests = 0; @@ -3457,7 +3465,10 @@ static void Main() 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) @@ -8412,5 +8423,261 @@ .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) + ); + } + + [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) + ); + } + + [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) + ); + } + + [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) + ); + } + + [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) + ); + } + + [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) + ); + } + + [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/Core/Portable/InternalSpecialType.cs b/src/Compilers/Core/Portable/InternalSpecialType.cs index 4f9dce73393e0..3483c6d11a9aa 100644 --- a/src/Compilers/Core/Portable/InternalSpecialType.cs +++ b/src/Compilers/Core/Portable/InternalSpecialType.cs @@ -112,6 +112,17 @@ internal enum InternalSpecialType : sbyte /// 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/SpecialTypes.cs b/src/Compilers/Core/Portable/SpecialTypes.cs index 0eb00f80def4c..d3d9b9926b403 100644 --- a/src/Compilers/Core/Portable/SpecialTypes.cs +++ b/src/Compilers/Core/Portable/SpecialTypes.cs @@ -80,6 +80,7 @@ internal static class SpecialTypes "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/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index f7b17b1f45df9..300711917c75b 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -2588,7 +2588,7 @@ static WellKnownMembers() 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 diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index e3454e17a5531..d3cff714f0552 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -237,10 +237,9 @@ internal enum WellKnownType System_Runtime_CompilerServices_AsyncStateMachineAttribute, System_Runtime_CompilerServices_IteratorStateMachineAttribute, - System_Windows_Forms_Form, - ExtSentinel, // Not a real type, just a marker for types above 255 and strictly below 512 + System_Windows_Forms_Form, System_Windows_Forms_Application, System_Environment, @@ -587,10 +586,9 @@ internal static class WellKnownTypes "System.Runtime.CompilerServices.AsyncStateMachineAttribute", "System.Runtime.CompilerServices.IteratorStateMachineAttribute", - "System.Windows.Forms.Form", - "", // WellKnownType.ExtSentinel extension marker + "System.Windows.Forms.Form", "System.Windows.Forms.Application", "System.Environment", From 9df8371c85ac0aefff83a57a2835cb402145bfac Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 16:31:53 -0700 Subject: [PATCH 08/15] Additional missing member testing --- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 5f68388f53fcf..f491b869e9467 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -8438,6 +8438,11 @@ public void MissingAwaitTask() // 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); } [Fact] @@ -8454,6 +8459,11 @@ public void MissingAwaitTaskT() // 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); } [Fact] @@ -8470,6 +8480,11 @@ public void MissingAwaitValueTask() // 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); } [Fact] @@ -8486,6 +8501,11 @@ public void MissingAwaitValueTaskT() // 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); } [Fact] @@ -8502,6 +8522,11 @@ public void MissingUnsafeAwaitAwaiter() // 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); } [Fact] @@ -8532,6 +8557,11 @@ public void GetResult() {} // 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); } [Fact] From c10918c02d410d1f7f907b5a7934a6321937afac Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 16:36:26 -0700 Subject: [PATCH 09/15] Small order refactor --- src/Compilers/CSharp/Portable/Binder/Binder_Await.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index 447ebb1d4d8b9..5d0bfcd97399b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs @@ -351,7 +351,7 @@ bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) { Debug.Assert(runtimeAwaitHelper.TypeParameters.Length == 1); runtimeAwaitHelper = runtimeAwaitHelper.Construct([nestedType]); - checkMethodGenericConstraints(expression, diagnostics, runtimeAwaitHelper); + checkMethodGenericConstraints(runtimeAwaitHelper, diagnostics, expression.Syntax.Location); } #if DEBUG else @@ -389,18 +389,18 @@ bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwa Debug.Assert(awaitMethod is { Arity: 1 }); runtimeAwaitAwaiterMethod = awaitMethod.Construct(awaiterType); - checkMethodGenericConstraints(expression, diagnostics, runtimeAwaitAwaiterMethod); + checkMethodGenericConstraints(runtimeAwaitAwaiterMethod, diagnostics, expression.Syntax.Location); return true; } - void checkMethodGenericConstraints(BoundExpression expression, BindingDiagnosticBag diagnostics, MethodSymbol method) + void checkMethodGenericConstraints(MethodSymbol method, BindingDiagnosticBag diagnostics, Location location) { var diagnosticsBuilder = ArrayBuilder.GetInstance(); ArrayBuilder? useSiteDiagnosticsBuilder = null; ConstraintsHelper.CheckMethodConstraints( method, - new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, location: expression.Syntax.Location, diagnostics: null), + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, location, diagnostics: null), diagnosticsBuilder, nullabilityDiagnosticsBuilderOpt: null, ref useSiteDiagnosticsBuilder); @@ -409,7 +409,7 @@ void checkMethodGenericConstraints(BoundExpression expression, BindingDiagnostic { if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) { - diagnostics.Add(diagnosticInfo, expression.Syntax.Location); + diagnostics.Add(diagnosticInfo, location); } diagnosticsBuilder.Free(); } @@ -420,7 +420,7 @@ void checkMethodGenericConstraints(BoundExpression expression, BindingDiagnostic { if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) { - diagnostics.Add(diagnosticInfo, expression.Syntax.Location); + diagnostics.Add(diagnosticInfo, location); } } useSiteDiagnosticsBuilder.Free(); From 459f528f602fde827ed4378659cb1fa96f5a2fad Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 24 Apr 2025 17:00:15 -0700 Subject: [PATCH 10/15] NRT warning --- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 85728aab85b1c..f439f34c75cab 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2229,8 +2229,8 @@ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, BindingDiagnostic RoslynDebug.Assert(!namedType.IsDynamic()); Debug.Assert(result is { Type: not null } || runtimeAwaitMethod is { ReturnType: not null }); - return success && - ((result?.Type ?? runtimeAwaitMethod!.ReturnType)!.IsVoidType() || result.Type!.SpecialType == SpecialType.System_Int32); + var returnType = result?.Type ?? runtimeAwaitMethod!.ReturnType; + return success && (returnType.IsVoidType() || returnType.SpecialType == SpecialType.System_Int32); } /// From 0e5c942783ee4f7d0648351f97b05c74822e8bb3 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 29 Apr 2025 14:30:48 -0700 Subject: [PATCH 11/15] Test failures, fixed a null reference bug. --- .../Portable/Compilation/CSharpCompilation.cs | 10 +++++++--- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 12 ++++++------ .../Test/Symbol/Symbols/CorLibrary/CorTypes.cs | 17 +++++++++++------ .../Symbols/SpecialTypeTests.cs | 4 ++-- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index f439f34c75cab..bbbbcd84b4a3c 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2224,13 +2224,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, out MethodSymbol? runtimeAwaitMethod, syntax, diagnostics); + var success = binder.GetAwaitableExpressionInfo(dumbInstance, out BoundExpression? result, out MethodSymbol? runtimeAwaitMethod, syntax, diagnostics); RoslynDebug.Assert(!namedType.IsDynamic()); + if (!success) + { + return false; + } + Debug.Assert(result is { Type: not null } || runtimeAwaitMethod is { ReturnType: not null }); var returnType = result?.Type ?? runtimeAwaitMethod!.ReturnType; - return success && (returnType.IsVoidType() || returnType.SpecialType == SpecialType.System_Int32); + return returnType.IsVoidType() || returnType.SpecialType == SpecialType.System_Int32; } /// diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index f491b869e9467..4d2b1b0395451 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -8442,7 +8442,7 @@ public void MissingAwaitTask() // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] @@ -8463,7 +8463,7 @@ public void MissingAwaitTaskT() // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] @@ -8484,7 +8484,7 @@ public void MissingAwaitValueTask() // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] @@ -8505,7 +8505,7 @@ public void MissingAwaitValueTaskT() // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] @@ -8526,7 +8526,7 @@ public void MissingUnsafeAwaitAwaiter() // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] @@ -8561,7 +8561,7 @@ public void GetResult() {} // 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); + CompileAndVerify(comp, verify: Verification.FailsPEVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs index ec6de998246ec..e9af58aebfb5e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs @@ -55,9 +55,14 @@ 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++) @@ -66,7 +71,7 @@ public void PresentCorLib() Assert.Equal((SpecialType)i, t.SpecialType); Assert.Equal((ExtendedSpecialType)i, t.ExtendedSpecialType); Assert.Same(msCorLibRef, t.ContainingAssembly); - if (knownMissingTypes.Contains(i)) + if (knownMissingSpecialTypes.Contains((SpecialType)i)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); @@ -83,7 +88,7 @@ public void PresentCorLib() 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)i)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); @@ -128,8 +133,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/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()); } } } From fa1b1d9e49b06e8dd08445a0fc7f9623a198339c Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 29 Apr 2025 15:21:01 -0700 Subject: [PATCH 12/15] PR feedback --- .../CSharp/Portable/Binder/Binder_Await.cs | 90 +++-------- .../Portable/BoundTree/BoundAwaitableInfo.cs | 38 +++++ .../CSharp/Portable/BoundTree/BoundNodes.xml | 5 +- .../Generated/BoundNodes.xml.Generated.cs | 4 + .../SynthesizedEntryPointSymbol.cs | 4 +- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 146 +++++++++++++++++- 6 files changed, 214 insertions(+), 73 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/BoundTree/BoundAwaitableInfo.cs diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index 5d0bfcd97399b..99bb6b763b4f5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs @@ -59,12 +59,12 @@ internal BoundAwaitableInfo BindAwaitInfo(BoundAwaitableValuePlaceholder placeho out PropertySymbol? isCompleted, out MethodSymbol? getResult, getAwaiterGetResultCall: out _, - out MethodSymbol? runtimeAsyncAwaitCall, + out MethodSymbol? runtimeAsyncAwaitMethod, node, diagnostics); hasErrors |= hasGetAwaitableErrors; - return new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitCall, hasErrors: hasGetAwaitableErrors) { WasCompilerGenerated = true }; + return new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, runtimeAsyncAwaitMethod, hasErrors: hasGetAwaitableErrors) { WasCompilerGenerated = true }; } /// @@ -125,7 +125,7 @@ private bool CouldBeAwaited(BoundExpression expression) return false; } - return GetAwaitableExpressionInfo(expression, getAwaiterGetResultCall: out _, runtimeAsyncAwaitCall: out _, + return GetAwaitableExpressionInfo(expression, getAwaiterGetResultCall: out _, runtimeAsyncAwaitMethod: out _, node: syntax, diagnostics: BindingDiagnosticBag.Discarded); } @@ -244,11 +244,11 @@ private bool ReportBadAwaitContext(SyntaxNodeOrToken nodeOrToken, BindingDiagnos internal bool GetAwaitableExpressionInfo( BoundExpression expression, out BoundExpression? getAwaiterGetResultCall, - out MethodSymbol? runtimeAsyncAwaitCall, + out MethodSymbol? runtimeAsyncAwaitMethod, SyntaxNode node, BindingDiagnosticBag diagnostics) { - return GetAwaitableExpressionInfo(expression, expression, out _, out _, out _, out _, out getAwaiterGetResultCall, out runtimeAsyncAwaitCall, node, diagnostics); + return GetAwaitableExpressionInfo(expression, expression, out _, out _, out _, out _, out getAwaiterGetResultCall, out runtimeAsyncAwaitMethod, node, diagnostics); } private bool GetAwaitableExpressionInfo( @@ -259,7 +259,7 @@ private bool GetAwaitableExpressionInfo( out PropertySymbol? isCompleted, out MethodSymbol? getResult, out BoundExpression? getAwaiterGetResultCall, - out MethodSymbol? runtimeAsyncAwaitCall, + out MethodSymbol? runtimeAsyncAwaitMethod, SyntaxNode node, BindingDiagnosticBag diagnostics) { @@ -270,7 +270,7 @@ private bool GetAwaitableExpressionInfo( isCompleted = null; getResult = null; getAwaiterGetResultCall = null; - runtimeAsyncAwaitCall = null; + runtimeAsyncAwaitMethod = null; if (!ValidateAwaitedExpression(expression, node, diagnostics)) { @@ -289,7 +289,7 @@ private bool GetAwaitableExpressionInfo( // 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 (tryGetRuntimeAwaitHelper(out runtimeAsyncAwaitCall)) + if (isRuntimeAsyncEnabled && tryGetRuntimeAwaitHelper(expression, out runtimeAsyncAwaitMethod, diagnostics)) { return true; } @@ -303,19 +303,13 @@ private bool GetAwaitableExpressionInfo( return GetIsCompletedProperty(awaiterType, node, expression.Type!, diagnostics, out isCompleted) && AwaiterImplementsINotifyCompletion(awaiterType, node, diagnostics) && GetGetResultMethod(getAwaiter, node, expression.Type!, diagnostics, out getResult, out getAwaiterGetResultCall) - && (!isRuntimeAsyncEnabled || getRuntimeAwaitAwaiter(awaiterType, out runtimeAsyncAwaitCall)); + && (!isRuntimeAsyncEnabled || getRuntimeAwaitAwaiter(awaiterType, out runtimeAsyncAwaitMethod, expression.Syntax, diagnostics)); - bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) + bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runtimeAwaitHelper, BindingDiagnosticBag diagnostics) { - if (!isRuntimeAsyncEnabled) - { - runtimeAwaitHelper = null; - return false; - } - var exprOriginalType = expression.Type!.OriginalDefinition; SpecialMember awaitCall; - TypeWithAnnotations? maybeNestedType = null; + TypeWithAnnotations? maybeResultType = null; if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask; @@ -323,7 +317,7 @@ bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T; - maybeNestedType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + maybeResultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask, diagnostics, expression.Syntax))) { @@ -332,7 +326,7 @@ bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T; - maybeNestedType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + maybeResultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else { @@ -347,23 +341,20 @@ bool tryGetRuntimeAwaitHelper(out MethodSymbol? runtimeAwaitHelper) return false; } - if (maybeNestedType is { } nestedType) - { - Debug.Assert(runtimeAwaitHelper.TypeParameters.Length == 1); - runtimeAwaitHelper = runtimeAwaitHelper.Construct([nestedType]); - checkMethodGenericConstraints(runtimeAwaitHelper, diagnostics, expression.Syntax.Location); - } -#if DEBUG - else + Debug.Assert((runtimeAwaitHelper is { Arity: 1 } && maybeResultType is { }) || runtimeAwaitHelper.TypeParameters.Length == 0); + + if (maybeResultType is { } resultType) { - Debug.Assert(runtimeAwaitHelper.TypeParameters.Length == 0); + runtimeAwaitHelper = runtimeAwaitHelper.Construct([resultType]); + ConstraintsHelper.CheckConstraints( + runtimeAwaitHelper, + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, expression.Syntax.Location, diagnostics)); } -#endif return true; } - bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwaitAwaiterMethod) + 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. @@ -378,7 +369,7 @@ bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwa ? SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__UnsafeAwaitAwaiter_TAwaiter : SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitAwaiter_TAwaiter, diagnostics, - expression.Syntax); + syntax); if (awaitMethod is null) { @@ -389,43 +380,12 @@ bool getRuntimeAwaitAwaiter(TypeSymbol awaiterType, out MethodSymbol? runtimeAwa Debug.Assert(awaitMethod is { Arity: 1 }); runtimeAwaitAwaiterMethod = awaitMethod.Construct(awaiterType); - checkMethodGenericConstraints(runtimeAwaitAwaiterMethod, diagnostics, expression.Syntax.Location); + ConstraintsHelper.CheckConstraints( + runtimeAwaitAwaiterMethod, + new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, syntax.Location, diagnostics)); return true; } - - void checkMethodGenericConstraints(MethodSymbol method, BindingDiagnosticBag diagnostics, Location location) - { - var diagnosticsBuilder = ArrayBuilder.GetInstance(); - ArrayBuilder? useSiteDiagnosticsBuilder = null; - ConstraintsHelper.CheckMethodConstraints( - method, - new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: false, location, diagnostics: null), - diagnosticsBuilder, - nullabilityDiagnosticsBuilderOpt: null, - ref useSiteDiagnosticsBuilder); - - foreach (var pair in diagnosticsBuilder) - { - if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) - { - diagnostics.Add(diagnosticInfo, location); - } - diagnosticsBuilder.Free(); - } - - if (useSiteDiagnosticsBuilder is { }) - { - foreach (var pair in useSiteDiagnosticsBuilder) - { - if (pair.UseSiteInfo.DiagnosticInfo is { } diagnosticInfo) - { - diagnostics.Add(diagnosticInfo, location); - } - } - useSiteDiagnosticsBuilder.Free(); - } - } } /// 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 3db4e012a84cd..41043aacefac0 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -686,16 +686,17 @@ - + - + diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index ddefa3c2ab738..1fe44dbcf48ab 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -2147,8 +2147,12 @@ public BoundAwaitableInfo(SyntaxNode syntax, BoundAwaitableValuePlaceholder? awa 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; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index ac668411c2d52..6a532a67902d4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -372,7 +372,7 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol c // The diagnostics that would be produced here will already have been captured and returned. // PROTOTYPE: handle the runtime case - var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _getAwaiterGetResultCall!, runtimeAsyncAwaitCall: out _, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded); + var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _getAwaiterGetResultCall!, runtimeAsyncAwaitMethod: out _, _userMainReturnTypeSyntax, BindingDiagnosticBag.Discarded); Debug.Assert( ReturnType.IsVoidType() || @@ -491,7 +491,7 @@ internal override BoundBlock CreateBody(BindingDiagnosticBag diagnostics) var initializeCall = CreateParameterlessCall(syntax, scriptLocal, receiverIsSubjectToCloning: ThreeState.False, initializer); BoundExpression getAwaiterGetResultCall; // PROTOTYPE: handle the runtime case - if (!binder.GetAwaitableExpressionInfo(initializeCall, out getAwaiterGetResultCall, runtimeAsyncAwaitCall: out _, syntax, diagnostics)) + 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 4d2b1b0395451..9301c1b6853bb 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -267,6 +267,21 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter 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 { @@ -401,7 +416,6 @@ public void VoidReturningAsync() { var source = @" using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -436,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] @@ -7824,8 +7961,9 @@ .maxstack 1 """); } - [Fact] - public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync() + [Theory] + [CombinatorialData] + public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync(bool withNonCoreLibSources) { var source = """ using System.Threading.Tasks; @@ -7833,7 +7971,7 @@ public void RuntimeAsync_CompilerFeatureFlag_EnabledWithoutRuntimeAsync() await Task.CompletedTask; """; - var comp = CreateCompilation(source, 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("", """ From 20273bbe7b93c475af9c8c3806937974872acc02 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Wed, 30 Apr 2025 12:41:23 -0700 Subject: [PATCH 13/15] More corlib test failures --- .../Test/Symbol/Symbols/CorLibrary/CorTypes.cs | 12 +++++++----- .../Test/Symbol/Symbols/MissingSpecialMember.cs | 2 +- .../Symbol/SymbolsTests/CorLibrary/CorTypes.vb | 17 ++++++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs index e9af58aebfb5e..12b502c04f786 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/CorTypes.cs @@ -67,11 +67,12 @@ public void PresentCorLib() 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 (knownMissingSpecialTypes.Contains((SpecialType)i)) + if (knownMissingSpecialTypes.Contains(specialType)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); @@ -84,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 (knownMissingInternalSpecialTypes.Contains((InternalSpecialType)i)) + if (knownMissingInternalSpecialTypes.Contains(internalSpecialType)) { // not present on dotnet core 3.1 Assert.Equal(TypeKind.Error, t.TypeKind); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 75db88124ced1..28013feccafbf 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -923,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] 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 From 5a789ef085efe706ab0955b261313f017f3db945 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Wed, 30 Apr 2025 16:33:05 -0700 Subject: [PATCH 14/15] PR Feedback --- src/Compilers/CSharp/Portable/Binder/Binder_Await.cs | 10 +++++----- src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml | 2 +- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 9 +++++---- src/Compilers/Core/Portable/ExtendedSpecialType.cs | 1 + 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs index 99bb6b763b4f5..1d738e6b3517c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs @@ -309,7 +309,7 @@ bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runt { var exprOriginalType = expression.Type!.OriginalDefinition; SpecialMember awaitCall; - TypeWithAnnotations? maybeResultType = null; + TypeWithAnnotations resultType = default; if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTask; @@ -317,7 +317,7 @@ bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runt else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitTaskT_T; - maybeResultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + resultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask, diagnostics, expression.Syntax))) { @@ -326,7 +326,7 @@ bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runt else if (ReferenceEquals(exprOriginalType, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T, diagnostics, expression.Syntax))) { awaitCall = SpecialMember.System_Runtime_CompilerServices_AsyncHelpers__AwaitValueTaskT_T; - maybeResultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + resultType = ((NamedTypeSymbol)expression.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; } else { @@ -341,9 +341,9 @@ bool tryGetRuntimeAwaitHelper(BoundExpression expression, out MethodSymbol? runt return false; } - Debug.Assert((runtimeAwaitHelper is { Arity: 1 } && maybeResultType is { }) || runtimeAwaitHelper.TypeParameters.Length == 0); + Debug.Assert(runtimeAwaitHelper.Arity == (resultType.HasType ? 1 : 0)); - if (maybeResultType is { } resultType) + if (resultType.HasType) { runtimeAwaitHelper = runtimeAwaitHelper.Construct([resultType]); ConstraintsHelper.CheckConstraints( diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 41043aacefac0..a0e40e5b24e85 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -693,7 +693,7 @@ - diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index bbbbcd84b4a3c..00a6a79357d90 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -331,10 +331,11 @@ internal bool IsRuntimeAsyncEnabledIn(Symbol? symbol) } var methodReturn = method.ReturnType.OriginalDefinition; - if (!ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task)) - && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_Task_T)) - && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask)) - && !ReferenceEquals(methodReturn, GetSpecialType(InternalSpecialType.System_Threading_Tasks_ValueTask_T))) + 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; } diff --git a/src/Compilers/Core/Portable/ExtendedSpecialType.cs b/src/Compilers/Core/Portable/ExtendedSpecialType.cs index a5b5eb8212982..b79e111acede9 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; From 3bb71897e57c1e16ac5d1297a7f11d7b8c883253 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 1 May 2025 10:39:29 -0700 Subject: [PATCH 15/15] Hardcode which value is returned for overlapping enum values in `ExtendedSpecialType.ToString`. --- src/Compilers/Core/Portable/ExtendedSpecialType.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Compilers/Core/Portable/ExtendedSpecialType.cs b/src/Compilers/Core/Portable/ExtendedSpecialType.cs index b79e111acede9..3cda91d247483 100644 --- a/src/Compilers/Core/Portable/ExtendedSpecialType.cs +++ b/src/Compilers/Core/Portable/ExtendedSpecialType.cs @@ -57,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) @@ -64,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(); }