From 78a89b7c9f87352d2c09904813b82c8b1769d3fe Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 7 Jun 2021 14:55:03 -0700 Subject: [PATCH 01/24] Allow AsyncMethodBuilder on method --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/MessageID.cs | 2 + .../AsyncMethodBuilderMemberCollection.cs | 78 +- .../Symbols/MethodSymbolExtensions.cs | 27 + .../SourceMethodSymbolWithAttributes.cs | 4 + .../Portable/Symbols/TypeSymbolExtensions.cs | 2 +- .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../CodeGenAsyncMethodBuilderOverrideTests.cs | 2113 +++++++++++++++++ .../BindingAsyncTasklikeMoreTests.cs | 180 ++ .../Semantic/Semantics/RecordStructTests.cs | 1 - 22 files changed, 2458 insertions(+), 17 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 6147ee61e336..b010a583003c 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6585,6 +6585,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ with on anonymous types + + async method builder override + positional fields in records diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index aa544faa423d..1df211f71067 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -225,6 +225,7 @@ internal enum MessageID IDS_FeatureLambdaAttributes = MessageBase + 12800, IDS_FeatureWithOnAnonymousTypes = MessageBase + 12801, IDS_FeatureExtendedPropertyPatterns = MessageBase + 12802, + IDS_AsyncMethodBuilderOverride = MessageBase + 12803, } // Message IDs may refer to strings that need to be localized. @@ -342,6 +343,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureInferredDelegateType: // semantic check case MessageID.IDS_FeatureLambdaAttributes: // semantic check case MessageID.IDS_FeatureExtendedPropertyPatterns: + case MessageID.IDS_AsyncMethodBuilderOverride: // semantic check return LanguageVersion.Preview; // C# 9.0 features. diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index f2d72b5841fd..fe297f915463 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -159,7 +159,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, out createBuilderMethod); if ((object)createBuilderMethod == null) { - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } return TryCreate( @@ -189,11 +189,32 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); - if ((object)builderType != null) + if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) + { + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false); + if ((object)initialBuilderType != null) + { + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) + { + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + } + } + else + { + builderType = null; + } + } + else { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - createBuilderMethod = GetCustomCreateMethod(F, builderType); + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); + if ((object)builderType != null) + { + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + createBuilderMethod = GetCustomCreateMethod(F, builderType); + } } } else @@ -217,7 +238,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, (object)createBuilderMethod == null || (object)taskProperty == null) { - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } return TryCreate( @@ -257,12 +278,35 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); - if ((object)builderType != null) + if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) { - builderType = builderType.ConstructedFrom.Construct(resultType); - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - createBuilderMethod = GetCustomCreateMethod(F, builderType); + builderArgument = methodLevelBuilder; + var initialBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); + if ((object)initialBuilderType != null) + { + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) + { + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + } + } + else + { + builderType = null; + } + } + else + { + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); + if ((object)builderType != null) + { + builderType = builderType.ConstructedFrom.Construct(resultType); + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + createBuilderMethod = GetCustomCreateMethod(F, builderType); + } } } else @@ -287,7 +331,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, (object)taskProperty == null || (object)createBuilderMethod == null) { - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } return TryCreate( @@ -376,7 +420,7 @@ private static bool TryCreate( return true; } - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } @@ -429,9 +473,12 @@ private static bool TryGetBuilderMember( return true; } + // For method-level builders, we allow the `Create` method to return a different type. + // We'll just use that type as the final builder type. private static MethodSymbol GetCustomCreateMethod( SyntheticBoundNodeFactory F, - NamedTypeSymbol builderType) + NamedTypeSymbol builderType, + bool forOverride = false) { // The Create method's return type is expected to be builderType. // The WellKnownMembers routines aren't able to enforce that, which is why this method exists. @@ -448,7 +495,8 @@ private static MethodSymbol GetCustomCreateMethod( method.IsStatic && method.ParameterCount == 0 && !method.IsGenericMethod && - method.ReturnType.Equals(builderType, TypeCompareKind.AllIgnoreOptions)) + method.RefKind == RefKind.None && + (forOverride || method.ReturnType.Equals(builderType, TypeCompareKind.AllIgnoreOptions))) { return method; } diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index 6ff5ef7702a8..c2a8f980d422 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -190,6 +191,32 @@ public static bool IsAsyncReturningIAsyncEnumerator(this MethodSymbol method, CS && method.ReturnType.IsIAsyncEnumeratorType(compilation); } +#nullable enable + /// + /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". + /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. + /// + internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) + { + Debug.Assert(method is not null); + + // Find the AsyncMethodBuilder attribute. + foreach (var attr in method.GetAttributes()) + { + if (attr.IsTargetAttribute(method, AttributeDescription.AsyncMethodBuilderAttribute) + && attr.CommonConstructorArguments.Length == 1 + && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) + { + builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; + return true; + } + } + + builderArgument = null; + return false; + } +#nullable disable + internal static CSharpSyntaxNode ExtractReturnTypeSyntax(this MethodSymbol method) { if (method is SynthesizedSimpleProgramEntryPointSymbol synthesized) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 503c3ffdaf5e..993ea3d60454 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1055,6 +1055,10 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, errorLocation); hasErrors = true; } + else if (this.HasMethodLevelBuilder(out _)) + { + hasErrors = MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); + } for (NamedTypeSymbol curr = this.ContainingType; (object)curr != null; curr = curr.ContainingType) { diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index a875bfa14eed..f9a522417a58 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1638,7 +1638,7 @@ internal static bool IsCustomTaskType(this NamedTypeSymbol type, [NotNullWhen(tr var arity = type.Arity; if (arity < 2) { - // Find the AsyncBuilder attribute. + // Find the AsyncMethodBuilder attribute. foreach (var attr in type.GetAttributes()) { if (attr.IsTargetAttribute(type, AttributeDescription.AsyncMethodBuilderAttribute) diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 453ac798fba6..743394bc1fa2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -992,6 +992,11 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns kovariantní návratové hodnoty diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 3a86d8bb8b03..5032380a222b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -992,6 +992,11 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns Covariante Rückgaben diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index c38190c0cec4..dff9355bd6cb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -992,6 +992,11 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns valores devueltos de covariante diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 3ee74728907d..1f31f38e50fc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -992,6 +992,11 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns retours covariants diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 3bb90a8d7d6a..8734aa9224ee 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -992,6 +992,11 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns tipi restituiti covarianti diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 728c746e3e6d..7227eb39fbb6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -992,6 +992,11 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns covariant の戻り値 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d977c150798e..2264a13b1007 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -992,6 +992,11 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns 공변(covariant) 반환 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index f5c1b09465c8..79ca3c5ee7fa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -992,6 +992,11 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns zwroty kowariantne diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 6ae87856a546..71ea2d6d6483 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -992,6 +992,11 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns retornos de covariante diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 0c91df221933..d569146097b1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -992,6 +992,11 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns ковариантные возвращаемые значения diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index df01876756de..4dc65e532d17 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -992,6 +992,11 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns birlikte değişken dönüşler diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index ef6840911fba..273d8ae05eeb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -992,6 +992,11 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns 协变返回 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 82fefad7c035..7e0b7c4f729d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -992,6 +992,11 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. + + async method builder override + async method builder override + + covariant returns Covariant 傳回 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs new file mode 100644 index 000000000000..461c1b22fef1 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -0,0 +1,2113 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen +{ + // Broad scenarios covered: + // - AsyncMethodBuilderAttribute can be placed on an async method, which overrides the builder used + // - The type used in an override needs only have a static Create() method which gives us the actual builder type + public class CodeGenAsyncMethodBuilderOverrideTests : EmitMetadataTestBase + { + private const string AsyncMethodBuilderAttribute = + "namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; + + private static string AsyncBuilderCode(string builderTypeName, string tasklikeTypeName, string? genericTypeParameter = null, bool isStruct = false) + { + string ofT = genericTypeParameter == null ? "" : "<" + genericTypeParameter + ">"; + + return $@" +public {(isStruct ? "struct" : "class")} {builderTypeName}{ofT} +{{ + public static {builderTypeName}{ofT} Create() => new {builderTypeName}{ofT}(new {tasklikeTypeName}{ofT}()); + private {tasklikeTypeName}{ofT} _task; + private {builderTypeName}({tasklikeTypeName}{ofT} task) {{ _task = task; }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(System.Exception e) {{ }} + public void SetResult({(genericTypeParameter == null ? "" : genericTypeParameter + " result")}) {{ {(genericTypeParameter == null ? "" : "_task._result = result;")} }} + 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 {tasklikeTypeName}{ofT} Task => _task; +}} +"; + } + + private static string AsyncBuilderFactoryCode(string builderTypeName, string tasklikeTypeName, string? genericTypeParameter = null, bool isStruct = false) + { + string ofT = genericTypeParameter == null ? "" : "<" + genericTypeParameter + ">"; + + return $@" +public {(isStruct ? "struct" : "class")} {builderTypeName}Factory{ofT} +{{ + public static {builderTypeName}{ofT} Create() => new {builderTypeName}{ofT}(new {tasklikeTypeName}{ofT}()); +}} + +public {(isStruct ? "struct" : "class")} {builderTypeName}{ofT} +{{ + private {tasklikeTypeName}{ofT} _task; + internal {builderTypeName}({tasklikeTypeName}{ofT} task) {{ _task = task; }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult({(genericTypeParameter == null ? "" : genericTypeParameter + " result")}) {{ {(genericTypeParameter == null ? "" : "_task._result = result;")} }} + 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 {tasklikeTypeName}{ofT} Task => _task; +}} +"; + } + + private static string AwaitableTypeCode(string taskLikeName, string? genericTypeParameter = null, bool isStruct = false) + { + if (genericTypeParameter == null) + { + return $@" +public {(isStruct ? "struct" : "class")} {taskLikeName} +{{ + internal Awaiter GetAwaiter() => new Awaiter(); + internal class Awaiter : INotifyCompletion + {{ + public void OnCompleted(Action a) {{ }} + internal bool IsCompleted => true; + internal void GetResult() {{ }} + }} +}}"; + } + else + { + string ofT = "<" + genericTypeParameter + ">"; + return $@" +public {(isStruct ? "struct" : "class")} {taskLikeName}{ofT} +{{ + internal {genericTypeParameter} _result; + public {genericTypeParameter} Result => _result; + internal Awaiter GetAwaiter() => new Awaiter(this); + internal class Awaiter : INotifyCompletion + {{ + private readonly {taskLikeName}{ofT} _task; + internal Awaiter({taskLikeName}{ofT} task) {{ _task = task; }} + public void OnCompleted(Action a) {{ }} + internal bool IsCompleted => true; + internal {genericTypeParameter} GetResult() => _task.Result; + }} +}} +"; + } + } + + [Theory] + [InlineData("typeof(MyTaskMethodBuilder)")] + [InlineData("typeof(object)")] + [InlineData("null")] + public void BuilderOnMethod_DummyBuilderOnType(string dummyBuilder) + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder({dummyBuilder})] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder({dummyBuilder})] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + compilation.VerifyDiagnostics( + // (11,25): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "F").WithArguments("async method builder override").WithLocation(11, 25), + // (14,28): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "G").WithArguments("async method builder override").WithLocation(14, 28), + // (17,37): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("async method builder override").WithLocation(17, 37) + ); + + compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); + verifier.VerifyDiagnostics(); + var testData = verifier.TestData; + var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; + Assert.True(method.IsAsync); + Assert.True(method.IsAsyncReturningTask(compilation)); + method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; + Assert.True(method.IsAsync); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); + verifier.VerifyIL("C.F()", @" +{ + // Code size 49 (0x31) + .maxstack 2 + .locals init (C.d__0 V_0) + IL_0000: newobj ""C.d__0..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" + IL_000c: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0011: ldloc.0 + IL_0012: ldc.i4.m1 + IL_0013: stfld ""int C.d__0.<>1__state"" + IL_0018: ldloc.0 + IL_0019: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_001e: ldloca.s V_0 + IL_0020: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_0025: ldloc.0 + IL_0026: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_002b: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0030: ret +} +"); + verifier.VerifyIL("C.G(T)", @" +{ + // Code size 56 (0x38) + .maxstack 2 + .locals init (C.d__1 V_0) + IL_0000: newobj ""C.d__1..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" + IL_000c: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0011: ldloc.0 + IL_0012: ldarg.0 + IL_0013: stfld ""T C.d__1.t"" + IL_0018: ldloc.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__1.<>1__state"" + IL_001f: ldloc.0 + IL_0020: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0025: ldloca.s V_0 + IL_0027: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" + IL_002c: ldloc.0 + IL_002d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0032: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0037: ret +} +"); + } + + [Fact] + public void BuilderOnMethod_NoBuilderOnType() + { + // Note: although we don't use the builder from the return type, we still require + // the return type to have the attribute. + // One reason is that if the return type is not "task-like" then implicit returns are disallowed. + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +// no attribute +{AwaitableTypeCode("MyTask")} + +// no attribute +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyEmitDiagnostics( + // (9,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(9, 25), + // (9,25): error CS0161: 'C.F()': not all code paths return a value + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(9, 25), + // (12,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(12, 28), + // (15,37): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(15, 37) + ); + } + + [Theory] + [InlineData("typeof(MyTaskMethodBuilder)")] + [InlineData("typeof(object)")] + [InlineData("null")] + public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuilder) + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await M()); + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] +static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] +static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] +static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} + +[AsyncMethodBuilder({dummyBuilder})] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder({dummyBuilder})] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + source = source.Replace("DUMMY_BUILDER", dummyBuilder); + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + compilation.VerifyDiagnostics( + // (9,21): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "F").WithArguments("async method builder override").WithLocation(9, 21), + // (12,24): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "G").WithArguments("async method builder override").WithLocation(12, 24), + // (15,26): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("async method builder override").WithLocation(15, 26) + ); + + compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_ErrorType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(Error))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(Error<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(Error<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,32): error CS0246: The type or namespace name 'Error' could not be found (are you missing a using directive or an assembly reference?) + // [AsyncMethodBuilder(typeof(Error))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error").WithArguments("Error").WithLocation(8, 32), + // (11,32): error CS0246: The type or namespace name 'Error<>' could not be found (are you missing a using directive or an assembly reference?) + // [AsyncMethodBuilder(typeof(Error<>))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error<>").WithArguments("Error<>").WithLocation(11, 32), + // (14,32): error CS0246: The type or namespace name 'Error<>' could not be found (are you missing a using directive or an assembly reference?) + // [AsyncMethodBuilder(typeof(Error<>))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Error<>").WithArguments("Error<>").WithLocation(14, 32) + ); + } + + [Fact] + public void BuilderOnMethod_WrongArity() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(9, 29), + // (12,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(12, 38), + // (15,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(15, 41) + ); + } + + [Fact] + public void BuilderOnMethod_WrongAccessibility() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +[AsyncMethodBuilder(typeof(B1))] public class T1 {{ }} +[AsyncMethodBuilder(typeof(B2))] public class T2 {{ }} +[AsyncMethodBuilder(typeof(B3))] internal class T3 {{ }} +[AsyncMethodBuilder(typeof(B4))] internal class T4 {{ }} + +{AsyncBuilderCode("B1", "T1").Replace("public class B1", "public class B1")} +{AsyncBuilderCode("B2", "T2").Replace("public class B2", "internal class B2")} +{AsyncBuilderCode("B3", "T3").Replace("public class B3", "public class B3").Replace("public T3 Task =>", "internal T3 Task =>")} +{AsyncBuilderCode("B4", "T4").Replace("public class B4", "internal class B4")} + +class Program +{{ + async T1 f1() => await Task.Delay(1); + async T2 f2() => await Task.Delay(2); + async T3 f3() => await Task.Delay(3); + async T4 f4() => await Task.Delay(4); +}} + +{AsyncMethodBuilderAttribute} +"; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (75,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // async T2 f2() => await Task.Delay(2); + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(2)").WithLocation(75, 19), + // (76,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // async T3 f3() => await Task.Delay(3); + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(3)").WithLocation(76, 19) + ); + } + + [Fact] + public void BuilderFactoryOnMethod() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3", symbolValidator: verifyMembers); + verifier.VerifyDiagnostics(); + var testData = verifier.TestData; + var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; + Assert.True(method.IsAsync); + Assert.True(method.IsAsyncReturningTask(compilation)); + method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; + Assert.True(method.IsAsync); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); + + // The initial builder type is used for Create() invocation + verifier.VerifyIL("C.F()", @" +{ + // Code size 49 (0x31) + .maxstack 2 + .locals init (C.d__0 V_0) + IL_0000: newobj ""C.d__0..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" + IL_000c: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0011: ldloc.0 + IL_0012: ldc.i4.m1 + IL_0013: stfld ""int C.d__0.<>1__state"" + IL_0018: ldloc.0 + IL_0019: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_001e: ldloca.s V_0 + IL_0020: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_0025: ldloc.0 + IL_0026: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_002b: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0030: ret +}"); + // The final builder type is used for the rest + verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 166 (0xa6) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_000c + IL_000a: br.s IL_000e + IL_000c: br.s IL_0053 + IL_000e: nop + IL_000f: ldstr ""F "" + IL_0014: call ""void System.Console.Write(string)"" + IL_0019: nop + IL_001a: ldc.i4.0 + IL_001b: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" + IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0025: stloc.1 + IL_0026: ldloca.s V_1 + IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_002d: brtrue.s IL_006f + IL_002f: ldarg.0 + IL_0030: ldc.i4.0 + IL_0031: dup + IL_0032: stloc.0 + IL_0033: stfld ""int C.d__0.<>1__state"" + IL_0038: ldarg.0 + IL_0039: ldloc.1 + IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_003f: ldarg.0 + IL_0040: stloc.2 + IL_0041: ldarg.0 + IL_0042: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0047: ldloca.s V_1 + IL_0049: ldloca.s V_2 + IL_004b: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_0050: nop + IL_0051: leave.s IL_00a5 + IL_0053: ldarg.0 + IL_0054: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0059: stloc.1 + IL_005a: ldarg.0 + IL_005b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0060: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0066: ldarg.0 + IL_0067: ldc.i4.m1 + IL_0068: dup + IL_0069: stloc.0 + IL_006a: stfld ""int C.d__0.<>1__state"" + IL_006f: ldloca.s V_1 + IL_0071: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0076: nop + IL_0077: leave.s IL_0091 + } + catch System.Exception + { + IL_0079: stloc.3 + IL_007a: ldarg.0 + IL_007b: ldc.i4.s -2 + IL_007d: stfld ""int C.d__0.<>1__state"" + IL_0082: ldarg.0 + IL_0083: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0088: ldloc.3 + IL_0089: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" + IL_008e: nop + IL_008f: leave.s IL_00a5 + } + IL_0091: ldarg.0 + IL_0092: ldc.i4.s -2 + IL_0094: stfld ""int C.d__0.<>1__state"" + IL_0099: ldarg.0 + IL_009a: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_009f: callvirt ""void MyTaskMethodBuilder.SetResult()"" + IL_00a4: nop + IL_00a5: ret +} +"); + + // The initial builder type is used for Create() invocation + verifier.VerifyIL("C.G(T)", @" +{ + // Code size 56 (0x38) + .maxstack 2 + .locals init (C.d__1 V_0) + IL_0000: newobj ""C.d__1..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" + IL_000c: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0011: ldloc.0 + IL_0012: ldarg.0 + IL_0013: stfld ""T C.d__1.t"" + IL_0018: ldloc.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__1.<>1__state"" + IL_001f: ldloc.0 + IL_0020: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0025: ldloca.s V_0 + IL_0027: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" + IL_002c: ldloc.0 + IL_002d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0032: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0037: ret +}"); + + // The final builder type is used for the rest + verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 176 (0xb0) + .maxstack 3 + .locals init (int V_0, + T V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + C.d__1 V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__1.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_000c + IL_000a: br.s IL_000e + IL_000c: br.s IL_0053 + IL_000e: nop + IL_000f: ldstr ""G "" + IL_0014: call ""void System.Console.Write(string)"" + IL_0019: nop + IL_001a: ldc.i4.0 + IL_001b: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" + IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0025: stloc.2 + IL_0026: ldloca.s V_2 + IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_002d: brtrue.s IL_006f + IL_002f: ldarg.0 + IL_0030: ldc.i4.0 + IL_0031: dup + IL_0032: stloc.0 + IL_0033: stfld ""int C.d__1.<>1__state"" + IL_0038: ldarg.0 + IL_0039: ldloc.2 + IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_003f: ldarg.0 + IL_0040: stloc.3 + IL_0041: ldarg.0 + IL_0042: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0047: ldloca.s V_2 + IL_0049: ldloca.s V_3 + IL_004b: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" + IL_0050: nop + IL_0051: leave.s IL_00af + IL_0053: ldarg.0 + IL_0054: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0059: stloc.2 + IL_005a: ldarg.0 + IL_005b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0060: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0066: ldarg.0 + IL_0067: ldc.i4.m1 + IL_0068: dup + IL_0069: stloc.0 + IL_006a: stfld ""int C.d__1.<>1__state"" + IL_006f: ldloca.s V_2 + IL_0071: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0076: nop + IL_0077: ldarg.0 + IL_0078: ldfld ""T C.d__1.t"" + IL_007d: stloc.1 + IL_007e: leave.s IL_009a + } + catch System.Exception + { + IL_0080: stloc.s V_4 + IL_0082: ldarg.0 + IL_0083: ldc.i4.s -2 + IL_0085: stfld ""int C.d__1.<>1__state"" + IL_008a: ldarg.0 + IL_008b: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0090: ldloc.s V_4 + IL_0092: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" + IL_0097: nop + IL_0098: leave.s IL_00af + } + IL_009a: ldarg.0 + IL_009b: ldc.i4.s -2 + IL_009d: stfld ""int C.d__1.<>1__state"" + IL_00a2: ldarg.0 + IL_00a3: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_00a8: ldloc.1 + IL_00a9: callvirt ""void MyTaskMethodBuilder.SetResult(T)"" + IL_00ae: nop + IL_00af: ret +} +"); + + void verifyMembers(ModuleSymbol module) + { + var fType = (NamedTypeSymbol)module.GlobalNamespace.GetMember("C.d__0"); + AssertEx.SetEqual(new[] { + "MyTaskMethodBuilder C.d__0.<>t__builder", + "C.d__0..ctor()", + "void C.d__0.MoveNext()", + "void C.d__0.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", + "System.Int32 C.d__0.<>1__state" }, + fType.GetMembersUnordered().ToTestDisplayStrings()); + + var gType = (NamedTypeSymbol)module.GlobalNamespace.GetMember("C.d__1"); + AssertEx.SetEqual(new[] { + "void C.d__1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", + "MyTaskMethodBuilder C.d__1.<>t__builder", + "T C.d__1.t", + "C.d__1..ctor()", + "void C.d__1.MoveNext()", + "System.Int32 C.d__1.<>1__state"}, + gType.GetMembersUnordered().ToTestDisplayStrings()); + } + } + + [Fact] + public void BuilderFactoryOnMethod_OnLambda() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; + +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; + +Console.WriteLine(await m()); +return; + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", isStruct: true)} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task", "public object Task")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS8204: For type 'MyTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'object'. + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "MyTask", "object").WithLocation(8, 29), + // (11,38): error CS8204: For type 'MyTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'object'. + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "MyTask", "object").WithLocation(11, 38), + // (14,34): error CS8204: For type 'MyTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'object'. + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "MyTask", "object").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateMissing() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") + .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") + .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Theory] + [InlineData("internal")] + [InlineData("private")] + public void BuilderFactoryOnMethod_CreateNotPublic(string accessibility) + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateNotStatic() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateHasParamaeter() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateIsGeneric() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateHasRefReturn() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") + .Replace( + "public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", + "public static ref MyTaskMethodBuilder Create() => throw null;")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") + .Replace( + "public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", + "public static ref MyTaskMethodBuilder Create() => throw null;")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_BuilderFactoryIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(8, 29), + // (11,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(11, 38), + // (14,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_CreateIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_TwoMethodLevelAttributes() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(null)] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(null)] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(null)] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} + +namespace System.Runtime.CompilerServices +{{ + [System.AttributeUsage(System.AttributeTargets.All, AllowMultiple=true)] + class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilderAttribute(System.Type t) {{ }} }} +}} +"; + // The first attribute is used + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderFactoryOnMethod_TwoMethodLevelAttributes_ReverseOrder() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} + +namespace System.Runtime.CompilerServices +{{ + [System.AttributeUsage(System.AttributeTargets.All, AllowMultiple=true)] + class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilderAttribute(System.Type t) {{ }} }} +}} +"; + // The first attribute is used + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (10,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(10, 29), + // (14,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(14, 38), + // (18,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(18, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_WrongArity() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(9, 29), + // (12,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(12, 38), + // (15,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(15, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_BoundGeneric_TypeParameter() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask G(T t) {{ await Task.Delay(0); throw null; }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,25): error CS0416: 'MyTaskMethodBuilderFactory': an attribute argument cannot use type parameters + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(MyTaskMethodBuilderFactory)").WithArguments("MyTaskMethodBuilderFactory").WithLocation(8, 25) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_BoundGeneric_SpecificType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask M() {{ await Task.Delay(0); throw null; }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask M() { await Task.Delay(0); throw null; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await Task.Delay(0); throw null; }").WithLocation(9, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_FinalBuilderTypeIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderFactoryOnMethod_TaskPropertyIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task =>", "internal MyTask Task =>")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_TaskPropertyIsStatic() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_TaskPropertyIsField() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task = null;")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Task").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_SetExceptionIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException", "internal void SetException")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_SetExceptionReturnsObject() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") + .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_SetExceptionLacksParameter() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException(Exception e)", "public void SetException()")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(Exception e)", "public void SetException()")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "SetException").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_SetResultIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetResult", "internal void SetResult")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetResult' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "SetResult").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetResult' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "SetResult").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetResult' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "SetResult").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_AwaitOnCompletedIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitOnCompleted' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "AwaitOnCompleted").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitOnCompleted' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "AwaitOnCompleted").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitOnCompleted' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "AwaitOnCompleted").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_AwaitUnsafeOnCompletedIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "AwaitUnsafeOnCompleted").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "AwaitUnsafeOnCompleted").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "AwaitUnsafeOnCompleted").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_StartIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void Start", "internal void Start")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Start' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Start").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Start' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Start").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Start' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Start").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_SetStateMachineIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetStateMachine", "internal void SetStateMachine")} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetStateMachine' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "SetStateMachine").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetStateMachine' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "SetStateMachine").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetStateMachine' + // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "SetStateMachine").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_AsyncMethodReturnsTask() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async Task F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async Task G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + public static async Task M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +public class MyTaskMethodBuilderFactory +{{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); +}} + +public class MyTaskMethodBuilder +{{ + internal MyTaskMethodBuilder() {{ }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult() {{ }} + 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 Task Task => System.Threading.Tasks.Task.CompletedTask; +}} + +public class MyTaskMethodBuilderFactory +{{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); +}} + +public class MyTaskMethodBuilder +{{ + private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); + internal MyTaskMethodBuilder() {{ }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult(T result) {{ _taskCompletionSource.SetResult(result); }} + 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 Task Task => _taskCompletionSource.Task; +}} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderFactoryOnMethod_AsyncMethodReturnsValueTask() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async ValueTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async ValueTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + public static async ValueTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +public class MyTaskMethodBuilderFactory +{{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); +}} + +public class MyTaskMethodBuilder +{{ + internal MyTaskMethodBuilder() {{ }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult() {{ }} + 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 ValueTask Task => new ValueTask(System.Threading.Tasks.Task.CompletedTask); +}} + +public class MyTaskMethodBuilderFactory +{{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); +}} + +public class MyTaskMethodBuilder +{{ + private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); + internal MyTaskMethodBuilder() {{ }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult(T result) {{ _taskCompletionSource.SetResult(result); }} + 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 ValueTask Task => new ValueTask(_taskCompletionSource.Task); +}} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (10,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(10, 6), + // (13,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(13, 6), + // (16,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(16, 6) + ); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilder() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +[AsyncMethodBuilder(null)] public class T1 {{ }} +[AsyncMethodBuilder(null)] public class T2 {{ }} +[AsyncMethodBuilder(null)] internal class T3 {{ }} +[AsyncMethodBuilder(null)] internal class T4 {{ }} + +{AsyncBuilderFactoryCode("B1", "T1")} + +{AsyncBuilderFactoryCode("B2", "T2") + .Replace("public class B2", "internal class B2") + .Replace("internal class B2Factory", "public class B2Factory") + .Replace("public static B2 Create()", "internal static B2 Create()")} + +{AsyncBuilderFactoryCode("B3", "T3") + .Replace("public T3 Task =>", "internal T3 Task =>")} + +{AsyncBuilderFactoryCode("B4", "T4") + .Replace("public class B4", "internal class B4") + .Replace("internal class B4Factory", "public class B4Factory") + .Replace("public static B4 Create()", "internal static B4 Create()")} + +class Program +{{ + [AsyncMethodBuilder(typeof(B1Factory))] + async T1 f1() => await Task.Delay(1); + + [AsyncMethodBuilder(typeof(B2Factory))] + async T2 f2() => await Task.Delay(2); + + [AsyncMethodBuilder(typeof(B3Factory))] + async T3 f3() => await Task.Delay(3); + + [AsyncMethodBuilder(typeof(B4Factory))] + async T4 f4() => await Task.Delay(4); +}} + +{AsyncMethodBuilderAttribute} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyEmitDiagnostics( + // (97,19): error CS0656: Missing compiler required member 'B2Factory.Create' + // async T2 f2() => await Task.Delay(2); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(2)").WithArguments("B2Factory", "Create").WithLocation(97, 19), + // (100,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // async T3 f3() => await Task.Delay(3); + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(3)").WithLocation(100, 19), + // (103,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // async T4 f4() => await Task.Delay(4); + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(4)").WithLocation(103, 19) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_InternalReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +[AsyncMethodBuilder(null)] internal class MyTaskType {{ }} + +// Make the builder factory and the builder internal as well +{AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskTypeBuilderFactory))] + async MyTaskType M() => await Task.Delay(4); +}} + +{AsyncMethodBuilderAttribute} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyEmitDiagnostics(); + } + + // PROTOTYPE confirm with LDM how much validation we should do on the builder type of the return type which is unused + // PROTOTYPE confirm with LDM that the factory indirection should only apply to overrides + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 58ea912c7c82..83b44e34e8f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -162,6 +162,186 @@ .locals init (C.d__1 V_0) }"); } + [Fact] + public void AsyncMethod_CreateHasRefReturn() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{ + static async MyTask F() { await Task.Delay(0); } + static async MyTask G(T t) { await Task.Delay(0); return t; } + static async MyTask M() { await F(); return await G(3); } +} +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] +struct MyTask +{ + internal Awaiter GetAwaiter() => new Awaiter(); + internal class Awaiter : INotifyCompletion + { + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal void GetResult() { } + } +} +[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] +struct MyTask +{ + internal T _result; + public T Result => _result; + internal Awaiter GetAwaiter() => new Awaiter(this); + internal class Awaiter : INotifyCompletion + { + private readonly MyTask _task; + internal Awaiter(MyTask task) { _task = task; } + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal T GetResult() => _task.Result; + } +} +struct MyTaskMethodBuilder +{ + private MyTask _task; + public static ref MyTaskMethodBuilder Create() => throw null; + internal MyTaskMethodBuilder(MyTask task) { _task = task; } + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } + public void SetException(Exception e) { } + public void SetResult() { } + 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 MyTask Task => _task; +} +struct MyTaskMethodBuilder +{ + private MyTask _task; + public static ref MyTaskMethodBuilder Create() => throw null; + internal MyTaskMethodBuilder(MyTask task) { _task = task; } + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } + public void SetException(Exception e) { } + public void SetResult(T t) { _task._result = t; } + 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 MyTask Task => _task; +} + +namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } +"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyEmitDiagnostics( + // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' + // static async MyTask F() { await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(6, 29), + // (7,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' + // static async MyTask G(T t) { await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(7, 38), + // (8,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' + // static async MyTask M() { await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 34) + ); + } + + [Fact] + public void AsyncMethod_BuilderFactoryDisallowed() + { + // Only method-level builder overrides allow having Create() return a different builder + var source = +@"using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{ + static async MyTask F() { await Task.Delay(0); } + static async MyTask G(T t) { await Task.Delay(0); return t; } + static async MyTask M() { await F(); return await G(3); } +} +[AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] +struct MyTask +{ + internal Awaiter GetAwaiter() => new Awaiter(); + internal class Awaiter : INotifyCompletion + { + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal void GetResult() { } + } +} +[AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] +struct MyTask +{ + internal T _result; + public T Result => _result; + internal Awaiter GetAwaiter() => new Awaiter(this); + internal class Awaiter : INotifyCompletion + { + private readonly MyTask _task; + internal Awaiter(MyTask task) { _task = task; } + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal T GetResult() => _task.Result; + } +} +struct MyTaskMethodBuilderFactory +{ + public static MyTaskMethodBuilder Create() => throw null; +} +struct MyTaskMethodBuilder +{ + private MyTask _task; + internal MyTaskMethodBuilder(MyTask task) { _task = task; } + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } + public void SetException(Exception e) { } + public void SetResult() { } + 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 MyTask Task => _task; +} +struct MyTaskMethodBuilderFactory +{ + public static MyTaskMethodBuilder Create() => throw null; +} +struct MyTaskMethodBuilder +{ + private MyTask _task; + internal MyTaskMethodBuilder(MyTask task) { _task = task; } + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } + public void SetException(Exception e) { } + public void SetResult(T t) { _task._result = t; } + 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 MyTask Task => _task; +} + +namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } +"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyEmitDiagnostics( + // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // static async MyTask F() { await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(6, 29), + // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(6, 29), + // (7,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // static async MyTask G(T t) { await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(7, 38), + // (7,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(7, 38), + // (8,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // static async MyTask M() { await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(8, 34), + // (8,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask M() { await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 34) + ); + } + [Fact] public void AsyncMethodBuilder_MissingMethods() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 4fe37305c5c5..3bfd14e649d1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -9742,7 +9742,6 @@ public static void M() var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreview); comp.VerifyEmitDiagnostics(expectedDiagnostics); - // TODO2 var expectedFlowGraph = @" Block[B0] - Entry Statements (0) From f084cb2d65a99c3812def59fbc29b99ca6a54967 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 15 Jun 2021 10:04:22 -0700 Subject: [PATCH 02/24] Allow returning a non-task-like type --- .../Portable/Binder/Binder_Expressions.cs | 3 +- .../Portable/Binder/Binder_Statements.cs | 25 ++- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../AsyncMethodBuilderMemberCollection.cs | 154 +++++++++--------- .../AsyncMethodToStateMachineRewriter.cs | 6 +- .../Symbols/MethodSymbolExtensions.cs | 16 ++ .../SourceMethodSymbolWithAttributes.cs | 19 ++- .../Portable/Symbols/TypeSymbolExtensions.cs | 11 -- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 152 ++++++++++------- 9 files changed, 233 insertions(+), 155 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index d09ed9112d04..3201e4f49816 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8597,7 +8597,8 @@ private bool ContainingMethodOrLambdaRequiresValue() return (object)containingMethod == null || !containingMethod.ReturnsVoid && - !containingMethod.IsAsyncReturningTask(this.Compilation); + !containingMethod.IsAsyncReturningTask(this.Compilation) && + !containingMethod.IsAsyncReturningTaskViaOverride(out _); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 233fcb3033ed..4eaa23fe3a4c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -623,7 +623,7 @@ BoundBlock runAnalysis(BoundBlock block, BindingDiagnosticBag blockDiagnostics) private bool ImplicitReturnIsOkay(MethodSymbol method) { - return method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(this.Compilation); + return method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(this.Compilation) || method.IsAsyncReturningTaskViaOverride(out _); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2650,12 +2650,24 @@ protected bool IsTaskReturningAsyncMethod() return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTask(this.Compilation); } + protected bool IsTaskReturningAsyncMethodViaOverride() + { + var symbol = this.ContainingMemberOrLambda; + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTaskViaOverride(out _); + } + protected bool IsGenericTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTask(this.Compilation); } + protected bool IsGenericTaskReturningAsyncMethodViaOverride() + { + var symbol = this.ContainingMemberOrLambda; + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTaskViaOverride(out _); + } + protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; @@ -2756,7 +2768,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti // on a lambda expression of unknown return type. if ((object)retType != null) { - if (retType.IsVoidType() || IsTaskReturningAsyncMethod()) + if (retType.IsVoidType() || IsTaskReturningAsyncMethod() || IsTaskReturningAsyncMethodViaOverride()) { if (arg != null) { @@ -2796,7 +2808,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti if (arg == null) { // Error case: non-void-returning or Task-returning method or lambda but just have "return;" - var requiredType = IsGenericTaskReturningAsyncMethod() + var requiredType = IsGenericTaskReturningAsyncMethod() || IsGenericTaskReturningAsyncMethodViaOverride() ? retType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single() : retType; @@ -2839,7 +2851,7 @@ internal BoundExpression CreateReturnConversion( { Debug.Assert(returnRefKind == RefKind.None); - if (!IsGenericTaskReturningAsyncMethod()) + if (!IsGenericTaskReturningAsyncMethod() && !IsGenericTaskReturningAsyncMethodViaOverride()) { conversion = Conversion.NoConversion; badAsyncReturnAlreadyReported = true; @@ -2876,7 +2888,8 @@ internal BoundExpression CreateReturnConversion( if (!badAsyncReturnAlreadyReported) { RefKind unusedRefKind; - if (IsGenericTaskReturningAsyncMethod() && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) + if ((IsGenericTaskReturningAsyncMethod() || IsGenericTaskReturningAsyncMethodViaOverride()) + && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) { // Since this is an async method, the return expression must be of type '{0}' rather than 'Task<{0}>' Error(diagnostics, ErrorCode.ERR_BadAsyncReturnExpression, argument.Syntax, returnType); @@ -3165,7 +3178,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr expression = BindToTypeForErrorRecovery(expression); statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true }; } - else if (returnType.IsVoidType() || IsTaskReturningAsyncMethod()) + else if (returnType.IsVoidType() || IsTaskReturningAsyncMethod() || IsTaskReturningAsyncMethodViaOverride()) { // If the return type is void then the expression is required to be a legal // statement expression. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index a138883fe13b..628f20017f1f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -40,7 +40,7 @@ public static BoundBlock Rewrite( #endif var compilation = method.DeclaringCompilation; - if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation)) + if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation) || method.IsAsyncReturningTaskViaOverride(out _)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index fe297f915463..1db99197db65 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -178,36 +178,39 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningTask(F.Compilation)) + object methodLevelBuilder = null; + if (method.IsAsyncReturningTaskViaOverride(out methodLevelBuilder) || method.IsAsyncReturningTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool customBuilder; - object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) + if ((object)methodLevelBuilder != null) { - if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false); + customBuilder = true; + if ((object)initialBuilderType != null) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false); - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - } - } - else + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) { - builderType = null; + taskProperty = GetCustomTaskProperty(F, builderType, returnType); } } else + { + builderType = null; + } + } + else + { + object builderArgument; + customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); if ((object)builderType != null) @@ -216,24 +219,25 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); + Debug.Assert((object)builderType != null); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, + builderType, + customBuilder, + out taskProperty); + } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); - Debug.Assert((object)builderType != null); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, - builderType, - customBuilder, - out taskProperty); - } + if ((object)builderType == null || (object)createBuilderMethod == null || (object)taskProperty == null) @@ -241,6 +245,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, @@ -257,7 +262,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningGenericTask(F.Compilation)) + if (method.IsAsyncReturningGenericTaskViaOverride(out methodLevelBuilder) || method.IsAsyncReturningGenericTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; @@ -273,32 +278,33 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool customBuilder; - object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) + if ((object)methodLevelBuilder != null) { - if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true); + customBuilder = true; + if ((object)initialBuilderType != null) { - builderArgument = methodLevelBuilder; - var initialBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - } - } - else + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) { - builderType = null; + taskProperty = GetCustomTaskProperty(F, builderType, returnType); } } else + { + builderType = null; + } + } + else + { + object builderArgument; + customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); if ((object)builderType != null) @@ -308,25 +314,26 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); + Debug.Assert((object)builderType != null); + builderType = builderType.Construct(resultType); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, + builderType, + customBuilder, + out taskProperty); + } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); - Debug.Assert((object)builderType != null); - builderType = builderType.Construct(resultType); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, - builderType, - customBuilder, - out taskProperty); - } + if ((object)builderType == null || (object)taskProperty == null || (object)createBuilderMethod == null) @@ -334,6 +341,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index d0a1e0d94bdf..460aebec9dfc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -85,7 +85,7 @@ internal AsyncMethodToStateMachineRewriter( _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); - _exprRetValue = method.IsAsyncReturningGenericTask(F.Compilation) + _exprRetValue = method.IsAsyncReturningGenericTask(F.Compilation) || method.IsAsyncReturningGenericTaskViaOverride(out _) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; @@ -208,7 +208,7 @@ protected virtual BoundStatement GenerateSetResultCall() F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, - _method.IsAsyncReturningGenericTask(F.Compilation) + _method.IsAsyncReturningGenericTask(F.Compilation) || _method.IsAsyncReturningGenericTaskViaOverride(out _) ? ImmutableArray.Create(F.Local(_exprRetValue)) : ImmutableArray.Empty)); } @@ -623,7 +623,7 @@ public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { - Debug.Assert(_method.IsAsyncReturningGenericTask(F.Compilation)); + Debug.Assert(_method.IsAsyncReturningGenericTask(F.Compilation) || _method.IsAsyncReturningGenericTaskViaOverride(out _)); return F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel)); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index c2a8f980d422..f25939d14fcc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -192,6 +192,22 @@ public static bool IsAsyncReturningIAsyncEnumerator(this MethodSymbol method, CS } #nullable enable + public static bool IsAsyncReturningTaskViaOverride(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) + { + builderArgument = null; + return method.IsAsync + && method.HasMethodLevelBuilder(builderArgument: out builderArgument) + && method.ReturnType is NamedTypeSymbol { Arity: 0 }; + } + + public static bool IsAsyncReturningGenericTaskViaOverride(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) + { + builderArgument = null; + return method.IsAsync + && method.HasMethodLevelBuilder(builderArgument: out builderArgument) + && method.ReturnType is NamedTypeSymbol { Arity: 1 }; + } + /// /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 993ea3d60454..20ba231f0c60 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1050,12 +1050,13 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) ReportBadRefToken(returnTypeSyntax, diagnostics); hasErrors = true; } - else if (ReturnType.IsBadAsyncReturn(this.DeclaringCompilation)) + else if (isBadAsyncReturn(this)) { diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, errorLocation); hasErrors = true; } - else if (this.HasMethodLevelBuilder(out _)) + + if (this.HasMethodLevelBuilder(out _)) { hasErrors = MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); } @@ -1103,6 +1104,20 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) } } } + + static bool isBadAsyncReturn(MethodSymbol methodSymbol) + { + var returnType = methodSymbol.ReturnType; + var declaringCompilation = methodSymbol.DeclaringCompilation; + return !returnType.IsErrorType() && + !returnType.IsVoidType() && + !returnType.IsNonGenericTaskType(declaringCompilation) && + !returnType.IsGenericTaskType(declaringCompilation) && + !returnType.IsIAsyncEnumerableType(declaringCompilation) && + !returnType.IsIAsyncEnumeratorType(declaringCompilation) && + !methodSymbol.IsAsyncReturningTaskViaOverride(out _) && + !methodSymbol.IsAsyncReturningGenericTaskViaOverride(out _); + } } private static FlowAnalysisAnnotations DecodeReturnTypeAnnotationAttributes(ReturnTypeWellKnownAttributeData attributeData) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index f9a522417a58..ad6fd80d3a77 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1929,17 +1929,6 @@ private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string ou return globalNamespace != null && globalNamespace.IsGlobalNamespace; } - public static bool IsBadAsyncReturn(this TypeSymbol returnType, CSharpCompilation declaringCompilation) - { - // Note: we're passing the return type explicitly (rather than using `method.ReturnType`) to avoid cycles - return !returnType.IsErrorType() && - !returnType.IsVoidType() && - !returnType.IsNonGenericTaskType(declaringCompilation) && - !returnType.IsGenericTaskType(declaringCompilation) && - !returnType.IsIAsyncEnumerableType(declaringCompilation) && - !returnType.IsIAsyncEnumeratorType(declaringCompilation); - } - internal static int TypeToIndex(this TypeSymbol type) { switch (type.GetSpecialTypeSafe()) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 461c1b22fef1..26404c2cff7b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -137,7 +137,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (11,25): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -150,7 +150,7 @@ class C Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("async method builder override").WithLocation(17, 37) ); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -162,51 +162,47 @@ class C Assert.True(method.IsAsyncReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @" { - // Code size 49 (0x31) + // Code size 45 (0x2d) .maxstack 2 .locals init (C.d__0 V_0) - IL_0000: newobj ""C.d__0..ctor()"" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" - IL_000c: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0011: ldloc.0 - IL_0012: ldc.i4.m1 - IL_0013: stfld ""int C.d__0.<>1__state"" - IL_0018: ldloc.0 - IL_0019: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_001e: ldloca.s V_0 - IL_0020: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" - IL_0025: ldloc.0 - IL_0026: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_002b: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_0030: ret + IL_0000: ldloca.s V_0 + IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" + IL_0007: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_000c: ldloca.s V_0 + IL_000e: ldc.i4.m1 + IL_000f: stfld ""int C.d__0.<>1__state"" + IL_0014: ldloc.0 + IL_0015: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_001a: ldloca.s V_0 + IL_001c: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_0021: ldloc.0 + IL_0022: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0027: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_002c: ret } "); verifier.VerifyIL("C.G(T)", @" { - // Code size 56 (0x38) + // Code size 53 (0x35) .maxstack 2 .locals init (C.d__1 V_0) - IL_0000: newobj ""C.d__1..ctor()"" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" - IL_000c: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0011: ldloc.0 - IL_0012: ldarg.0 - IL_0013: stfld ""T C.d__1.t"" - IL_0018: ldloc.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__1.<>1__state"" - IL_001f: ldloc.0 - IL_0020: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0025: ldloca.s V_0 - IL_0027: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" - IL_002c: ldloc.0 - IL_002d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0032: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_0037: ret + IL_0000: ldloca.s V_0 + IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilder.Create()"" + IL_0007: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_000c: ldloca.s V_0 + IL_000e: ldarg.0 + IL_000f: stfld ""T C.d__1.t"" + IL_0014: ldloca.s V_0 + IL_0016: ldc.i4.m1 + IL_0017: stfld ""int C.d__1.<>1__state"" + IL_001c: ldloc.0 + IL_001d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0022: ldloca.s V_0 + IL_0024: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" + IL_0029: ldloc.0 + IL_002a: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_002f: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0034: ret } "); } @@ -214,14 +210,13 @@ .locals init (C.d__1 V_0) [Fact] public void BuilderOnMethod_NoBuilderOnType() { - // Note: although we don't use the builder from the return type, we still require - // the return type to have the attribute. - // One reason is that if the return type is not "task-like" then implicit returns are disallowed. var source = $@" using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; +Console.WriteLine(await C.M()); + class C {{ [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] @@ -245,20 +240,64 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderOnMethod_NoBuilderOnType_BadReturns() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ await Task.Yield(); return 1; }} // 1 + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ await Task.Yield(); return; }} // 2 + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask M() {{ await Task.Yield(); return null; }} // 3 + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask M2(MyTask mt) {{ await Task.Yield(); return mt; }} // 4 + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask M2(bool b) => b ? await Task.Yield() : await Task.Yield(); // 5 +}} + +// no attribute +{AwaitableTypeCode("MyTask")} + +// no attribute +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (9,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(9, 25), - // (9,25): error CS0161: 'C.F()': not all code paths return a value - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(9, 25), - // (12,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(12, 28), - // (15,37): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(15, 37) + // (9,51): error CS1997: Since 'C.F()' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task'? + // static async MyTask F() { await Task.Yield(); return 1; } // 1 + Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequired, "return").WithArguments("C.F()").WithLocation(9, 51), + // (12,60): error CS0126: An object of a type convertible to 'T' is required + // static async MyTask G(T t) { await Task.Yield(); return; } // 2 + Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("T").WithLocation(12, 60), + // (15,63): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type + // static async MyTask M() { await Task.Yield(); return null; } // 3 + Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(15, 63), + // (18,78): error CS4016: Since this is an async method, the return expression must be of type 'int' rather than 'Task' + // static async MyTask M2(MyTask mt) { await Task.Yield(); return mt; } // 4 + Diagnostic(ErrorCode.ERR_BadAsyncReturnExpression, "mt").WithArguments("int").WithLocation(18, 78), + // (21,39): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // static async MyTask M2(bool b) => b ? await Task.Yield() : await Task.Yield(); // 5 + Diagnostic(ErrorCode.ERR_IllegalStatement, "b ? await Task.Yield() : await Task.Yield()").WithLocation(21, 39) ); } @@ -2106,8 +2145,5 @@ class C var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyEmitDiagnostics(); } - - // PROTOTYPE confirm with LDM how much validation we should do on the builder type of the return type which is unused - // PROTOTYPE confirm with LDM that the factory indirection should only apply to overrides } } From e1f1d413b3de8bed6daaed5e314bf9402404259e Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 15 Jun 2021 12:12:24 -0700 Subject: [PATCH 03/24] Relax accessibility requirements for overrides --- .../AsyncMethodBuilderMemberCollection.cs | 8 +-- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 64 ++++++++++++++----- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index 1db99197db65..54b733baff1b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -189,7 +189,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if ((object)methodLevelBuilder != null) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false); + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); customBuilder = true; if ((object)initialBuilderType != null) { @@ -282,7 +282,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if ((object)methodLevelBuilder != null) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true); + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); customBuilder = true; if ((object)initialBuilderType != null) { @@ -361,14 +361,14 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, throw ExceptionUtilities.UnexpectedValue(method); } - private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric) + private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric, bool forOverride = false) { var builderType = builderAttributeArgument as NamedTypeSymbol; if ((object)builderType != null && !builderType.IsErrorType() && !builderType.IsVoidType() && - builderType.DeclaredAccessibility == desiredAccessibility) + (forOverride || builderType.DeclaredAccessibility == desiredAccessibility)) { bool isArityOk = isGeneric ? builderType.IsUnboundGenericType && builderType.ContainingType?.IsGenericType != true && builderType.Arity == 1 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 26404c2cff7b..e3d00e1bf3b1 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -1133,6 +1133,9 @@ public void BuilderFactoryOnMethod_BuilderFactoryIsInternal() using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + class C {{ [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] @@ -1142,7 +1145,7 @@ class C static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] - static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} [AsyncMethodBuilder(null)] @@ -1156,17 +1159,44 @@ class C {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (8,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(8, 29), - // (11,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(11, 38), - // (14,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(14, 34) - ); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderFactoryOnMethod_BuilderFactoryIsPrivate() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} + + {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} + {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} +}} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); } [Fact] @@ -2063,7 +2093,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } [Fact] - public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilder() + public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilderMembers() { var source = $@" using System; @@ -2112,12 +2142,12 @@ class Program // (97,19): error CS0656: Missing compiler required member 'B2Factory.Create' // async T2 f2() => await Task.Delay(2); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(2)").WithArguments("B2Factory", "Create").WithLocation(97, 19), - // (100,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // (100,19): error CS0656: Missing compiler required member 'B3.Task' // async T3 f3() => await Task.Delay(3); - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(3)").WithLocation(100, 19), - // (103,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("B3", "Task").WithLocation(100, 19), + // (103,19): error CS0656: Missing compiler required member 'B4Factory.Create' // async T4 f4() => await Task.Delay(4); - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(4)").WithLocation(103, 19) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(4)").WithArguments("B4Factory", "Create").WithLocation(103, 19) ); } From a39ee15a52e1d4021e770272344a1694ccb2ec05 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 16 Jun 2021 11:39:14 -0700 Subject: [PATCH 04/24] Factor extension methods --- .../Portable/Binder/Binder_Expressions.cs | 3 +- .../Portable/Binder/Binder_Statements.cs | 32 +++++--------- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../AsyncMethodBuilderMemberCollection.cs | 4 +- .../AsyncMethodToStateMachineRewriter.cs | 6 +-- .../Symbols/MethodSymbolExtensions.cs | 40 +++++++----------- .../SourceMethodSymbolWithAttributes.cs | 6 +-- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 42 ++++++++++++++++--- .../BindingAsyncTasklikeMoreTests.cs | 16 +++---- 9 files changed, 78 insertions(+), 73 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 3201e4f49816..f9f928fb6e0c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8597,8 +8597,7 @@ private bool ContainingMethodOrLambdaRequiresValue() return (object)containingMethod == null || !containingMethod.ReturnsVoid && - !containingMethod.IsAsyncReturningTask(this.Compilation) && - !containingMethod.IsAsyncReturningTaskViaOverride(out _); + !containingMethod.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 4eaa23fe3a4c..ca5bfea2bb4c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -623,7 +623,7 @@ BoundBlock runAnalysis(BoundBlock block, BindingDiagnosticBag blockDiagnostics) private bool ImplicitReturnIsOkay(MethodSymbol method) { - return method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(this.Compilation) || method.IsAsyncReturningTaskViaOverride(out _); + return method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2644,28 +2644,16 @@ protected bool IsInAsyncMethod() return IsInAsyncMethod(this.ContainingMemberOrLambda as MethodSymbol); } - protected bool IsTaskReturningAsyncMethod() + protected bool IsEffectivelyTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTask(this.Compilation); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); } - protected bool IsTaskReturningAsyncMethodViaOverride() + protected bool IsEffectivelyGenericTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTaskViaOverride(out _); - } - - protected bool IsGenericTaskReturningAsyncMethod() - { - var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTask(this.Compilation); - } - - protected bool IsGenericTaskReturningAsyncMethodViaOverride() - { - var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTaskViaOverride(out _); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningGenericTask(this.Compilation, builderOverride: out _); } protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() @@ -2768,7 +2756,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti // on a lambda expression of unknown return type. if ((object)retType != null) { - if (retType.IsVoidType() || IsTaskReturningAsyncMethod() || IsTaskReturningAsyncMethodViaOverride()) + if (retType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) { if (arg != null) { @@ -2808,7 +2796,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti if (arg == null) { // Error case: non-void-returning or Task-returning method or lambda but just have "return;" - var requiredType = IsGenericTaskReturningAsyncMethod() || IsGenericTaskReturningAsyncMethodViaOverride() + var requiredType = IsEffectivelyGenericTaskReturningAsyncMethod() ? retType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single() : retType; @@ -2851,7 +2839,7 @@ internal BoundExpression CreateReturnConversion( { Debug.Assert(returnRefKind == RefKind.None); - if (!IsGenericTaskReturningAsyncMethod() && !IsGenericTaskReturningAsyncMethodViaOverride()) + if (!IsEffectivelyGenericTaskReturningAsyncMethod()) { conversion = Conversion.NoConversion; badAsyncReturnAlreadyReported = true; @@ -2888,7 +2876,7 @@ internal BoundExpression CreateReturnConversion( if (!badAsyncReturnAlreadyReported) { RefKind unusedRefKind; - if ((IsGenericTaskReturningAsyncMethod() || IsGenericTaskReturningAsyncMethodViaOverride()) + if (IsEffectivelyGenericTaskReturningAsyncMethod() && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) { // Since this is an async method, the return expression must be of type '{0}' rather than 'Task<{0}>' @@ -3178,7 +3166,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr expression = BindToTypeForErrorRecovery(expression); statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true }; } - else if (returnType.IsVoidType() || IsTaskReturningAsyncMethod() || IsTaskReturningAsyncMethodViaOverride()) + else if (returnType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index 628f20017f1f..49b5dbca5e72 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -40,7 +40,7 @@ public static BoundBlock Rewrite( #endif var compilation = method.DeclaringCompilation; - if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation) || method.IsAsyncReturningTaskViaOverride(out _)) + if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index 54b733baff1b..e4e9759c428e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -179,7 +179,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, } object methodLevelBuilder = null; - if (method.IsAsyncReturningTaskViaOverride(out methodLevelBuilder) || method.IsAsyncReturningTask(F.Compilation)) + if (method.IsAsyncEffectivelyReturningTask(F.Compilation, out methodLevelBuilder)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; @@ -262,7 +262,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningGenericTaskViaOverride(out methodLevelBuilder) || method.IsAsyncReturningGenericTask(F.Compilation)) + if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, out methodLevelBuilder)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index 460aebec9dfc..768b3d612a17 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -85,7 +85,7 @@ internal AsyncMethodToStateMachineRewriter( _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); - _exprRetValue = method.IsAsyncReturningGenericTask(F.Compilation) || method.IsAsyncReturningGenericTaskViaOverride(out _) + _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; @@ -208,7 +208,7 @@ protected virtual BoundStatement GenerateSetResultCall() F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, - _method.IsAsyncReturningGenericTask(F.Compilation) || _method.IsAsyncReturningGenericTaskViaOverride(out _) + _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) ? ImmutableArray.Create(F.Local(_exprRetValue)) : ImmutableArray.Empty)); } @@ -623,7 +623,7 @@ public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { - Debug.Assert(_method.IsAsyncReturningGenericTask(F.Compilation) || _method.IsAsyncReturningGenericTaskViaOverride(out _)); + Debug.Assert(_method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _)); return F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel)); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index f25939d14fcc..d54c71912bac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -147,6 +147,7 @@ private static bool CanBeHiddenByMethodPropertyOrType(MethodSymbol method) } } +#nullable enable /// /// Returns whether this method is async and returns void. /// @@ -156,21 +157,25 @@ public static bool IsAsyncReturningVoid(this MethodSymbol method) } /// - /// Returns whether this method is async and returns a task. + /// Returns whether this method is async and returns a task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncReturningTask(this MethodSymbol method, CSharpCompilation compilation) + public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) { + builderOverride = null; return method.IsAsync - && method.ReturnType.IsNonGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 0 } + && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); } /// - /// Returns whether this method is async and returns a generic task. + /// Returns whether this method is async and returns a generic task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation) + public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) { + builderOverride = null; return method.IsAsync - && method.ReturnType.IsGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 1 } + && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); } /// @@ -191,28 +196,11 @@ public static bool IsAsyncReturningIAsyncEnumerator(this MethodSymbol method, CS && method.ReturnType.IsIAsyncEnumeratorType(compilation); } -#nullable enable - public static bool IsAsyncReturningTaskViaOverride(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) - { - builderArgument = null; - return method.IsAsync - && method.HasMethodLevelBuilder(builderArgument: out builderArgument) - && method.ReturnType is NamedTypeSymbol { Arity: 0 }; - } - - public static bool IsAsyncReturningGenericTaskViaOverride(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) - { - builderArgument = null; - return method.IsAsync - && method.HasMethodLevelBuilder(builderArgument: out builderArgument) - && method.ReturnType is NamedTypeSymbol { Arity: 1 }; - } - /// /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. /// - internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) + internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderOverride) { Debug.Assert(method is not null); @@ -223,12 +211,12 @@ internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhe && attr.CommonConstructorArguments.Length == 1 && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) { - builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; + builderOverride = attr.CommonConstructorArguments[0].ValueInternal!; return true; } } - builderArgument = null; + builderOverride = null; return false; } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 20ba231f0c60..12c1e2387083 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1111,12 +1111,10 @@ static bool isBadAsyncReturn(MethodSymbol methodSymbol) var declaringCompilation = methodSymbol.DeclaringCompilation; return !returnType.IsErrorType() && !returnType.IsVoidType() && - !returnType.IsNonGenericTaskType(declaringCompilation) && - !returnType.IsGenericTaskType(declaringCompilation) && !returnType.IsIAsyncEnumerableType(declaringCompilation) && !returnType.IsIAsyncEnumeratorType(declaringCompilation) && - !methodSymbol.IsAsyncReturningTaskViaOverride(out _) && - !methodSymbol.IsAsyncReturningGenericTaskViaOverride(out _); + !methodSymbol.IsAsyncEffectivelyReturningTask(declaringCompilation, builderOverride: out _) && + !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation, builderOverride: out _); } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e3d00e1bf3b1..e0824b874210 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -156,10 +156,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); verifier.VerifyIL("C.F()", @" { // Code size 45 (0x2d) @@ -522,10 +522,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); // The initial builder type is used for Create() invocation verifier.VerifyIL("C.F()", @" @@ -807,6 +807,38 @@ public void BuilderFactoryOnMethod_OnLambda() verifier.VerifyDiagnostics(); } + [Fact] + public void BuilderFactoryOnMethod_OnLambda_WithExplicitType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +var f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async MyTask () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; + +var m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async MyTask () => {{ System.Console.Write(""M ""); await f(); return 3; }}; + +Console.WriteLine(await m()); +return; + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", isStruct: true)} + +[AsyncMethodBuilder(null)] +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + // This test will be revisited once explicit lambda return types are allowed + Assert.Equal(16, compilation.GetDiagnostics().Length); + //var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + //verifier.VerifyDiagnostics(); + } + [Fact] public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() { @@ -988,7 +1020,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_CreateHasParamaeter() + public void BuilderFactoryOnMethod_CreateHasParameter() { var source = $@" using System; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 83b44e34e8f6..34fbbf6a8a0f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -434,11 +434,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +515,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +594,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From e4ab3c347250db3488a97e33179d34d81862cb0c Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 16 Jun 2021 12:41:10 -0700 Subject: [PATCH 05/24] Fix nullability scenario --- .../Portable/BoundTree/UnboundLambda.cs | 4 +- .../Portable/FlowAnalysis/NullableWalker.cs | 2 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 102 ++++++++++++++++-- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 7f03fb6cb86a..da1858c61802 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -563,7 +563,7 @@ private bool DelegateNeedsReturn(MethodSymbol? invokeMethod) return false; } - if (IsAsync && invokeMethod.ReturnType.IsNonGenericTaskType(this.Binder.Compilation)) + if (IsAsync && invokeMethod.ReturnType.IsNonGenericTaskType(this.Binder.Compilation)) // TODO2 { return false; } @@ -707,7 +707,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { if (returnType.HasType && // Can be null if "delegateType" is not actually a delegate type. !returnType.IsVoidType() && - !returnType.Type.IsNonGenericTaskType(compilation) && + !returnType.Type.IsNonGenericTaskType(compilation) && // TODO2 !returnType.Type.IsGenericTaskType(compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 62e4c9f9f911..3acb6ac25fd5 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2542,7 +2542,7 @@ private bool TryGetReturnType(out TypeWithAnnotations type, out FlowAnalysisAnno return true; } - if (returnType.Type.IsGenericTaskType(compilation)) + if (method.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) { type = ((NamedTypeSymbol)returnType.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single(); annotations = FlowAnalysisAnnotations.None; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e0824b874210..0fa4d8b3b74d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -240,10 +240,64 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); } + [Fact] + public void BuilderOnMethod_NoBuilderOnType_Nullability() + { + var source = $@" +#nullable enable + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) + {{ + await Task.Delay(0); + return default(T); // 1 + }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M() + {{ + return await G((string?)null); // 2 + }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M2() {{ return await G((string?)null); }} +}} + +// no attribute +{AwaitableTypeCode("MyTask")} + +// no attribute +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics( + // (14,16): warning CS8603: Possible null reference return. + // return default(T); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default(T)").WithLocation(14, 16), + // (20,16): warning CS8603: Possible null reference return. + // return await G((string?)null); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "await G((string?)null)").WithLocation(20, 16), + // (44,16): warning CS8618: Non-nullable field '_result' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // internal T _result; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "_result").WithArguments("field", "_result").WithLocation(44, 16) + ); + } + [Fact] public void BuilderOnMethod_NoBuilderOnType_BadReturns() { @@ -335,7 +389,7 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild {AsyncMethodBuilderAttribute} "; source = source.Replace("DUMMY_BUILDER", dummyBuilder); - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (9,21): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -348,7 +402,7 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("async method builder override").WithLocation(15, 26) ); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); verifier.VerifyDiagnostics(); } @@ -516,7 +570,7 @@ class C {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3", symbolValidator: verifyMembers); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -802,7 +856,7 @@ public void BuilderFactoryOnMethod_OnLambda() {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); verifier.VerifyDiagnostics(); } @@ -832,13 +886,49 @@ public void BuilderFactoryOnMethod_OnLambda_WithExplicitType() {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); // This test will be revisited once explicit lambda return types are allowed Assert.Equal(16, compilation.GetDiagnostics().Length); //var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); //verifier.VerifyDiagnostics(); } + [Fact] + public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; + +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; + +Console.WriteLine(await m()); +return; + +// no attribute +{AwaitableTypeCode("MyTask", isStruct: true)} + +// no attribute +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics( + // (6,91): error CS1643: Not all code paths return a value in lambda expression of type 'Func' + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(6, 91), + // (8,91): error CS4010: Cannot convert async lambda expression to delegate type 'Func>'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func>'. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(8, 91) + ); + } + [Fact] public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() { From 72cbc019f91185e19d84b544a507006299b8b322 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 17 Jun 2021 11:35:51 -0700 Subject: [PATCH 06/24] Fix lambda scenario with non-task-like return type --- .../Portable/Binder/Binder_Expressions.cs | 16 +++++++------- .../Portable/BoundTree/UnboundLambda.cs | 21 +++---------------- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 10 ++------- 3 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index f9f928fb6e0c..465bd89d9481 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8553,15 +8553,15 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess break; case SyntaxKind.SimpleLambdaExpression: - resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ParenthesizedLambdaExpression: - resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ArrowExpressionClause: - resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ForStatement: @@ -8591,13 +8591,11 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess return new BoundConditionalAccess(node, receiver, access, accessType); } - private bool ContainingMethodOrLambdaRequiresValue() + internal static bool MethodOrLambdaRequiresValue(Symbol symbol, CSharpCompilation compilation) { - var containingMethod = ContainingMemberOrLambda as MethodSymbol; - return - (object)containingMethod == null || - !containingMethod.ReturnsVoid && - !containingMethod.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); + return symbol is MethodSymbol method && + !method.ReturnsVoid && + !method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index da1858c61802..56331d7c1d52 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -556,21 +556,6 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo return invokeMethod.ReturnTypeWithAnnotations; } - private bool DelegateNeedsReturn(MethodSymbol? invokeMethod) - { - if (invokeMethod is null || invokeMethod.ReturnsVoid) - { - return false; - } - - if (IsAsync && invokeMethod.ReturnType.IsNonGenericTaskType(this.Binder.Compilation)) // TODO2 - { - return false; - } - - return true; - } - internal NamedTypeSymbol? InferDelegateType(ref CompoundUseSiteInfo useSiteInfo) { Debug.Assert(Binder.ContainingMemberOrLambda is { }); @@ -692,7 +677,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) bool reachableEndpoint = ControlFlowPass.Analyze(compilation, lambdaSymbol, block, diagnostics.DiagnosticBag); if (reachableEndpoint) { - if (DelegateNeedsReturn(invokeMethod)) + if (Binder.MethodOrLambdaRequiresValue(lambdaSymbol, this.Binder.Compilation)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.DiagnosticLocation, this.MessageID.Localize(), delegateType); @@ -707,8 +692,8 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { if (returnType.HasType && // Can be null if "delegateType" is not actually a delegate type. !returnType.IsVoidType() && - !returnType.Type.IsNonGenericTaskType(compilation) && // TODO2 - !returnType.Type.IsGenericTaskType(compilation)) + !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _) && + !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 0fa4d8b3b74d..673143ac737c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -919,14 +919,8 @@ public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyDiagnostics( - // (6,91): error CS1643: Not all code paths return a value in lambda expression of type 'Func' - // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(6, 91), - // (8,91): error CS4010: Cannot convert async lambda expression to delegate type 'Func>'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func>'. - // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => { System.Console.Write("M "); await f(); return 3; }; - Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(8, 91) - ); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + verifier.VerifyDiagnostics(); } [Fact] From 3e9518b52d3d5335de8dd846deccc0e2cba4d3c4 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 17 Jun 2021 13:40:50 -0700 Subject: [PATCH 07/24] Fix test --- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 322 ++++++++---------- 1 file changed, 149 insertions(+), 173 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 673143ac737c..596f0f27e466 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -584,227 +584,201 @@ class C // The initial builder type is used for Create() invocation verifier.VerifyIL("C.F()", @" { - // Code size 49 (0x31) + // Code size 45 (0x2d) .maxstack 2 .locals init (C.d__0 V_0) - IL_0000: newobj ""C.d__0..ctor()"" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" - IL_000c: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0011: ldloc.0 - IL_0012: ldc.i4.m1 - IL_0013: stfld ""int C.d__0.<>1__state"" - IL_0018: ldloc.0 - IL_0019: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_001e: ldloca.s V_0 - IL_0020: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" - IL_0025: ldloc.0 - IL_0026: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_002b: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_0030: ret + IL_0000: ldloca.s V_0 + IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" + IL_0007: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_000c: ldloca.s V_0 + IL_000e: ldc.i4.m1 + IL_000f: stfld ""int C.d__0.<>1__state"" + IL_0014: ldloc.0 + IL_0015: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_001a: ldloca.s V_0 + IL_001c: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_0021: ldloc.0 + IL_0022: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0027: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_002c: ret }"); // The final builder type is used for the rest verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 166 (0xa6) + // Code size 153 (0x99) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, - C.d__0 V_2, - System.Exception V_3) + System.Exception V_2) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__0.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_000c - IL_000a: br.s IL_000e - IL_000c: br.s IL_0053 - IL_000e: nop - IL_000f: ldstr ""F "" - IL_0014: call ""void System.Console.Write(string)"" - IL_0019: nop - IL_001a: ldc.i4.0 - IL_001b: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" - IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0025: stloc.1 - IL_0026: ldloca.s V_1 - IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_002d: brtrue.s IL_006f - IL_002f: ldarg.0 - IL_0030: ldc.i4.0 - IL_0031: dup - IL_0032: stloc.0 - IL_0033: stfld ""int C.d__0.<>1__state"" - IL_0038: ldarg.0 - IL_0039: ldloc.1 - IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_003f: ldarg.0 - IL_0040: stloc.2 + IL_0008: brfalse.s IL_0049 + IL_000a: ldstr ""F "" + IL_000f: call ""void System.Console.Write(string)"" + IL_0014: ldc.i4.0 + IL_0015: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" + IL_001a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_001f: stloc.1 + IL_0020: ldloca.s V_1 + IL_0022: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0027: brtrue.s IL_0065 + IL_0029: ldarg.0 + IL_002a: ldc.i4.0 + IL_002b: dup + IL_002c: stloc.0 + IL_002d: stfld ""int C.d__0.<>1__state"" + IL_0032: ldarg.0 + IL_0033: ldloc.1 + IL_0034: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0039: ldarg.0 + IL_003a: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_003f: ldloca.s V_1 IL_0041: ldarg.0 - IL_0042: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0047: ldloca.s V_1 - IL_0049: ldloca.s V_2 - IL_004b: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0050: nop - IL_0051: leave.s IL_00a5 - IL_0053: ldarg.0 - IL_0054: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0059: stloc.1 - IL_005a: ldarg.0 - IL_005b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0060: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0066: ldarg.0 - IL_0067: ldc.i4.m1 - IL_0068: dup - IL_0069: stloc.0 - IL_006a: stfld ""int C.d__0.<>1__state"" - IL_006f: ldloca.s V_1 - IL_0071: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0076: nop - IL_0077: leave.s IL_0091 + IL_0042: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_0047: leave.s IL_0098 + IL_0049: ldarg.0 + IL_004a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_004f: stloc.1 + IL_0050: ldarg.0 + IL_0051: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0056: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_005c: ldarg.0 + IL_005d: ldc.i4.m1 + IL_005e: dup + IL_005f: stloc.0 + IL_0060: stfld ""int C.d__0.<>1__state"" + IL_0065: ldloca.s V_1 + IL_0067: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_006c: leave.s IL_0085 } catch System.Exception { - IL_0079: stloc.3 - IL_007a: ldarg.0 - IL_007b: ldc.i4.s -2 - IL_007d: stfld ""int C.d__0.<>1__state"" - IL_0082: ldarg.0 - IL_0083: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0088: ldloc.3 - IL_0089: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" - IL_008e: nop - IL_008f: leave.s IL_00a5 + IL_006e: stloc.2 + IL_006f: ldarg.0 + IL_0070: ldc.i4.s -2 + IL_0072: stfld ""int C.d__0.<>1__state"" + IL_0077: ldarg.0 + IL_0078: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_007d: ldloc.2 + IL_007e: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" + IL_0083: leave.s IL_0098 } - IL_0091: ldarg.0 - IL_0092: ldc.i4.s -2 - IL_0094: stfld ""int C.d__0.<>1__state"" - IL_0099: ldarg.0 - IL_009a: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_009f: callvirt ""void MyTaskMethodBuilder.SetResult()"" - IL_00a4: nop - IL_00a5: ret + IL_0085: ldarg.0 + IL_0086: ldc.i4.s -2 + IL_0088: stfld ""int C.d__0.<>1__state"" + IL_008d: ldarg.0 + IL_008e: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" + IL_0093: callvirt ""void MyTaskMethodBuilder.SetResult()"" + IL_0098: ret } "); // The initial builder type is used for Create() invocation verifier.VerifyIL("C.G(T)", @" { - // Code size 56 (0x38) + // Code size 53 (0x35) .maxstack 2 .locals init (C.d__1 V_0) - IL_0000: newobj ""C.d__1..ctor()"" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" - IL_000c: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0011: ldloc.0 - IL_0012: ldarg.0 - IL_0013: stfld ""T C.d__1.t"" - IL_0018: ldloc.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__1.<>1__state"" - IL_001f: ldloc.0 - IL_0020: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0025: ldloca.s V_0 - IL_0027: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" - IL_002c: ldloc.0 - IL_002d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0032: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_0037: ret + IL_0000: ldloca.s V_0 + IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" + IL_0007: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_000c: ldloca.s V_0 + IL_000e: ldarg.0 + IL_000f: stfld ""T C.d__1.t"" + IL_0014: ldloca.s V_0 + IL_0016: ldc.i4.m1 + IL_0017: stfld ""int C.d__1.<>1__state"" + IL_001c: ldloc.0 + IL_001d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0022: ldloca.s V_0 + IL_0024: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" + IL_0029: ldloc.0 + IL_002a: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_002f: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" + IL_0034: ret }"); // The final builder type is used for the rest verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 176 (0xb0) + // Code size 161 (0xa1) .maxstack 3 .locals init (int V_0, T V_1, System.Runtime.CompilerServices.TaskAwaiter V_2, - C.d__1 V_3, - System.Exception V_4) + System.Exception V_3) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_000c - IL_000a: br.s IL_000e - IL_000c: br.s IL_0053 - IL_000e: nop - IL_000f: ldstr ""G "" - IL_0014: call ""void System.Console.Write(string)"" - IL_0019: nop - IL_001a: ldc.i4.0 - IL_001b: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" - IL_0020: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0025: stloc.2 - IL_0026: ldloca.s V_2 - IL_0028: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_002d: brtrue.s IL_006f - IL_002f: ldarg.0 - IL_0030: ldc.i4.0 - IL_0031: dup - IL_0032: stloc.0 - IL_0033: stfld ""int C.d__1.<>1__state"" - IL_0038: ldarg.0 - IL_0039: ldloc.2 - IL_003a: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_003f: ldarg.0 - IL_0040: stloc.3 + IL_0008: brfalse.s IL_0049 + IL_000a: ldstr ""G "" + IL_000f: call ""void System.Console.Write(string)"" + IL_0014: ldc.i4.0 + IL_0015: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" + IL_001a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_001f: stloc.2 + IL_0020: ldloca.s V_2 + IL_0022: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0027: brtrue.s IL_0065 + IL_0029: ldarg.0 + IL_002a: ldc.i4.0 + IL_002b: dup + IL_002c: stloc.0 + IL_002d: stfld ""int C.d__1.<>1__state"" + IL_0032: ldarg.0 + IL_0033: ldloc.2 + IL_0034: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0039: ldarg.0 + IL_003a: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_003f: ldloca.s V_2 IL_0041: ldarg.0 - IL_0042: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0047: ldloca.s V_2 - IL_0049: ldloca.s V_3 - IL_004b: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" - IL_0050: nop - IL_0051: leave.s IL_00af - IL_0053: ldarg.0 - IL_0054: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_0059: stloc.2 - IL_005a: ldarg.0 - IL_005b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_0060: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0066: ldarg.0 - IL_0067: ldc.i4.m1 - IL_0068: dup - IL_0069: stloc.0 - IL_006a: stfld ""int C.d__1.<>1__state"" - IL_006f: ldloca.s V_2 - IL_0071: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0076: nop - IL_0077: ldarg.0 - IL_0078: ldfld ""T C.d__1.t"" - IL_007d: stloc.1 - IL_007e: leave.s IL_009a + IL_0042: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" + IL_0047: leave.s IL_00a0 + IL_0049: ldarg.0 + IL_004a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_004f: stloc.2 + IL_0050: ldarg.0 + IL_0051: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0056: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_005c: ldarg.0 + IL_005d: ldc.i4.m1 + IL_005e: dup + IL_005f: stloc.0 + IL_0060: stfld ""int C.d__1.<>1__state"" + IL_0065: ldloca.s V_2 + IL_0067: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_006c: ldarg.0 + IL_006d: ldfld ""T C.d__1.t"" + IL_0072: stloc.1 + IL_0073: leave.s IL_008c } catch System.Exception { - IL_0080: stloc.s V_4 - IL_0082: ldarg.0 - IL_0083: ldc.i4.s -2 - IL_0085: stfld ""int C.d__1.<>1__state"" - IL_008a: ldarg.0 - IL_008b: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0090: ldloc.s V_4 - IL_0092: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" - IL_0097: nop - IL_0098: leave.s IL_00af + IL_0075: stloc.3 + IL_0076: ldarg.0 + IL_0077: ldc.i4.s -2 + IL_0079: stfld ""int C.d__1.<>1__state"" + IL_007e: ldarg.0 + IL_007f: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_0084: ldloc.3 + IL_0085: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" + IL_008a: leave.s IL_00a0 } - IL_009a: ldarg.0 - IL_009b: ldc.i4.s -2 - IL_009d: stfld ""int C.d__1.<>1__state"" - IL_00a2: ldarg.0 - IL_00a3: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_00a8: ldloc.1 - IL_00a9: callvirt ""void MyTaskMethodBuilder.SetResult(T)"" - IL_00ae: nop - IL_00af: ret + IL_008c: ldarg.0 + IL_008d: ldc.i4.s -2 + IL_008f: stfld ""int C.d__1.<>1__state"" + IL_0094: ldarg.0 + IL_0095: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" + IL_009a: ldloc.1 + IL_009b: callvirt ""void MyTaskMethodBuilder.SetResult(T)"" + IL_00a0: ret } "); @@ -816,6 +790,7 @@ void verifyMembers(ModuleSymbol module) "C.d__0..ctor()", "void C.d__0.MoveNext()", "void C.d__0.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", + "System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1", "System.Int32 C.d__0.<>1__state" }, fType.GetMembersUnordered().ToTestDisplayStrings()); @@ -826,6 +801,7 @@ void verifyMembers(ModuleSymbol module) "T C.d__1.t", "C.d__1..ctor()", "void C.d__1.MoveNext()", + "System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1", "System.Int32 C.d__1.<>1__state"}, gType.GetMembersUnordered().ToTestDisplayStrings()); } From 2a3fdf149e01ad855ef822442548d5239ae19cfc Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 17 Jun 2021 15:26:44 -0700 Subject: [PATCH 08/24] Disallow non-task-like return type after all --- .../Portable/Binder/Binder_Expressions.cs | 16 +- .../Portable/Binder/Binder_Statements.cs | 21 ++- .../Portable/BoundTree/UnboundLambda.cs | 21 ++- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../Portable/FlowAnalysis/NullableWalker.cs | 2 +- .../AsyncMethodBuilderMemberCollection.cs | 154 +++++++++--------- .../AsyncMethodToStateMachineRewriter.cs | 6 +- .../Symbols/MethodSymbolExtensions.cs | 24 ++- .../SourceMethodSymbolWithAttributes.cs | 14 +- .../Portable/Symbols/TypeSymbolExtensions.cs | 11 ++ .../CodeGenAsyncMethodBuilderOverrideTests.cs | 122 +++++++++++--- .../BindingAsyncTasklikeMoreTests.cs | 16 +- 12 files changed, 244 insertions(+), 165 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 465bd89d9481..d09ed9112d04 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8553,15 +8553,15 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess break; case SyntaxKind.SimpleLambdaExpression: - resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); + resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); break; case SyntaxKind.ParenthesizedLambdaExpression: - resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); + resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); break; case SyntaxKind.ArrowExpressionClause: - resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); + resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || ContainingMethodOrLambdaRequiresValue(); break; case SyntaxKind.ForStatement: @@ -8591,11 +8591,13 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess return new BoundConditionalAccess(node, receiver, access, accessType); } - internal static bool MethodOrLambdaRequiresValue(Symbol symbol, CSharpCompilation compilation) + private bool ContainingMethodOrLambdaRequiresValue() { - return symbol is MethodSymbol method && - !method.ReturnsVoid && - !method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _); + var containingMethod = ContainingMemberOrLambda as MethodSymbol; + return + (object)containingMethod == null || + !containingMethod.ReturnsVoid && + !containingMethod.IsAsyncReturningTask(this.Compilation); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index ca5bfea2bb4c..233fcb3033ed 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -623,7 +623,7 @@ BoundBlock runAnalysis(BoundBlock block, BindingDiagnosticBag blockDiagnostics) private bool ImplicitReturnIsOkay(MethodSymbol method) { - return method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); + return method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(this.Compilation); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2644,16 +2644,16 @@ protected bool IsInAsyncMethod() return IsInAsyncMethod(this.ContainingMemberOrLambda as MethodSymbol); } - protected bool IsEffectivelyTaskReturningAsyncMethod() + protected bool IsTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTask(this.Compilation); } - protected bool IsEffectivelyGenericTaskReturningAsyncMethod() + protected bool IsGenericTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningGenericTask(this.Compilation, builderOverride: out _); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTask(this.Compilation); } protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() @@ -2756,7 +2756,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti // on a lambda expression of unknown return type. if ((object)retType != null) { - if (retType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) + if (retType.IsVoidType() || IsTaskReturningAsyncMethod()) { if (arg != null) { @@ -2796,7 +2796,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti if (arg == null) { // Error case: non-void-returning or Task-returning method or lambda but just have "return;" - var requiredType = IsEffectivelyGenericTaskReturningAsyncMethod() + var requiredType = IsGenericTaskReturningAsyncMethod() ? retType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single() : retType; @@ -2839,7 +2839,7 @@ internal BoundExpression CreateReturnConversion( { Debug.Assert(returnRefKind == RefKind.None); - if (!IsEffectivelyGenericTaskReturningAsyncMethod()) + if (!IsGenericTaskReturningAsyncMethod()) { conversion = Conversion.NoConversion; badAsyncReturnAlreadyReported = true; @@ -2876,8 +2876,7 @@ internal BoundExpression CreateReturnConversion( if (!badAsyncReturnAlreadyReported) { RefKind unusedRefKind; - if (IsEffectivelyGenericTaskReturningAsyncMethod() - && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) + if (IsGenericTaskReturningAsyncMethod() && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) { // Since this is an async method, the return expression must be of type '{0}' rather than 'Task<{0}>' Error(diagnostics, ErrorCode.ERR_BadAsyncReturnExpression, argument.Syntax, returnType); @@ -3166,7 +3165,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr expression = BindToTypeForErrorRecovery(expression); statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true }; } - else if (returnType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) + else if (returnType.IsVoidType() || IsTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 56331d7c1d52..7f03fb6cb86a 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -556,6 +556,21 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo return invokeMethod.ReturnTypeWithAnnotations; } + private bool DelegateNeedsReturn(MethodSymbol? invokeMethod) + { + if (invokeMethod is null || invokeMethod.ReturnsVoid) + { + return false; + } + + if (IsAsync && invokeMethod.ReturnType.IsNonGenericTaskType(this.Binder.Compilation)) + { + return false; + } + + return true; + } + internal NamedTypeSymbol? InferDelegateType(ref CompoundUseSiteInfo useSiteInfo) { Debug.Assert(Binder.ContainingMemberOrLambda is { }); @@ -677,7 +692,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) bool reachableEndpoint = ControlFlowPass.Analyze(compilation, lambdaSymbol, block, diagnostics.DiagnosticBag); if (reachableEndpoint) { - if (Binder.MethodOrLambdaRequiresValue(lambdaSymbol, this.Binder.Compilation)) + if (DelegateNeedsReturn(invokeMethod)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.DiagnosticLocation, this.MessageID.Localize(), delegateType); @@ -692,8 +707,8 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { if (returnType.HasType && // Can be null if "delegateType" is not actually a delegate type. !returnType.IsVoidType() && - !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _) && - !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) + !returnType.Type.IsNonGenericTaskType(compilation) && + !returnType.Type.IsGenericTaskType(compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index 49b5dbca5e72..a138883fe13b 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -40,7 +40,7 @@ public static BoundBlock Rewrite( #endif var compilation = method.DeclaringCompilation; - if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _)) + if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 3acb6ac25fd5..62e4c9f9f911 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2542,7 +2542,7 @@ private bool TryGetReturnType(out TypeWithAnnotations type, out FlowAnalysisAnno return true; } - if (method.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) + if (returnType.Type.IsGenericTaskType(compilation)) { type = ((NamedTypeSymbol)returnType.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single(); annotations = FlowAnalysisAnnotations.None; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index e4e9759c428e..e4824642173f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -178,39 +178,36 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - object methodLevelBuilder = null; - if (method.IsAsyncEffectivelyReturningTask(F.Compilation, out methodLevelBuilder)) + if (method.IsAsyncReturningTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool customBuilder; - if ((object)methodLevelBuilder != null) + object builderArgument; + bool customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); - customBuilder = true; - if ((object)initialBuilderType != null) + if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); + if ((object)initialBuilderType != null) { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) + { + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + } + } + else + { + builderType = null; } } else - { - builderType = null; - } - } - else - { - object builderArgument; - customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); if ((object)builderType != null) @@ -219,25 +216,24 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); - Debug.Assert((object)builderType != null); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, - builderType, - customBuilder, - out taskProperty); - } } - + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); + Debug.Assert((object)builderType != null); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, + builderType, + customBuilder, + out taskProperty); + } if ((object)builderType == null || (object)createBuilderMethod == null || (object)taskProperty == null) @@ -245,7 +241,6 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } - return TryCreate( F, customBuilder: customBuilder, @@ -262,7 +257,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, out methodLevelBuilder)) + if (method.IsAsyncReturningGenericTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; @@ -278,33 +273,32 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool customBuilder; - if ((object)methodLevelBuilder != null) + object builderArgument; + bool customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); - customBuilder = true; - if ((object)initialBuilderType != null) + if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) + builderArgument = methodLevelBuilder; + var initialBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); + if ((object)initialBuilderType != null) { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) + { + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + } + } + else + { + builderType = null; } } else - { - builderType = null; - } - } - else - { - object builderArgument; - customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); if ((object)builderType != null) @@ -314,26 +308,25 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); - Debug.Assert((object)builderType != null); - builderType = builderType.Construct(resultType); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, - builderType, - customBuilder, - out taskProperty); - } } - + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); + Debug.Assert((object)builderType != null); + builderType = builderType.Construct(resultType); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, + builderType, + customBuilder, + out taskProperty); + } if ((object)builderType == null || (object)taskProperty == null || (object)createBuilderMethod == null) @@ -341,7 +334,6 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } - return TryCreate( F, customBuilder: customBuilder, diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index 768b3d612a17..d0a1e0d94bdf 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -85,7 +85,7 @@ internal AsyncMethodToStateMachineRewriter( _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); - _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) + _exprRetValue = method.IsAsyncReturningGenericTask(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; @@ -208,7 +208,7 @@ protected virtual BoundStatement GenerateSetResultCall() F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, - _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) + _method.IsAsyncReturningGenericTask(F.Compilation) ? ImmutableArray.Create(F.Local(_exprRetValue)) : ImmutableArray.Empty)); } @@ -623,7 +623,7 @@ public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { - Debug.Assert(_method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _)); + Debug.Assert(_method.IsAsyncReturningGenericTask(F.Compilation)); return F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel)); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index d54c71912bac..c2a8f980d422 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -147,7 +147,6 @@ private static bool CanBeHiddenByMethodPropertyOrType(MethodSymbol method) } } -#nullable enable /// /// Returns whether this method is async and returns void. /// @@ -157,25 +156,21 @@ public static bool IsAsyncReturningVoid(this MethodSymbol method) } /// - /// Returns whether this method is async and returns a task, task-like, or other type with a method-level builder. + /// Returns whether this method is async and returns a task. /// - public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) + public static bool IsAsyncReturningTask(this MethodSymbol method, CSharpCompilation compilation) { - builderOverride = null; return method.IsAsync - && method.ReturnType is NamedTypeSymbol { Arity: 0 } - && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); + && method.ReturnType.IsNonGenericTaskType(compilation); } /// - /// Returns whether this method is async and returns a generic task, task-like, or other type with a method-level builder. + /// Returns whether this method is async and returns a generic task. /// - public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) + public static bool IsAsyncReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation) { - builderOverride = null; return method.IsAsync - && method.ReturnType is NamedTypeSymbol { Arity: 1 } - && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); + && method.ReturnType.IsGenericTaskType(compilation); } /// @@ -196,11 +191,12 @@ public static bool IsAsyncReturningIAsyncEnumerator(this MethodSymbol method, CS && method.ReturnType.IsIAsyncEnumeratorType(compilation); } +#nullable enable /// /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. /// - internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderOverride) + internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) { Debug.Assert(method is not null); @@ -211,12 +207,12 @@ internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhe && attr.CommonConstructorArguments.Length == 1 && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) { - builderOverride = attr.CommonConstructorArguments[0].ValueInternal!; + builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; return true; } } - builderOverride = null; + builderArgument = null; return false; } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 12c1e2387083..a62a5915fb06 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1050,7 +1050,7 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) ReportBadRefToken(returnTypeSyntax, diagnostics); hasErrors = true; } - else if (isBadAsyncReturn(this)) + else if (ReturnType.IsBadAsyncReturn(this.DeclaringCompilation)) { diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, errorLocation); hasErrors = true; @@ -1104,18 +1104,6 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) } } } - - static bool isBadAsyncReturn(MethodSymbol methodSymbol) - { - var returnType = methodSymbol.ReturnType; - var declaringCompilation = methodSymbol.DeclaringCompilation; - return !returnType.IsErrorType() && - !returnType.IsVoidType() && - !returnType.IsIAsyncEnumerableType(declaringCompilation) && - !returnType.IsIAsyncEnumeratorType(declaringCompilation) && - !methodSymbol.IsAsyncEffectivelyReturningTask(declaringCompilation, builderOverride: out _) && - !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation, builderOverride: out _); - } } private static FlowAnalysisAnnotations DecodeReturnTypeAnnotationAttributes(ReturnTypeWellKnownAttributeData attributeData) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index ad6fd80d3a77..f9a522417a58 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1929,6 +1929,17 @@ private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string ou return globalNamespace != null && globalNamespace.IsGlobalNamespace; } + public static bool IsBadAsyncReturn(this TypeSymbol returnType, CSharpCompilation declaringCompilation) + { + // Note: we're passing the return type explicitly (rather than using `method.ReturnType`) to avoid cycles + return !returnType.IsErrorType() && + !returnType.IsVoidType() && + !returnType.IsNonGenericTaskType(declaringCompilation) && + !returnType.IsGenericTaskType(declaringCompilation) && + !returnType.IsIAsyncEnumerableType(declaringCompilation) && + !returnType.IsIAsyncEnumeratorType(declaringCompilation); + } + internal static int TypeToIndex(this TypeSymbol type) { switch (type.GetSpecialTypeSafe()) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 596f0f27e466..7ad7bb79558c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -156,10 +156,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @" { // Code size 45 (0x2d) @@ -241,7 +241,20 @@ class C {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); + compilation.VerifyEmitDiagnostics( + // (11,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(11, 25), + // (11,25): error CS0161: 'C.F()': not all code paths return a value + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(11, 25), + // (14,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(14, 28), + // (17,37): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(17, 37) + ); } [Fact] @@ -284,14 +297,18 @@ public static async MyTask M() {AsyncMethodBuilderAttribute} "; + // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( - // (14,16): warning CS8603: Possible null reference return. - // return default(T); // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default(T)").WithLocation(14, 16), - // (20,16): warning CS8603: Possible null reference return. - // return await G((string?)null); // 2 - Diagnostic(ErrorCode.WRN_NullReferenceReturn, "await G((string?)null)").WithLocation(20, 16), + // (11,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(11, 28), + // (18,40): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(18, 40), + // (24,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M2() { return await G((string?)null); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(24, 41), // (44,16): warning CS8618: Non-nullable field '_result' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // internal T _result; Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "_result").WithArguments("field", "_result").WithLocation(44, 16) @@ -337,21 +354,24 @@ class C "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (9,51): error CS1997: Since 'C.F()' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task'? + // (9,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask F() { await Task.Yield(); return 1; } // 1 - Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequired, "return").WithArguments("C.F()").WithLocation(9, 51), - // (12,60): error CS0126: An object of a type convertible to 'T' is required + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(9, 25), + // (12,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { await Task.Yield(); return; } // 2 + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(12, 28), + // (12,60): error CS0126: An object of a type convertible to 'MyTask' is required // static async MyTask G(T t) { await Task.Yield(); return; } // 2 - Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("T").WithLocation(12, 60), - // (15,63): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type + Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("MyTask").WithLocation(12, 60), + // (15,30): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask M() { await Task.Yield(); return null; } // 3 - Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(15, 63), - // (18,78): error CS4016: Since this is an async method, the return expression must be of type 'int' rather than 'Task' + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(15, 30), + // (18,30): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask M2(MyTask mt) { await Task.Yield(); return mt; } // 4 - Diagnostic(ErrorCode.ERR_BadAsyncReturnExpression, "mt").WithArguments("int").WithLocation(18, 78), - // (21,39): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(18, 30), + // (21,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask M2(bool b) => b ? await Task.Yield() : await Task.Yield(); // 5 - Diagnostic(ErrorCode.ERR_IllegalStatement, "b ? await Task.Yield() : await Task.Yield()").WithLocation(21, 39) + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(21, 25) ); } @@ -576,10 +596,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); // The initial builder type is used for Create() invocation verifier.VerifyIL("C.F()", @" @@ -894,9 +914,65 @@ public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; + // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); - verifier.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (6,91): error CS1643: Not all code paths return a value in lambda expression of type 'Func' + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(6, 91), + // (8,91): error CS4010: Cannot convert async lambda expression to delegate type 'Func>'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func>'. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(8, 91) + ); + } + + [Fact] + public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} +); + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} +); + +await Task.Delay(0); +return; + +public class C +{{ + public static void F(Func f) {{ System.Console.Write(""Overload1 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload2 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload3 ""); f().GetAwaiter().GetResult(); }} +}} + +// no attribute +{AwaitableTypeCode("MyTask", isStruct: true)} + +// no attribute +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + // Even if we allowed async lambdas to return non-task-like types, there would be an issue to be worked out + // with type inference + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (7,78): error CS1643: Not all code paths return a value in lambda expression of type 'Func' + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(7, 78), + // (11,80): error CS4010: Cannot convert async lambda expression to delegate type 'Func'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func'. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } + Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func").WithLocation(11, 80) + ); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 34fbbf6a8a0f..83b44e34e8f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -434,11 +434,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +515,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +594,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From 869671b4313bca9d6fe9f770a6b7dbb60c5406d0 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 17 Jun 2021 20:07:44 -0700 Subject: [PATCH 09/24] Validate ignored builder type --- .../AsyncMethodBuilderMemberCollection.cs | 41 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 409 +++++++++++++++--- 2 files changed, 379 insertions(+), 71 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index e4824642173f..8d326d92338f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -200,6 +200,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if ((object)builderType != null) { taskProperty = GetCustomTaskProperty(F, builderType, returnType); + validateIgnoredBuilderType(F, returnType, builderArgument, isGeneric: false); } } else @@ -280,8 +281,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, { if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) { - builderArgument = methodLevelBuilder; - var initialBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); if ((object)initialBuilderType != null) { // We only get the Create method from the initial builder type, then we'll use its return type as builder type @@ -291,6 +291,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if ((object)builderType != null) { taskProperty = GetCustomTaskProperty(F, builderType, returnType); + validateIgnoredBuilderType(F, returnType, builderArgument, isGeneric: true); } } else @@ -351,6 +352,42 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, } throw ExceptionUtilities.UnexpectedValue(method); + + void validateIgnoredBuilderType(SyntheticBoundNodeFactory F, NamedTypeSymbol returnType, object builderArgument, bool isGeneric) + { + var ignoredBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric); + + if ((object)ignoredBuilderType != null) + { + if (isGeneric) + { + var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; + ignoredBuilderType = ignoredBuilderType.ConstructedFrom.Construct(resultType); + } + + GetCustomCreateMethod(F, ignoredBuilderType, forOverride: false); + GetCustomTaskProperty(F, ignoredBuilderType, returnType); + + _ = TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetException : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetException, + ignoredBuilderType, customBuilder: true, out MethodSymbol _) && + TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetResult : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetResult, + ignoredBuilderType, customBuilder: true, out MethodSymbol _) && + TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitOnCompleted, + ignoredBuilderType, customBuilder: true, out MethodSymbol _) && + TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitUnsafeOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitUnsafeOnCompleted, + ignoredBuilderType, customBuilder: true, out MethodSymbol _) && + TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Start_T : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Start_T, + ignoredBuilderType, customBuilder: true, out MethodSymbol _) && + TryGetBuilderMember(F, + isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetStateMachine : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetStateMachine, + ignoredBuilderType, customBuilder: true, out MethodSymbol _); + } + } } private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric, bool forOverride = false) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 7ad7bb79558c..fc9f6e393e05 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -101,11 +101,8 @@ public void OnCompleted(Action a) {{ }} } } - [Theory] - [InlineData("typeof(MyTaskMethodBuilder)")] - [InlineData("typeof(object)")] - [InlineData("null")] - public void BuilderOnMethod_DummyBuilderOnType(string dummyBuilder) + [Fact] + public void BuilderOnMethod() { var source = $@" using System; @@ -126,14 +123,16 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder({dummyBuilder})] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder({dummyBuilder})] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; @@ -258,7 +257,7 @@ class C } [Fact] - public void BuilderOnMethod_NoBuilderOnType_Nullability() + public void BuilderOnMethod_Nullability() { var source = $@" #nullable enable @@ -286,29 +285,29 @@ public static async MyTask M() public static async MyTask M2() {{ return await G((string?)null); }} }} -// no attribute +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -// no attribute +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} +#nullable disable +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} + {AsyncMethodBuilderAttribute} "; - // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( - // (11,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(11, 28), - // (18,40): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M() - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(18, 40), - // (24,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M2() { return await G((string?)null); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(24, 41), + // (14,16): warning CS8603: Possible null reference return. + // return default(T); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default(T)").WithLocation(14, 16), + // (20,16): warning CS8603: Possible null reference return. + // return await G((string?)null); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "await G((string?)null)").WithLocation(20, 16), // (44,16): warning CS8618: Non-nullable field '_result' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // internal T _result; Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "_result").WithArguments("field", "_result").WithLocation(44, 16) @@ -375,11 +374,238 @@ class C ); } - [Theory] - [InlineData("typeof(MyTaskMethodBuilder)")] - [InlineData("typeof(object)")] - [InlineData("null")] - public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuilder) + [Fact] + public void BuilderOnMethod_BadBuilderOnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(typeof(void))] // void +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] // wrong arity +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (11,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(11, 29), + // (14,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(14, 38), + // (17,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(17, 41) + ); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_CreateReturnsInt() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "Create").WithLocation(9, 29), + // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "Create").WithLocation(12, 38) + ); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_TaskPropertyReturnsInt() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public MyTask Task => _task;", "public int Task => 0;")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public MyTask Task => _task;", "public int Task => 0;")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS8204: For type 'IgnoredTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'int'. + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "MyTask", "int").WithLocation(9, 29), + // (12,38): error CS8204: For type 'IgnoredTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'int'. + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "MyTask", "int").WithLocation(12, 38) + ); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_SetExceptionIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public void SetException", "internal void SetException") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetException", "internal void SetException") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetException' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "SetException").WithLocation(9, 29), + // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetException' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "SetException").WithLocation(12, 38) + ); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_SetResultIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetResult' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "SetResult").WithLocation(9, 29), + // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetResult' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "SetResult").WithLocation(12, 38) + ); + } + + [Fact] + public void BuilderOnMethod_OnLocalFunction() { var source = $@" using System; @@ -397,18 +623,19 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -[AsyncMethodBuilder({dummyBuilder})] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder({dummyBuilder})] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; - source = source.Replace("DUMMY_BUILDER", dummyBuilder); var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (9,21): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -580,14 +807,16 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -842,14 +1071,16 @@ public void BuilderFactoryOnMethod_OnLambda() Console.WriteLine(await m()); return; -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask", isStruct: true)} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -994,14 +1225,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task", "public object Task")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1316,14 +1549,16 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1355,12 +1590,14 @@ class C {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1435,14 +1672,16 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} namespace System.Runtime.CompilerServices {{ @@ -1631,14 +1870,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1664,14 +1905,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task =>", "internal MyTask Task =>")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1707,14 +1950,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1750,14 +1995,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task = null;")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1793,14 +2040,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException", "internal void SetException")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1836,10 +2085,10 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") @@ -1848,6 +2097,8 @@ class C {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1883,14 +2134,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException(Exception e)", "public void SetException()")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(Exception e)", "public void SetException()")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1926,14 +2179,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetResult", "internal void SetResult")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1969,14 +2224,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2012,14 +2269,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2055,14 +2314,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void Start", "internal void Start")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2098,14 +2359,16 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(null)] +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetStateMachine", "internal void SetStateMachine")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2268,10 +2531,10 @@ public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilderMembers() using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(null)] public class T1 {{ }} -[AsyncMethodBuilder(null)] public class T2 {{ }} -[AsyncMethodBuilder(null)] internal class T3 {{ }} -[AsyncMethodBuilder(null)] internal class T4 {{ }} +[AsyncMethodBuilder(typeof(IgnoredBuilder1))] public class T1 {{ }} +[AsyncMethodBuilder(typeof(IgnoredBuilder2))] public class T2 {{ }} +[AsyncMethodBuilder(typeof(IgnoredBuilder3))] internal class T3 {{ }} +[AsyncMethodBuilder(typeof(IgnoredBuilder4))] internal class T4 {{ }} {AsyncBuilderFactoryCode("B1", "T1")} @@ -2303,6 +2566,10 @@ class Program async T4 f4() => await Task.Delay(4); }} +{AsyncBuilderCode("IgnoredBuilder1", "T1")} +{AsyncBuilderCode("IgnoredBuilder2", "T2")} +{AsyncBuilderCode("IgnoredBuilder3", "T3").Replace("public class IgnoredBuilder3", "internal class IgnoredBuilder3").Replace("public T3 Task", "internal T3 Task")} +{AsyncBuilderCode("IgnoredBuilder4", "T4").Replace("public T4 Task", "internal T4 Task")} {AsyncMethodBuilderAttribute} "; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); @@ -2313,6 +2580,9 @@ class Program // (100,19): error CS0656: Missing compiler required member 'B3.Task' // async T3 f3() => await Task.Delay(3); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("B3", "Task").WithLocation(100, 19), + // (100,19): error CS0656: Missing compiler required member 'IgnoredBuilder3.Task' + // async T3 f3() => await Task.Delay(3); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("IgnoredBuilder3", "Task").WithLocation(100, 19), // (103,19): error CS0656: Missing compiler required member 'B4Factory.Create' // async T4 f4() => await Task.Delay(4); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(4)").WithArguments("B4Factory", "Create").WithLocation(103, 19) @@ -2327,7 +2597,7 @@ public void BuilderFactoryOnMethod_InternalReturnType() using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(null)] internal class MyTaskType {{ }} +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] internal class MyTaskType {{ }} // Make the builder factory and the builder internal as well {AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } @@ -2338,6 +2608,7 @@ class C async MyTaskType M() => await Task.Delay(4); }} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTaskType").Replace("public class IgnoredTaskMethodBuilder", "internal class IgnoredTaskMethodBuilder")} {AsyncMethodBuilderAttribute} "; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); From 22b537326e0f8b27c0639f98f89d19ba1402167d Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 18 Jun 2021 09:34:55 -0700 Subject: [PATCH 10/24] use TryCreate --- .../AsyncMethodBuilderMemberCollection.cs | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index 8d326d92338f..d793d2d90522 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -365,27 +365,23 @@ void validateIgnoredBuilderType(SyntheticBoundNodeFactory F, NamedTypeSymbol ret ignoredBuilderType = ignoredBuilderType.ConstructedFrom.Construct(resultType); } - GetCustomCreateMethod(F, ignoredBuilderType, forOverride: false); - GetCustomTaskProperty(F, ignoredBuilderType, returnType); - - _ = TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetException : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetException, - ignoredBuilderType, customBuilder: true, out MethodSymbol _) && - TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetResult : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetResult, - ignoredBuilderType, customBuilder: true, out MethodSymbol _) && - TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitOnCompleted, - ignoredBuilderType, customBuilder: true, out MethodSymbol _) && - TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitUnsafeOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitUnsafeOnCompleted, - ignoredBuilderType, customBuilder: true, out MethodSymbol _) && - TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Start_T : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Start_T, - ignoredBuilderType, customBuilder: true, out MethodSymbol _) && - TryGetBuilderMember(F, - isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetStateMachine : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetStateMachine, - ignoredBuilderType, customBuilder: true, out MethodSymbol _); + var createMethod = GetCustomCreateMethod(F, ignoredBuilderType, forOverride: false); + var taskProperty = GetCustomTaskProperty(F, ignoredBuilderType, returnType); + + _ = TryCreate( + F, + customBuilder: true, + builderType: ignoredBuilderType, + resultType: null, // unused + createBuilderMethod: createMethod, + taskProperty: taskProperty, + setException: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetException : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetException, + setResult: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetResult : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetResult, + awaitOnCompleted: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitOnCompleted, + awaitUnsafeOnCompleted: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitUnsafeOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitUnsafeOnCompleted, + start: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Start_T : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Start_T, + setStateMachine: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetStateMachine : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetStateMachine, + collection: out _); } } } From 2e7ad79c6bb34f8cc661c153ed4726c36ecc7006 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Sun, 20 Jun 2021 22:09:25 -0700 Subject: [PATCH 11/24] hasErros --- .../SourceMethodSymbolWithAttributes.cs | 2 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index a62a5915fb06..d85712a0466e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1058,7 +1058,7 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) if (this.HasMethodLevelBuilder(out _)) { - hasErrors = MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); + hasErrors |= MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); } for (NamedTypeSymbol curr = this.ContainingType; (object)curr != null; curr = curr.ContainingType) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index fc9f6e393e05..628ea31233c0 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -2614,5 +2614,34 @@ class C var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyEmitDiagnostics(); } + + [Fact] + public void BuilderFactoryOnMethod_IntReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] public class MyTaskType {{ }} + +{AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType")} + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskTypeBuilderFactory))] + async int M() => await Task.Delay(4); +}} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTaskType")} +{AsyncMethodBuilderAttribute} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyEmitDiagnostics( + // (31,15): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // async int M() => await Task.Delay(4); + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(31, 15) + ); + } } } From 4375aea24d14b7bcdbf6914d689465d5c97c5bc3 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 09:48:54 -0700 Subject: [PATCH 12/24] Factor extension method --- .../AsyncMethodBuilderMemberCollection.cs | 4 +-- .../Symbols/MethodSymbolExtensions.cs | 26 ------------------- .../SourceMethodSymbolWithAttributes.cs | 2 +- .../Portable/Symbols/SymbolExtensions.cs | 24 +++++++++++++++++ .../Portable/Symbols/TypeSymbolExtensions.cs | 12 +-------- 5 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index d793d2d90522..3ec31e55226c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -189,7 +189,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { - if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) + if (method.HasAsyncMethodBuilder(out var methodLevelBuilder)) { var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); if ((object)initialBuilderType != null) @@ -279,7 +279,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { - if (method.HasMethodLevelBuilder(out var methodLevelBuilder)) + if (method.HasAsyncMethodBuilder(out var methodLevelBuilder)) { var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); if ((object)initialBuilderType != null) diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index c2a8f980d422..a45b2a34b1c2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -191,32 +191,6 @@ public static bool IsAsyncReturningIAsyncEnumerator(this MethodSymbol method, CS && method.ReturnType.IsIAsyncEnumeratorType(compilation); } -#nullable enable - /// - /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". - /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. - /// - internal static bool HasMethodLevelBuilder(this MethodSymbol method, [NotNullWhen(true)] out object? builderArgument) - { - Debug.Assert(method is not null); - - // Find the AsyncMethodBuilder attribute. - foreach (var attr in method.GetAttributes()) - { - if (attr.IsTargetAttribute(method, AttributeDescription.AsyncMethodBuilderAttribute) - && attr.CommonConstructorArguments.Length == 1 - && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) - { - builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; - return true; - } - } - - builderArgument = null; - return false; - } -#nullable disable - internal static CSharpSyntaxNode ExtractReturnTypeSyntax(this MethodSymbol method) { if (method is SynthesizedSimpleProgramEntryPointSymbol synthesized) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index d85712a0466e..fbac01d59ca5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1056,7 +1056,7 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) hasErrors = true; } - if (this.HasMethodLevelBuilder(out _)) + if (this.HasAsyncMethodBuilder(out _)) { hasErrors |= MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); } diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs index eb072757a2b2..904eb8e239c3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs @@ -815,5 +815,29 @@ internal static ImmutableArray GetPublicSymbols(this Immutable { return symbol.GetSymbol(); } + + /// + /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". + /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. + /// + internal static bool HasAsyncMethodBuilder(this Symbol symbol, [NotNullWhen(true)] out object? builderArgument) + { + Debug.Assert(symbol is not null); + + // Find the AsyncMethodBuilder attribute. + foreach (var attr in symbol.GetAttributes()) + { + if (attr.IsTargetAttribute(symbol, AttributeDescription.AsyncMethodBuilderAttribute) + && attr.CommonConstructorArguments.Length == 1 + && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) + { + builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; + return true; + } + } + + builderArgument = null; + return false; + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 4fbe82d945bc..ed727ef87fea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1647,17 +1647,7 @@ internal static bool IsCustomTaskType(this NamedTypeSymbol type, [NotNullWhen(tr var arity = type.Arity; if (arity < 2) { - // Find the AsyncMethodBuilder attribute. - foreach (var attr in type.GetAttributes()) - { - if (attr.IsTargetAttribute(type, AttributeDescription.AsyncMethodBuilderAttribute) - && attr.CommonConstructorArguments.Length == 1 - && attr.CommonConstructorArguments[0].Kind == TypedConstantKind.Type) - { - builderArgument = attr.CommonConstructorArguments[0].ValueInternal!; - return true; - } - } + return type.HasAsyncMethodBuilder(out builderArgument); } builderArgument = null; From 43416a2d462b80020a04ba13be0e8da4adfea5ad Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 09:54:03 -0700 Subject: [PATCH 13/24] using --- src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index a45b2a34b1c2..6ff5ef7702a8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -12,7 +12,6 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.CSharp.Symbols { From d5c0a275a6d8b6d9bcc2d782385ac4d4941c522a Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 11:58:22 -0700 Subject: [PATCH 14/24] Revert "Disallow non-task-like return type after all" This reverts commit 2a3fdf149e01ad855ef822442548d5239ae19cfc. --- .../Portable/Binder/Binder_Expressions.cs | 16 +- .../Portable/Binder/Binder_Statements.cs | 21 +-- .../Portable/BoundTree/UnboundLambda.cs | 21 +-- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../Portable/FlowAnalysis/NullableWalker.cs | 2 +- .../AsyncMethodBuilderMemberCollection.cs | 155 +++++++++--------- .../AsyncMethodToStateMachineRewriter.cs | 6 +- .../Symbols/MethodSymbolExtensions.cs | 17 +- .../SourceMethodSymbolWithAttributes.cs | 14 +- .../Portable/Symbols/TypeSymbolExtensions.cs | 11 -- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 106 ++---------- .../BindingAsyncTasklikeMoreTests.cs | 16 +- 12 files changed, 156 insertions(+), 231 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 46158af25f76..5e7c110acfe1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8638,15 +8638,15 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess break; case SyntaxKind.SimpleLambdaExpression: - resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((SimpleLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ParenthesizedLambdaExpression: - resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((ParenthesizedLambdaExpressionSyntax)parent).Body != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ArrowExpressionClause: - resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || ContainingMethodOrLambdaRequiresValue(); + resultIsUsed = (((ArrowExpressionClauseSyntax)parent).Expression != node) || MethodOrLambdaRequiresValue(ContainingMemberOrLambda, Compilation); break; case SyntaxKind.ForStatement: @@ -8676,13 +8676,11 @@ private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccess return new BoundConditionalAccess(node, receiver, access, accessType); } - private bool ContainingMethodOrLambdaRequiresValue() + internal static bool MethodOrLambdaRequiresValue(Symbol symbol, CSharpCompilation compilation) { - var containingMethod = ContainingMemberOrLambda as MethodSymbol; - return - (object)containingMethod == null || - !containingMethod.ReturnsVoid && - !containingMethod.IsAsyncReturningTask(this.Compilation); + return symbol is MethodSymbol method && + !method.ReturnsVoid && + !method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index fa6b2ce3d8c8..5cd612f0190f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -623,7 +623,7 @@ BoundBlock runAnalysis(BoundBlock block, BindingDiagnosticBag blockDiagnostics) private bool ImplicitReturnIsOkay(MethodSymbol method) { - return method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(this.Compilation); + return method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2647,16 +2647,16 @@ protected bool IsInAsyncMethod() return IsInAsyncMethod(this.ContainingMemberOrLambda as MethodSymbol); } - protected bool IsTaskReturningAsyncMethod() + protected bool IsEffectivelyTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningTask(this.Compilation); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); } - protected bool IsGenericTaskReturningAsyncMethod() + protected bool IsEffectivelyGenericTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncReturningGenericTask(this.Compilation); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningGenericTask(this.Compilation, builderOverride: out _); } protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() @@ -2759,7 +2759,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti // on a lambda expression of unknown return type. if ((object)retType != null) { - if (retType.IsVoidType() || IsTaskReturningAsyncMethod()) + if (retType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) { if (arg != null) { @@ -2799,7 +2799,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti if (arg == null) { // Error case: non-void-returning or Task-returning method or lambda but just have "return;" - var requiredType = IsGenericTaskReturningAsyncMethod() + var requiredType = IsEffectivelyGenericTaskReturningAsyncMethod() ? retType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single() : retType; @@ -2842,7 +2842,7 @@ internal BoundExpression CreateReturnConversion( { Debug.Assert(returnRefKind == RefKind.None); - if (!IsGenericTaskReturningAsyncMethod()) + if (!IsEffectivelyGenericTaskReturningAsyncMethod()) { conversion = Conversion.NoConversion; badAsyncReturnAlreadyReported = true; @@ -2879,7 +2879,8 @@ internal BoundExpression CreateReturnConversion( if (!badAsyncReturnAlreadyReported) { RefKind unusedRefKind; - if (IsGenericTaskReturningAsyncMethod() && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) + if (IsEffectivelyGenericTaskReturningAsyncMethod() + && TypeSymbol.Equals(argument.Type, this.GetCurrentReturnType(out unusedRefKind), TypeCompareKind.ConsiderEverything2)) { // Since this is an async method, the return expression must be of type '{0}' rather than 'Task<{0}>' Error(diagnostics, ErrorCode.ERR_BadAsyncReturnExpression, argument.Syntax, returnType); @@ -3168,7 +3169,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr expression = BindToTypeForErrorRecovery(expression); statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true }; } - else if (returnType.IsVoidType() || IsTaskReturningAsyncMethod()) + else if (returnType.IsVoidType() || IsEffectivelyTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 7f03fb6cb86a..56331d7c1d52 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -556,21 +556,6 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo return invokeMethod.ReturnTypeWithAnnotations; } - private bool DelegateNeedsReturn(MethodSymbol? invokeMethod) - { - if (invokeMethod is null || invokeMethod.ReturnsVoid) - { - return false; - } - - if (IsAsync && invokeMethod.ReturnType.IsNonGenericTaskType(this.Binder.Compilation)) - { - return false; - } - - return true; - } - internal NamedTypeSymbol? InferDelegateType(ref CompoundUseSiteInfo useSiteInfo) { Debug.Assert(Binder.ContainingMemberOrLambda is { }); @@ -692,7 +677,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) bool reachableEndpoint = ControlFlowPass.Analyze(compilation, lambdaSymbol, block, diagnostics.DiagnosticBag); if (reachableEndpoint) { - if (DelegateNeedsReturn(invokeMethod)) + if (Binder.MethodOrLambdaRequiresValue(lambdaSymbol, this.Binder.Compilation)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.DiagnosticLocation, this.MessageID.Localize(), delegateType); @@ -707,8 +692,8 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { if (returnType.HasType && // Can be null if "delegateType" is not actually a delegate type. !returnType.IsVoidType() && - !returnType.Type.IsNonGenericTaskType(compilation) && - !returnType.Type.IsGenericTaskType(compilation)) + !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _) && + !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index a138883fe13b..49b5dbca5e72 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -40,7 +40,7 @@ public static BoundBlock Rewrite( #endif var compilation = method.DeclaringCompilation; - if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation)) + if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 62e4c9f9f911..3acb6ac25fd5 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2542,7 +2542,7 @@ private bool TryGetReturnType(out TypeWithAnnotations type, out FlowAnalysisAnno return true; } - if (returnType.Type.IsGenericTaskType(compilation)) + if (method.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) { type = ((NamedTypeSymbol)returnType.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single(); annotations = FlowAnalysisAnnotations.None; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index 3ec31e55226c..6d4350d3ef7c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -178,37 +178,39 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningTask(F.Compilation)) + object methodLevelBuilder = null; + if (method.IsAsyncEffectivelyReturningTask(F.Compilation, out methodLevelBuilder)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool customBuilder; - object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) + if ((object)methodLevelBuilder != null) { - if (method.HasAsyncMethodBuilder(out var methodLevelBuilder)) + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); + customBuilder = true; + if ((object)initialBuilderType != null) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - validateIgnoredBuilderType(F, returnType, builderArgument, isGeneric: false); - } - } - else + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) { - builderType = null; + taskProperty = GetCustomTaskProperty(F, builderType, returnType); } } else + { + builderType = null; + } + } + else + { + object builderArgument; + customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); if ((object)builderType != null) @@ -217,24 +219,25 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); + Debug.Assert((object)builderType != null); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, + builderType, + customBuilder, + out taskProperty); + } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); - Debug.Assert((object)builderType != null); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, - builderType, - customBuilder, - out taskProperty); - } + if ((object)builderType == null || (object)createBuilderMethod == null || (object)taskProperty == null) @@ -242,6 +245,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, @@ -258,7 +262,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningGenericTask(F.Compilation)) + if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, out methodLevelBuilder)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; @@ -274,32 +278,33 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool customBuilder; - object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) + if ((object)methodLevelBuilder != null) { - if (method.HasAsyncMethodBuilder(out var methodLevelBuilder)) + var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); + customBuilder = true; + if ((object)initialBuilderType != null) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - validateIgnoredBuilderType(F, returnType, builderArgument, isGeneric: true); - } - } - else + // We only get the Create method from the initial builder type, then we'll use its return type as builder type + initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); + createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); + builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; + if ((object)builderType != null) { - builderType = null; + taskProperty = GetCustomTaskProperty(F, builderType, returnType); } } else + { + builderType = null; + } + } + else + { + object builderArgument; + customBuilder = returnType.IsCustomTaskType(out builderArgument); + if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); if ((object)builderType != null) @@ -309,25 +314,26 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); + Debug.Assert((object)builderType != null); + builderType = builderType.Construct(resultType); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, + builderType, + customBuilder, + out taskProperty); + } } - else - { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); - Debug.Assert((object)builderType != null); - builderType = builderType.Construct(resultType); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, - builderType, - customBuilder, - out taskProperty); - } + if ((object)builderType == null || (object)taskProperty == null || (object)createBuilderMethod == null) @@ -335,6 +341,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index d0a1e0d94bdf..768b3d612a17 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -85,7 +85,7 @@ internal AsyncMethodToStateMachineRewriter( _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); - _exprRetValue = method.IsAsyncReturningGenericTask(F.Compilation) + _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; @@ -208,7 +208,7 @@ protected virtual BoundStatement GenerateSetResultCall() F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, - _method.IsAsyncReturningGenericTask(F.Compilation) + _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) ? ImmutableArray.Create(F.Local(_exprRetValue)) : ImmutableArray.Empty)); } @@ -623,7 +623,7 @@ public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { - Debug.Assert(_method.IsAsyncReturningGenericTask(F.Compilation)); + Debug.Assert(_method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _)); return F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel)); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index 6ff5ef7702a8..857db7a336fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -146,6 +146,7 @@ private static bool CanBeHiddenByMethodPropertyOrType(MethodSymbol method) } } +#nullable enable /// /// Returns whether this method is async and returns void. /// @@ -155,21 +156,25 @@ public static bool IsAsyncReturningVoid(this MethodSymbol method) } /// - /// Returns whether this method is async and returns a task. + /// Returns whether this method is async and returns a task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncReturningTask(this MethodSymbol method, CSharpCompilation compilation) + public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) { + builderOverride = null; return method.IsAsync - && method.ReturnType.IsNonGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 0 } + && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); } /// - /// Returns whether this method is async and returns a generic task. + /// Returns whether this method is async and returns a generic task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation) + public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) { + builderOverride = null; return method.IsAsync - && method.ReturnType.IsGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 1 } + && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index fbac01d59ca5..e6ba0e13d70b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1050,7 +1050,7 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) ReportBadRefToken(returnTypeSyntax, diagnostics); hasErrors = true; } - else if (ReturnType.IsBadAsyncReturn(this.DeclaringCompilation)) + else if (isBadAsyncReturn(this)) { diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, errorLocation); hasErrors = true; @@ -1104,6 +1104,18 @@ protected void AsyncMethodChecks(BindingDiagnosticBag diagnostics) } } } + + static bool isBadAsyncReturn(MethodSymbol methodSymbol) + { + var returnType = methodSymbol.ReturnType; + var declaringCompilation = methodSymbol.DeclaringCompilation; + return !returnType.IsErrorType() && + !returnType.IsVoidType() && + !returnType.IsIAsyncEnumerableType(declaringCompilation) && + !returnType.IsIAsyncEnumeratorType(declaringCompilation) && + !methodSymbol.IsAsyncEffectivelyReturningTask(declaringCompilation, builderOverride: out _) && + !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation, builderOverride: out _); + } } private static FlowAnalysisAnnotations DecodeReturnTypeAnnotationAttributes(ReturnTypeWellKnownAttributeData attributeData) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index ed727ef87fea..fb5952ed7be2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1928,17 +1928,6 @@ private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string ou return globalNamespace != null && globalNamespace.IsGlobalNamespace; } - public static bool IsBadAsyncReturn(this TypeSymbol returnType, CSharpCompilation declaringCompilation) - { - // Note: we're passing the return type explicitly (rather than using `method.ReturnType`) to avoid cycles - return !returnType.IsErrorType() && - !returnType.IsVoidType() && - !returnType.IsNonGenericTaskType(declaringCompilation) && - !returnType.IsGenericTaskType(declaringCompilation) && - !returnType.IsIAsyncEnumerableType(declaringCompilation) && - !returnType.IsIAsyncEnumeratorType(declaringCompilation); - } - internal static int TypeToIndex(this TypeSymbol type) { switch (type.GetSpecialTypeSafe()) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 628ea31233c0..a632a405a4da 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -155,10 +155,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); verifier.VerifyIL("C.F()", @" { // Code size 45 (0x2d) @@ -240,20 +240,7 @@ class C {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (11,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(11, 25), - // (11,25): error CS0161: 'C.F()': not all code paths return a value - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("C.F()").WithLocation(11, 25), - // (14,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(14, 28), - // (17,37): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(17, 37) - ); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); } [Fact] @@ -353,24 +340,21 @@ class C "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (9,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // (9,51): error CS1997: Since 'C.F()' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task'? // static async MyTask F() { await Task.Yield(); return 1; } // 1 - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(9, 25), - // (12,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { await Task.Yield(); return; } // 2 - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(12, 28), - // (12,60): error CS0126: An object of a type convertible to 'MyTask' is required + Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequired, "return").WithArguments("C.F()").WithLocation(9, 51), + // (12,60): error CS0126: An object of a type convertible to 'T' is required // static async MyTask G(T t) { await Task.Yield(); return; } // 2 - Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("MyTask").WithLocation(12, 60), - // (15,30): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("T").WithLocation(12, 60), + // (15,63): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // static async MyTask M() { await Task.Yield(); return null; } // 3 - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(15, 30), - // (18,30): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(15, 63), + // (18,78): error CS4016: Since this is an async method, the return expression must be of type 'int' rather than 'Task' // static async MyTask M2(MyTask mt) { await Task.Yield(); return mt; } // 4 - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(18, 30), - // (21,25): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + Diagnostic(ErrorCode.ERR_BadAsyncReturnExpression, "mt").WithArguments("int").WithLocation(18, 78), + // (21,39): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // static async MyTask M2(bool b) => b ? await Task.Yield() : await Task.Yield(); // 5 - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(21, 25) + Diagnostic(ErrorCode.ERR_IllegalStatement, "b ? await Task.Yield() : await Task.Yield()").WithLocation(21, 39) ); } @@ -825,10 +809,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); // The initial builder type is used for Create() invocation verifier.VerifyIL("C.F()", @" @@ -1145,65 +1129,9 @@ public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (6,91): error CS1643: Not all code paths return a value in lambda expression of type 'Func' - // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(6, 91), - // (8,91): error CS4010: Cannot convert async lambda expression to delegate type 'Func>'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func>'. - // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => { System.Console.Write("M "); await f(); return 3; }; - Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(8, 91) - ); - } - - [Fact] - public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} -); - -C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} -); - -await Task.Delay(0); -return; - -public class C -{{ - public static void F(Func f) {{ System.Console.Write(""Overload1 ""); f().GetAwaiter().GetResult(); }} - public static void F(Func> f) {{ System.Console.Write(""Overload2 ""); f().GetAwaiter().GetResult(); }} - public static void F(Func> f) {{ System.Console.Write(""Overload3 ""); f().GetAwaiter().GetResult(); }} -}} - -// no attribute -{AwaitableTypeCode("MyTask", isStruct: true)} - -// no attribute -{AwaitableTypeCode("MyTask", "T", isStruct: true)} - -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} -{AsyncMethodBuilderAttribute} -"; - // Even if we allowed async lambdas to return non-task-like types, there would be an issue to be worked out - // with type inference - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (7,78): error CS1643: Not all code paths return a value in lambda expression of type 'Func' - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(7, 78), - // (11,80): error CS4010: Cannot convert async lambda expression to delegate type 'Func'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func'. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } - Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func").WithLocation(11, 80) - ); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + verifier.VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 83b44e34e8f6..34fbbf6a8a0f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -434,11 +434,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +515,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +594,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From f7900d8ef6389480f3a453ef03a4b93332ae691c Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 11:59:41 -0700 Subject: [PATCH 15/24] Revert "Validate ignored builder type" This reverts commit 869671b4313bca9d6fe9f770a6b7dbb60c5406d0. --- .../AsyncMethodBuilderMemberCollection.cs | 32 -- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 409 +++--------------- 2 files changed, 69 insertions(+), 372 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index 6d4350d3ef7c..e4e9759c428e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -359,38 +359,6 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, } throw ExceptionUtilities.UnexpectedValue(method); - - void validateIgnoredBuilderType(SyntheticBoundNodeFactory F, NamedTypeSymbol returnType, object builderArgument, bool isGeneric) - { - var ignoredBuilderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric); - - if ((object)ignoredBuilderType != null) - { - if (isGeneric) - { - var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; - ignoredBuilderType = ignoredBuilderType.ConstructedFrom.Construct(resultType); - } - - var createMethod = GetCustomCreateMethod(F, ignoredBuilderType, forOverride: false); - var taskProperty = GetCustomTaskProperty(F, ignoredBuilderType, returnType); - - _ = TryCreate( - F, - customBuilder: true, - builderType: ignoredBuilderType, - resultType: null, // unused - createBuilderMethod: createMethod, - taskProperty: taskProperty, - setException: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetException : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetException, - setResult: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetResult : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetResult, - awaitOnCompleted: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitOnCompleted, - awaitUnsafeOnCompleted: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitUnsafeOnCompleted : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitUnsafeOnCompleted, - start: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Start_T : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Start_T, - setStateMachine: isGeneric ? WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetStateMachine : WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetStateMachine, - collection: out _); - } - } } private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric, bool forOverride = false) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index a632a405a4da..3669e7e93741 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -101,8 +101,11 @@ public void OnCompleted(Action a) {{ }} } } - [Fact] - public void BuilderOnMethod() + [Theory] + [InlineData("typeof(MyTaskMethodBuilder)")] + [InlineData("typeof(object)")] + [InlineData("null")] + public void BuilderOnMethod_DummyBuilderOnType(string dummyBuilder) { var source = $@" using System; @@ -123,16 +126,14 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder({dummyBuilder})] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder({dummyBuilder})] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; @@ -244,7 +245,7 @@ class C } [Fact] - public void BuilderOnMethod_Nullability() + public void BuilderOnMethod_NoBuilderOnType_Nullability() { var source = $@" #nullable enable @@ -272,29 +273,29 @@ public static async MyTask M() public static async MyTask M2() {{ return await G((string?)null); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +// no attribute {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +// no attribute {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} -#nullable disable -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} - {AsyncMethodBuilderAttribute} "; + // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( - // (14,16): warning CS8603: Possible null reference return. - // return default(T); // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default(T)").WithLocation(14, 16), - // (20,16): warning CS8603: Possible null reference return. - // return await G((string?)null); // 2 - Diagnostic(ErrorCode.WRN_NullReferenceReturn, "await G((string?)null)").WithLocation(20, 16), + // (11,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(11, 28), + // (18,40): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M() + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(18, 40), + // (24,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // public static async MyTask M2() { return await G((string?)null); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(24, 41), // (44,16): warning CS8618: Non-nullable field '_result' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // internal T _result; Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "_result").WithArguments("field", "_result").WithLocation(44, 16) @@ -358,238 +359,11 @@ class C ); } - [Fact] - public void BuilderOnMethod_BadBuilderOnType() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -Console.WriteLine(await C.M()); - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -}} - -[AsyncMethodBuilder(typeof(void))] // void -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] // wrong arity -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (11,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(11, 29), - // (14,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(14, 38), - // (17,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(17, 41) - ); - } - - [Fact] - public void BuilderOnMethod_BadBuilderOnType_CreateReturnsInt() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} -}} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") - .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") - .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.Create' - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "Create").WithLocation(9, 29), - // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.Create' - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "Create").WithLocation(12, 38) - ); - } - - [Fact] - public void BuilderOnMethod_BadBuilderOnType_TaskPropertyReturnsInt() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} -}} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") - .Replace("public MyTask Task => _task;", "public int Task => 0;")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") - .Replace("public MyTask Task => _task;", "public int Task => 0;")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (9,29): error CS8204: For type 'IgnoredTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'int'. - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "MyTask", "int").WithLocation(9, 29), - // (12,38): error CS8204: For type 'IgnoredTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'int'. - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncMethodBuilderTaskProperty, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "MyTask", "int").WithLocation(12, 38) - ); - } - - [Fact] - public void BuilderOnMethod_BadBuilderOnType_SetExceptionIsInternal() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} -}} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") - .Replace("public void SetException", "internal void SetException") - .Replace("public void SetResult", "internal void SetResult")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") - .Replace("public void SetException", "internal void SetException") - .Replace("public void SetResult", "internal void SetResult")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetException' - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "SetException").WithLocation(9, 29), - // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetException' - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "SetException").WithLocation(12, 38) - ); - } - - [Fact] - public void BuilderOnMethod_BadBuilderOnType_SetResultIsInternal() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} -}} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") - .Replace("public void SetResult", "internal void SetResult")} - -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") - .Replace("public void SetResult", "internal void SetResult")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (9,29): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetResult' - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("IgnoredTaskMethodBuilder", "SetResult").WithLocation(9, 29), - // (12,38): error CS0656: Missing compiler required member 'IgnoredTaskMethodBuilder.SetResult' - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("IgnoredTaskMethodBuilder", "SetResult").WithLocation(12, 38) - ); - } - - [Fact] - public void BuilderOnMethod_OnLocalFunction() + [Theory] + [InlineData("typeof(MyTaskMethodBuilder)")] + [InlineData("typeof(object)")] + [InlineData("null")] + public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuilder) { var source = $@" using System; @@ -607,19 +381,18 @@ public void BuilderOnMethod_OnLocalFunction() [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder({dummyBuilder})] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder({dummyBuilder})] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; + source = source.Replace("DUMMY_BUILDER", dummyBuilder); var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (9,21): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -791,16 +564,14 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1055,16 +826,14 @@ public void BuilderFactoryOnMethod_OnLambda() Console.WriteLine(await m()); return; -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", isStruct: true)} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1153,16 +922,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task", "public object Task")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1477,16 +1244,14 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1518,14 +1283,12 @@ class C {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1600,16 +1363,14 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} namespace System.Runtime.CompilerServices {{ @@ -1798,16 +1559,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1833,16 +1592,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task =>", "internal MyTask Task =>")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1878,16 +1635,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1923,16 +1678,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task = null;")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1968,16 +1721,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException", "internal void SetException")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2013,10 +1764,10 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") @@ -2025,8 +1776,6 @@ class C {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2062,16 +1811,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException(Exception e)", "public void SetException()")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(Exception e)", "public void SetException()")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2107,16 +1854,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetResult", "internal void SetResult")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2152,16 +1897,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2197,16 +1940,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2242,16 +1983,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void Start", "internal void Start")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2287,16 +2026,14 @@ class C static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetStateMachine", "internal void SetStateMachine")} {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2459,10 +2196,10 @@ public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilderMembers() using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(typeof(IgnoredBuilder1))] public class T1 {{ }} -[AsyncMethodBuilder(typeof(IgnoredBuilder2))] public class T2 {{ }} -[AsyncMethodBuilder(typeof(IgnoredBuilder3))] internal class T3 {{ }} -[AsyncMethodBuilder(typeof(IgnoredBuilder4))] internal class T4 {{ }} +[AsyncMethodBuilder(null)] public class T1 {{ }} +[AsyncMethodBuilder(null)] public class T2 {{ }} +[AsyncMethodBuilder(null)] internal class T3 {{ }} +[AsyncMethodBuilder(null)] internal class T4 {{ }} {AsyncBuilderFactoryCode("B1", "T1")} @@ -2494,10 +2231,6 @@ class Program async T4 f4() => await Task.Delay(4); }} -{AsyncBuilderCode("IgnoredBuilder1", "T1")} -{AsyncBuilderCode("IgnoredBuilder2", "T2")} -{AsyncBuilderCode("IgnoredBuilder3", "T3").Replace("public class IgnoredBuilder3", "internal class IgnoredBuilder3").Replace("public T3 Task", "internal T3 Task")} -{AsyncBuilderCode("IgnoredBuilder4", "T4").Replace("public T4 Task", "internal T4 Task")} {AsyncMethodBuilderAttribute} "; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); @@ -2508,9 +2241,6 @@ class Program // (100,19): error CS0656: Missing compiler required member 'B3.Task' // async T3 f3() => await Task.Delay(3); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("B3", "Task").WithLocation(100, 19), - // (100,19): error CS0656: Missing compiler required member 'IgnoredBuilder3.Task' - // async T3 f3() => await Task.Delay(3); - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("IgnoredBuilder3", "Task").WithLocation(100, 19), // (103,19): error CS0656: Missing compiler required member 'B4Factory.Create' // async T4 f4() => await Task.Delay(4); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(4)").WithArguments("B4Factory", "Create").WithLocation(103, 19) @@ -2525,7 +2255,7 @@ public void BuilderFactoryOnMethod_InternalReturnType() using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] internal class MyTaskType {{ }} +[AsyncMethodBuilder(null)] internal class MyTaskType {{ }} // Make the builder factory and the builder internal as well {AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } @@ -2536,7 +2266,6 @@ class C async MyTaskType M() => await Task.Delay(4); }} -{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTaskType").Replace("public class IgnoredTaskMethodBuilder", "internal class IgnoredTaskMethodBuilder")} {AsyncMethodBuilderAttribute} "; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); From e7ed4e3711027c61167fbb8454c75cef77374c61 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 12:00:55 -0700 Subject: [PATCH 16/24] Restore tests --- .../Semantics/BindingAsyncTasklikeMoreTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 34fbbf6a8a0f..83b44e34e8f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -434,11 +434,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +515,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +594,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From af160e234f8f3688421d2cf1093c8e76f5d3002a Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 12:21:11 -0700 Subject: [PATCH 17/24] Remove validation on return type --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 2 +- .../Symbols/MethodSymbolExtensions.cs | 5 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 6 + .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../CodeGenAsyncMethodBuilderOverrideTests.cs | 366 +++++++++++++++++- .../BindingAsyncTasklikeMoreTests.cs | 16 +- 19 files changed, 432 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 832270ac3818..a0ffd1482a58 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6704,4 +6704,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 'UnmanagedCallersOnly' method '{0}' cannot implement interface member '{1}' in type '{2}' UnmanagedCallersOnly is not localizable. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index e03b44df8124..0c624f945616 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1955,10 +1955,10 @@ internal enum ErrorCode ERR_ExplicitImplementationOfOperatorsMustBeStatic = 8930, ERR_AbstractConversionNotInvolvingContainedType = 8931, ERR_InterfaceImplementedByUnmanagedCallersOnlyMethod = 8932, + ERR_BuilderAttributeDisallowed = 8933, #endregion - // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) } } diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index 857db7a336fc..a07025ea8995 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -163,7 +164,7 @@ public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSh builderOverride = null; return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 0 } - && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilder(builderArgument: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); } /// @@ -174,7 +175,7 @@ public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol meth builderOverride = null; return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 1 } - && (method.HasMethodLevelBuilder(builderOverride: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilder(builderArgument: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 5a1981680817..d2f441222b70 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -281,6 +281,12 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) GetAttributes(); GetReturnTypeAttributes(); + if (this.HasAsyncMethodBuilder(out _)) + { + // This will need to be adjusted to account for explicit return type on lambdas + addTo.Add(ErrorCode.ERR_BuilderAttributeDisallowed, DiagnosticLocation); + } + addTo.AddRange(_declarationDiagnostics, allowMismatchInDependencyAccumulation: true); } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 7b817cdfecb2..2d9aae3e6f87 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -202,6 +202,11 @@ Chyba syntaxe příkazového řádku: {0} není platná hodnota možnosti {1}. Hodnota musí mít tvar {2}. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index b1c75831d9a9..5cdc56fd41f2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -202,6 +202,11 @@ Fehler in der Befehlszeilensyntax: "{0}" ist kein gültiger Wert für die Option "{1}". Der Wert muss im Format "{2}" vorliegen. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index f543da65693c..857967c5f335 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -202,6 +202,11 @@ Error de sintaxis de la línea de comandos: "{0}" no es un valor válido para la opción "{1}". El valor debe tener el formato "{2}". + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index f986f303d796..08ec781ca869 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -202,6 +202,11 @@ Erreur de syntaxe de ligne de commande : '{0}' est une valeur non valide pour l'option '{1}'. La valeur doit se présenter sous la forme '{2}'. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 932e123ba52b..b934a5d0e0b2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -202,6 +202,11 @@ Errore di sintassi della riga di comando: '{0}' non è un valore valido per l'opzione '{1}'. Il valore deve essere espresso nel formato '{2}'. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 94c256d2f3f1..949a2cd2d22c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -202,6 +202,11 @@ コマンドライン構文エラー: '{0}' は、'{1}' オプションの有効な値ではありません。値は '{2}' の形式にする必要があります。 + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 685dad1090d2..678eb832ddc5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -202,6 +202,11 @@ 명령줄 구문 오류: '{0}'은(는) '{1}' 옵션에 유효한 값이 아닙니다. 값은 '{2}' 형식이어야 합니다. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 2e10f5604a90..70e43b392ba9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -202,6 +202,11 @@ Błąd składni wiersza polecenia: „{0}” nie jest prawidłową wartością dla opcji „{1}”. Wartość musi mieć postać „{2}”. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 96e3bfa3bd87..244f990d4223 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -202,6 +202,11 @@ Erro de sintaxe de linha de comando: '{0}' não é um valor válido para a opção '{1}'. O valor precisa estar no formato '{2}'. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 4ccf80a85a79..c6c58db19451 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -202,6 +202,11 @@ Ошибка в синтаксисе командной строки: "{0}" не является допустимым значением для параметра "{1}". Значение должно иметь форму "{2}". + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 51e01116572f..1a1ab3c50567 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -202,6 +202,11 @@ Komut satırı söz dizimi hatası: '{0}', '{1}' seçeneği için geçerli bir değer değil. Değer '{2}' biçiminde olmalıdır. + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index d6861a3b63f5..bd7782a5825b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -202,6 +202,11 @@ 命令行语法错误:“{0}”不是“{1}”选项的有效值。值的格式必须为 "{2}"。 + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 83712f0997de..8f02a6139ed3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -202,6 +202,11 @@ 命令列語法錯誤: '{0}' 對 '{1}' 選項而言不是有效的值。此值的格式必須是 '{2}'。 + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + + The receiver type '{0}' is not a valid record type and is not a struct type. The receiver type '{0}' is not a valid record type and is not a struct type. diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 3669e7e93741..e1b7fb917dd5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -2,8 +2,11 @@ // 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.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -284,18 +287,14 @@ public static async MyTask M() {AsyncMethodBuilderAttribute} "; - // Async methods must return task-like types var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( - // (11,28): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "G").WithLocation(11, 28), - // (18,40): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M() - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(18, 40), - // (24,41): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // public static async MyTask M2() { return await G((string?)null); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M2").WithLocation(24, 41), + // (14,16): warning CS8603: Possible null reference return. + // return default(T); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "default(T)").WithLocation(14, 16), + // (20,16): warning CS8603: Possible null reference return. + // return await G((string?)null); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "await G((string?)null)").WithLocation(20, 16), // (44,16): warning CS8618: Non-nullable field '_result' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. // internal T _result; Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "_result").WithArguments("field", "_result").WithLocation(44, 16) @@ -359,6 +358,198 @@ class C ); } + [Fact] + public void BuilderOnMethod_BadBuilderOnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +[AsyncMethodBuilder(typeof(void))] // void +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] // wrong arity +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_CreateReturnsInt() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public static IgnoredTaskMethodBuilder Create() => new IgnoredTaskMethodBuilder(new MyTask());", "public static int Create() => 0;")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_TaskPropertyReturnsInt() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public MyTask Task => _task;", "public int Task => 0;")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public MyTask Task => _task;", "public int Task => 0;")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_SetExceptionIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public void SetException", "internal void SetException") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetException", "internal void SetException") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_BadBuilderOnType_SetResultIsInternal() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} +}} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] +{AwaitableTypeCode("MyTask")} + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder<>))] +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetResult", "internal void SetResult")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics(); + } + [Theory] [InlineData("typeof(MyTaskMethodBuilder)")] [InlineData("typeof(object)")] @@ -392,7 +583,6 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild {AsyncMethodBuilderAttribute} "; - source = source.Replace("DUMMY_BUILDER", dummyBuilder); var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (9,21): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -903,6 +1093,129 @@ public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() verifier.VerifyDiagnostics(); } + [Fact] + public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 +); + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 +); + +await Task.Delay(0); +return; + +public class C +{{ + public static void F(Func f) {{ System.Console.Write(""Overload1 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload2 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload3 ""); f().GetAwaiter().GetResult(); }} +}} + +// no attribute +{AwaitableTypeCode("MyTask", isStruct: true)} + +// no attribute +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (7,78): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(7, 78), + // (7,78): error CS1643: Not all code paths return a value in lambda expression of type 'Func>' + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(7, 78), + // (11,80): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 80), + // (11,140): error CS8031: Async lambda expression converted to a 'Task' returning delegate cannot return a value. Did you intend to return 'Task'? + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequiredLambda, "return").WithLocation(11, 140), + // (11,147): error CS0029: Cannot implicitly convert type 'int' to 'string' + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(11, 147), + // (11,147): error CS4010: Cannot convert async lambda expression to delegate type 'MyTask'. An async lambda expression may return void, Task or Task, none of which are convertible to 'MyTask'. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "3").WithArguments("lambda expression", "MyTask").WithLocation(11, 147) + ); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + var lambdas = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var firstLambda = model.GetTypeInfo(lambdas[0]); + Assert.Null(firstLambda.Type); + Assert.Equal("System.Func", firstLambda.ConvertedType.ToTestDisplayString()); + + var secondLambda = model.GetTypeInfo(lambdas[1]); + Assert.Null(secondLambda.Type); + Assert.Equal("System.Func", secondLambda.ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_ExplicitReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async MyTask () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 +); + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async MyTask () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 +); + +await Task.Delay(0); +return; + +public class C +{{ + public static void F(Func f) {{ System.Console.Write(""Overload1 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload2 ""); f().GetAwaiter().GetResult(); }} + public static void F(Func> f) {{ System.Console.Write(""Overload3 ""); f().GetAwaiter().GetResult(); }} +}} + +// no attribute +{AwaitableTypeCode("MyTask", isStruct: true)} + +// no attribute +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + // We'll need to adjust this test once explicit return types are allowed on lambdas + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + Assert.Equal(18, compilation.GetDiagnostics().Length); + + //var tree = compilation.SyntaxTrees.Single(); + //var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + //var lambdas = tree.GetRoot().DescendantNodes().OfType().ToArray(); + //var firstLambda = model.GetTypeInfo(lambdas[0]); + //Assert.Null(firstLambda.Type); + //Assert.Equal("System.Func", firstLambda.ConvertedType.ToTestDisplayString()); + + //var secondLambda = model.GetTypeInfo(lambdas[1]); + //Assert.Null(secondLambda.Type); + //Assert.Equal("System.Func", secondLambda.ConvertedType.ToTestDisplayString()); + } + + [Fact] public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() { @@ -2280,25 +2593,38 @@ public void BuilderFactoryOnMethod_IntReturnType() using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] public class MyTaskType {{ }} +System.Console.Write(new C().M()); -{AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType")} +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] public class MyTaskType {{ }} -class C +public class C {{ [AsyncMethodBuilder(typeof(MyTaskTypeBuilderFactory))] - async int M() => await Task.Delay(4); + public async int M() => await Task.Delay(4); +}} + +public class MyTaskTypeBuilderFactory +{{ + public static MyTaskTypeBuilder Create() => new MyTaskTypeBuilder(); +}} + +public class MyTaskTypeBuilder +{{ + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult() {{ }} + 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 int Task => 42; }} {AsyncBuilderCode("IgnoredTaskMethodBuilder", "MyTaskType")} {AsyncMethodBuilderAttribute} "; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - comp.VerifyEmitDiagnostics( - // (31,15): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // async int M() => await Task.Delay(4); - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "M").WithLocation(31, 15) - ); + var verifier = CompileAndVerify(comp, expectedOutput: "42"); + verifier.VerifyDiagnostics(); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 83b44e34e8f6..34fbbf6a8a0f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -434,11 +434,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +515,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +594,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From 42185073acd0a9c1cb6465b7c5fc70752b46240e Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 14:37:25 -0700 Subject: [PATCH 18/24] Remove builder/factory indirection --- .../Portable/Binder/Binder_Expressions.cs | 2 +- .../Portable/Binder/Binder_Statements.cs | 6 +- .../Portable/BoundTree/UnboundLambda.cs | 4 +- .../Portable/FlowAnalysis/FlowAnalysisPass.cs | 2 +- .../Portable/FlowAnalysis/NullableWalker.cs | 2 +- .../AsyncMethodBuilderMemberCollection.cs | 154 +-- .../AsyncMethodToStateMachineRewriter.cs | 6 +- .../Symbols/MethodSymbolExtensions.cs | 10 +- .../SourceMethodSymbolWithAttributes.cs | 4 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 1082 +++++------------ .../BindingAsyncTasklikeMoreTests.cs | 75 +- 11 files changed, 450 insertions(+), 897 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 5e7c110acfe1..c04f96742300 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8680,7 +8680,7 @@ internal static bool MethodOrLambdaRequiresValue(Symbol symbol, CSharpCompilatio { return symbol is MethodSymbol method && !method.ReturnsVoid && - !method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _); + !method.IsAsyncEffectivelyReturningTask(compilation); } private BoundConditionalAccess GenerateBadConditionalAccessNodeError(ConditionalAccessExpressionSyntax node, BoundExpression receiver, BoundExpression access, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 5cd612f0190f..798e4a9b44f3 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -623,7 +623,7 @@ BoundBlock runAnalysis(BoundBlock block, BindingDiagnosticBag blockDiagnostics) private bool ImplicitReturnIsOkay(MethodSymbol method) { - return method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); + return method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(this.Compilation); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2650,13 +2650,13 @@ protected bool IsInAsyncMethod() protected bool IsEffectivelyTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningTask(this.Compilation, builderOverride: out _); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningTask(this.Compilation); } protected bool IsEffectivelyGenericTaskReturningAsyncMethod() { var symbol = this.ContainingMemberOrLambda; - return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningGenericTask(this.Compilation, builderOverride: out _); + return symbol?.Kind == SymbolKind.Method && ((MethodSymbol)symbol).IsAsyncEffectivelyReturningGenericTask(this.Compilation); } protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 56331d7c1d52..c620b16a09cf 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -692,8 +692,8 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { if (returnType.HasType && // Can be null if "delegateType" is not actually a delegate type. !returnType.IsVoidType() && - !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _) && - !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) + !lambdaSymbol.IsAsyncEffectivelyReturningTask(compilation) && + !lambdaSymbol.IsAsyncEffectivelyReturningGenericTask(compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index 49b5dbca5e72..cb6480c0e4ef 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -40,7 +40,7 @@ public static BoundBlock Rewrite( #endif var compilation = method.DeclaringCompilation; - if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation, builderOverride: out _)) + if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 3acb6ac25fd5..9b87fb55cee7 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2542,7 +2542,7 @@ private bool TryGetReturnType(out TypeWithAnnotations type, out FlowAnalysisAnno return true; } - if (method.IsAsyncEffectivelyReturningGenericTask(compilation, builderOverride: out _)) + if (method.IsAsyncEffectivelyReturningGenericTask(compilation)) { type = ((NamedTypeSymbol)returnType.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single(); annotations = FlowAnalysisAnnotations.None; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index e4e9759c428e..dcc1b4969b2f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -179,64 +179,52 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, } object methodLevelBuilder = null; - if (method.IsAsyncEffectivelyReturningTask(F.Compilation, out methodLevelBuilder)) + if (method.IsAsyncEffectivelyReturningTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool forOverride = method.HasAsyncMethodBuilder(out methodLevelBuilder); bool customBuilder; + object builderArgument; - if ((object)methodLevelBuilder != null) + if (forOverride) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: false, forOverride: true); customBuilder = true; - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - } - } - else - { - builderType = null; - } + builderArgument = methodLevelBuilder; } else { - object builderArgument; customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) - { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - createBuilderMethod = GetCustomCreateMethod(F, builderType); - } - } - else + } + + if (customBuilder) + { + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false, forOverride); + if ((object)builderType != null) { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); - Debug.Assert((object)builderType != null); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, - builderType, - customBuilder, - out taskProperty); + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); + Debug.Assert((object)builderType != null); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, + builderType, + customBuilder, + out taskProperty); + } if ((object)builderType == null || (object)createBuilderMethod == null || @@ -262,7 +250,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, out methodLevelBuilder)) + if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; @@ -278,61 +266,48 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; + bool forOverride = method.HasAsyncMethodBuilder(out methodLevelBuilder); bool customBuilder; + object builderArgument; - if ((object)methodLevelBuilder != null) + if (forOverride) { - var initialBuilderType = ValidateBuilderType(F, methodLevelBuilder, returnType.DeclaredAccessibility, isGeneric: true, forOverride: true); customBuilder = true; - if ((object)initialBuilderType != null) - { - // We only get the Create method from the initial builder type, then we'll use its return type as builder type - initialBuilderType = initialBuilderType.ConstructedFrom.Construct(resultType); - createBuilderMethod = GetCustomCreateMethod(F, initialBuilderType, forOverride: true); - builderType = createBuilderMethod?.ReturnType as NamedTypeSymbol; - if ((object)builderType != null) - { - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - } - } - else - { - builderType = null; - } + builderArgument = methodLevelBuilder; } else { - object builderArgument; customBuilder = returnType.IsCustomTaskType(out builderArgument); - if (customBuilder) - { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); - if ((object)builderType != null) - { - builderType = builderType.ConstructedFrom.Construct(resultType); - taskProperty = GetCustomTaskProperty(F, builderType, returnType); - createBuilderMethod = GetCustomCreateMethod(F, builderType); - } - } - else + } + + if (customBuilder) + { + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, forOverride); + if ((object)builderType != null) { - builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); - Debug.Assert((object)builderType != null); - builderType = builderType.Construct(resultType); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, - builderType, - customBuilder, - out createBuilderMethod); - TryGetBuilderMember( - F, - WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, - builderType, - customBuilder, - out taskProperty); + builderType = builderType.ConstructedFrom.Construct(resultType); + taskProperty = GetCustomTaskProperty(F, builderType, returnType); + createBuilderMethod = GetCustomCreateMethod(F, builderType); } } + else + { + builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); + Debug.Assert((object)builderType != null); + builderType = builderType.Construct(resultType); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, + builderType, + customBuilder, + out createBuilderMethod); + TryGetBuilderMember( + F, + WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, + builderType, + customBuilder, + out taskProperty); + } if ((object)builderType == null || (object)taskProperty == null || @@ -485,8 +460,7 @@ private static bool TryGetBuilderMember( // We'll just use that type as the final builder type. private static MethodSymbol GetCustomCreateMethod( SyntheticBoundNodeFactory F, - NamedTypeSymbol builderType, - bool forOverride = false) + NamedTypeSymbol builderType) { // The Create method's return type is expected to be builderType. // The WellKnownMembers routines aren't able to enforce that, which is why this method exists. @@ -504,7 +478,7 @@ private static MethodSymbol GetCustomCreateMethod( method.ParameterCount == 0 && !method.IsGenericMethod && method.RefKind == RefKind.None && - (forOverride || method.ReturnType.Equals(builderType, TypeCompareKind.AllIgnoreOptions))) + method.ReturnType.Equals(builderType, TypeCompareKind.AllIgnoreOptions)) { return method; } diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index 768b3d612a17..de5d554e25fa 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -85,7 +85,7 @@ internal AsyncMethodToStateMachineRewriter( _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); - _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) + _exprRetValue = method.IsAsyncEffectivelyReturningGenericTask(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; @@ -208,7 +208,7 @@ protected virtual BoundStatement GenerateSetResultCall() F.Call( F.Field(F.This(), _asyncMethodBuilderField), _asyncMethodBuilderMemberCollection.SetResult, - _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _) + _method.IsAsyncEffectivelyReturningGenericTask(F.Compilation) ? ImmutableArray.Create(F.Local(_exprRetValue)) : ImmutableArray.Empty)); } @@ -623,7 +623,7 @@ public sealed override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { - Debug.Assert(_method.IsAsyncEffectivelyReturningGenericTask(F.Compilation, builderOverride: out _)); + Debug.Assert(_method.IsAsyncEffectivelyReturningGenericTask(F.Compilation)); return F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel)); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index a07025ea8995..f1a7b7af12a3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -159,23 +159,21 @@ public static bool IsAsyncReturningVoid(this MethodSymbol method) /// /// Returns whether this method is async and returns a task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) + public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSharpCompilation compilation) { - builderOverride = null; return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 0 } - && (method.HasAsyncMethodBuilder(builderArgument: out builderOverride) || method.ReturnType.IsNonGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilder(builderArgument: out _) || method.ReturnType.IsNonGenericTaskType(compilation)); } /// /// Returns whether this method is async and returns a generic task, task-like, or other type with a method-level builder. /// - public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation, [NotNullWhen(true)] out object? builderOverride) + public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol method, CSharpCompilation compilation) { - builderOverride = null; return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 1 } - && (method.HasAsyncMethodBuilder(builderArgument: out builderOverride) || method.ReturnType.IsGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilder(builderArgument: out _) || method.ReturnType.IsGenericTaskType(compilation)); } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index e6ba0e13d70b..6d0a34f969f2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1113,8 +1113,8 @@ static bool isBadAsyncReturn(MethodSymbol methodSymbol) !returnType.IsVoidType() && !returnType.IsIAsyncEnumerableType(declaringCompilation) && !returnType.IsIAsyncEnumeratorType(declaringCompilation) && - !methodSymbol.IsAsyncEffectivelyReturningTask(declaringCompilation, builderOverride: out _) && - !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation, builderOverride: out _); + !methodSymbol.IsAsyncEffectivelyReturningTask(declaringCompilation) && + !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation); } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e1b7fb917dd5..80d996df8b41 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -12,9 +12,6 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { - // Broad scenarios covered: - // - AsyncMethodBuilderAttribute can be placed on an async method, which overrides the builder used - // - The type used in an override needs only have a static Create() method which gives us the actual builder type public class CodeGenAsyncMethodBuilderOverrideTests : EmitMetadataTestBase { private const string AsyncMethodBuilderAttribute = @@ -41,31 +38,6 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter "; } - private static string AsyncBuilderFactoryCode(string builderTypeName, string tasklikeTypeName, string? genericTypeParameter = null, bool isStruct = false) - { - string ofT = genericTypeParameter == null ? "" : "<" + genericTypeParameter + ">"; - - return $@" -public {(isStruct ? "struct" : "class")} {builderTypeName}Factory{ofT} -{{ - public static {builderTypeName}{ofT} Create() => new {builderTypeName}{ofT}(new {tasklikeTypeName}{ofT}()); -}} - -public {(isStruct ? "struct" : "class")} {builderTypeName}{ofT} -{{ - private {tasklikeTypeName}{ofT} _task; - internal {builderTypeName}({tasklikeTypeName}{ofT} task) {{ _task = task; }} - public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} - public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} - public void SetException(Exception e) {{ }} - public void SetResult({(genericTypeParameter == null ? "" : genericTypeParameter + " result")}) {{ {(genericTypeParameter == null ? "" : "_task._result = result;")} }} - 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 {tasklikeTypeName}{ofT} Task => _task; -}} -"; - } - private static string AwaitableTypeCode(string taskLikeName, string? genericTypeParameter = null, bool isStruct = false) { if (genericTypeParameter == null) @@ -159,10 +131,10 @@ class C var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @" { // Code size 45 (0x2d) @@ -754,285 +726,96 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} +{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3", symbolValidator: verifyMembers); - verifier.VerifyDiagnostics(); - var testData = verifier.TestData; - var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; - Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); - method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; - Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); - - // The initial builder type is used for Create() invocation - verifier.VerifyIL("C.F()", @" -{ - // Code size 45 (0x2d) - .maxstack 2 - .locals init (C.d__0 V_0) - IL_0000: ldloca.s V_0 - IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" - IL_0007: stfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_000c: ldloca.s V_0 - IL_000e: ldc.i4.m1 - IL_000f: stfld ""int C.d__0.<>1__state"" - IL_0014: ldloc.0 - IL_0015: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_001a: ldloca.s V_0 - IL_001c: callvirt ""void MyTaskMethodBuilder.Startd__0>(ref C.d__0)"" - IL_0021: ldloc.0 - IL_0022: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0027: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_002c: ret -}"); - // The final builder type is used for the rest - verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" -{ - // Code size 153 (0x99) - .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 C.d__0.<>1__state"" - IL_0006: stloc.0 - .try - { - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0049 - IL_000a: ldstr ""F "" - IL_000f: call ""void System.Console.Write(string)"" - IL_0014: ldc.i4.0 - IL_0015: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" - IL_001a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_001f: stloc.1 - IL_0020: ldloca.s V_1 - IL_0022: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0027: brtrue.s IL_0065 - IL_0029: ldarg.0 - IL_002a: ldc.i4.0 - IL_002b: dup - IL_002c: stloc.0 - IL_002d: stfld ""int C.d__0.<>1__state"" - IL_0032: ldarg.0 - IL_0033: ldloc.1 - IL_0034: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0039: ldarg.0 - IL_003a: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_003f: ldloca.s V_1 - IL_0041: ldarg.0 - IL_0042: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0047: leave.s IL_0098 - IL_0049: ldarg.0 - IL_004a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_004f: stloc.1 - IL_0050: ldarg.0 - IL_0051: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0056: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_005c: ldarg.0 - IL_005d: ldc.i4.m1 - IL_005e: dup - IL_005f: stloc.0 - IL_0060: stfld ""int C.d__0.<>1__state"" - IL_0065: ldloca.s V_1 - IL_0067: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_006c: leave.s IL_0085 - } - catch System.Exception - { - IL_006e: stloc.2 - IL_006f: ldarg.0 - IL_0070: ldc.i4.s -2 - IL_0072: stfld ""int C.d__0.<>1__state"" - IL_0077: ldarg.0 - IL_0078: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_007d: ldloc.2 - IL_007e: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" - IL_0083: leave.s IL_0098 - } - IL_0085: ldarg.0 - IL_0086: ldc.i4.s -2 - IL_0088: stfld ""int C.d__0.<>1__state"" - IL_008d: ldarg.0 - IL_008e: ldfld ""MyTaskMethodBuilder C.d__0.<>t__builder"" - IL_0093: callvirt ""void MyTaskMethodBuilder.SetResult()"" - IL_0098: ret -} -"); + compilation.VerifyEmitDiagnostics( + // (11,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 29), + // (11,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(11, 29), + // (14,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 38), + // (14,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(14, 38), + // (17,41): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(17, 41), + // (17,41): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' + // public static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Task").WithLocation(17, 41) + ); - // The initial builder type is used for Create() invocation - verifier.VerifyIL("C.G(T)", @" -{ - // Code size 53 (0x35) - .maxstack 2 - .locals init (C.d__1 V_0) - IL_0000: ldloca.s V_0 - IL_0002: call ""MyTaskMethodBuilder MyTaskMethodBuilderFactory.Create()"" - IL_0007: stfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_000c: ldloca.s V_0 - IL_000e: ldarg.0 - IL_000f: stfld ""T C.d__1.t"" - IL_0014: ldloca.s V_0 - IL_0016: ldc.i4.m1 - IL_0017: stfld ""int C.d__1.<>1__state"" - IL_001c: ldloc.0 - IL_001d: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0022: ldloca.s V_0 - IL_0024: callvirt ""void MyTaskMethodBuilder.Startd__1>(ref C.d__1)"" - IL_0029: ldloc.0 - IL_002a: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_002f: callvirt ""MyTask MyTaskMethodBuilder.Task.get"" - IL_0034: ret -}"); + static string asyncBuilderFactoryCode(string builderTypeName, string tasklikeTypeName, string? genericTypeParameter = null, bool isStruct = false) + { + string ofT = genericTypeParameter == null ? "" : "<" + genericTypeParameter + ">"; - // The final builder type is used for the rest - verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" -{ - // Code size 161 (0xa1) - .maxstack 3 - .locals init (int V_0, - T V_1, - System.Runtime.CompilerServices.TaskAwaiter V_2, - System.Exception V_3) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__1.<>1__state"" - IL_0006: stloc.0 - .try - { - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0049 - IL_000a: ldstr ""G "" - IL_000f: call ""void System.Console.Write(string)"" - IL_0014: ldc.i4.0 - IL_0015: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.Delay(int)"" - IL_001a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_001f: stloc.2 - IL_0020: ldloca.s V_2 - IL_0022: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0027: brtrue.s IL_0065 - IL_0029: ldarg.0 - IL_002a: ldc.i4.0 - IL_002b: dup - IL_002c: stloc.0 - IL_002d: stfld ""int C.d__1.<>1__state"" - IL_0032: ldarg.0 - IL_0033: ldloc.2 - IL_0034: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_0039: ldarg.0 - IL_003a: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_003f: ldloca.s V_2 - IL_0041: ldarg.0 - IL_0042: callvirt ""void MyTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" - IL_0047: leave.s IL_00a0 - IL_0049: ldarg.0 - IL_004a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_004f: stloc.2 - IL_0050: ldarg.0 - IL_0051: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_0056: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_005c: ldarg.0 - IL_005d: ldc.i4.m1 - IL_005e: dup - IL_005f: stloc.0 - IL_0060: stfld ""int C.d__1.<>1__state"" - IL_0065: ldloca.s V_2 - IL_0067: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_006c: ldarg.0 - IL_006d: ldfld ""T C.d__1.t"" - IL_0072: stloc.1 - IL_0073: leave.s IL_008c - } - catch System.Exception - { - IL_0075: stloc.3 - IL_0076: ldarg.0 - IL_0077: ldc.i4.s -2 - IL_0079: stfld ""int C.d__1.<>1__state"" - IL_007e: ldarg.0 - IL_007f: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_0084: ldloc.3 - IL_0085: callvirt ""void MyTaskMethodBuilder.SetException(System.Exception)"" - IL_008a: leave.s IL_00a0 - } - IL_008c: ldarg.0 - IL_008d: ldc.i4.s -2 - IL_008f: stfld ""int C.d__1.<>1__state"" - IL_0094: ldarg.0 - IL_0095: ldfld ""MyTaskMethodBuilder C.d__1.<>t__builder"" - IL_009a: ldloc.1 - IL_009b: callvirt ""void MyTaskMethodBuilder.SetResult(T)"" - IL_00a0: ret -} -"); + return $@" +public {(isStruct ? "struct" : "class")} {builderTypeName}Factory{ofT} +{{ + public static {builderTypeName}{ofT} Create() => new {builderTypeName}{ofT}(new {tasklikeTypeName}{ofT}()); +}} - void verifyMembers(ModuleSymbol module) - { - var fType = (NamedTypeSymbol)module.GlobalNamespace.GetMember("C.d__0"); - AssertEx.SetEqual(new[] { - "MyTaskMethodBuilder C.d__0.<>t__builder", - "C.d__0..ctor()", - "void C.d__0.MoveNext()", - "void C.d__0.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", - "System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1", - "System.Int32 C.d__0.<>1__state" }, - fType.GetMembersUnordered().ToTestDisplayStrings()); - - var gType = (NamedTypeSymbol)module.GlobalNamespace.GetMember("C.d__1"); - AssertEx.SetEqual(new[] { - "void C.d__1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)", - "MyTaskMethodBuilder C.d__1.<>t__builder", - "T C.d__1.t", - "C.d__1..ctor()", - "void C.d__1.MoveNext()", - "System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1", - "System.Int32 C.d__1.<>1__state"}, - gType.GetMembersUnordered().ToTestDisplayStrings()); +public {(isStruct ? "struct" : "class")} {builderTypeName}{ofT} +{{ + private {tasklikeTypeName}{ofT} _task; + internal {builderTypeName}({tasklikeTypeName}{ofT} task) {{ _task = task; }} + public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} + public void SetException(Exception e) {{ }} + public void SetResult({(genericTypeParameter == null ? "" : genericTypeParameter + " result")}) {{ {(genericTypeParameter == null ? "" : "_task._result = result;")} }} + 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 {tasklikeTypeName}{ofT} Task => _task; +}} +"; } } [Fact] - public void BuilderFactoryOnMethod_OnLambda() + public void BuilderOnMethod_OnLambda() { var source = $@" using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; -Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; -Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; Console.WriteLine(await m()); return; -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", isStruct: true)} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); - verifier.VerifyDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (6,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(6, 84), + // (8,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(8, 84) + ); } [Fact] - public void BuilderFactoryOnMethod_OnLambda_WithExplicitType() + public void BuilderOnMethod_OnLambda_WithExplicitType() { var source = $@" using System; @@ -1046,55 +829,22 @@ public void BuilderFactoryOnMethod_OnLambda_WithExplicitType() Console.WriteLine(await m()); return; -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", isStruct: true)} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); // This test will be revisited once explicit lambda return types are allowed - Assert.Equal(16, compilation.GetDiagnostics().Length); + Assert.Equal(18, compilation.GetDiagnostics().Length); //var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); //verifier.VerifyDiagnostics(); } [Fact] - public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; - -Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; - -Console.WriteLine(await m()); -return; - -// no attribute -{AwaitableTypeCode("MyTask", isStruct: true)} - -// no attribute -{AwaitableTypeCode("MyTask", "T", isStruct: true)} - -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); - verifier.VerifyDiagnostics(); - } - - [Fact] - public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() + public void BuilderOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() { var source = $@" using System; @@ -1102,11 +852,11 @@ public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() using System.Threading.Tasks; C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 ); C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 ); await Task.Delay(0); @@ -1125,30 +875,30 @@ public class C // no attribute {AwaitableTypeCode("MyTask", "T", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (7,78): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 - Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(7, 78), - // (7,78): error CS1643: Not all code paths return a value in lambda expression of type 'Func>' - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(7, 78), - // (11,80): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 80), - // (11,140): error CS8031: Async lambda expression converted to a 'Task' returning delegate cannot return a value. Did you intend to return 'Task'? - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequiredLambda, "return").WithLocation(11, 140), - // (11,147): error CS0029: Cannot implicitly convert type 'int' to 'string' - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(11, 147), - // (11,147): error CS4010: Cannot convert async lambda expression to delegate type 'MyTask'. An async lambda expression may return void, Task or Task, none of which are convertible to 'MyTask'. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "3").WithArguments("lambda expression", "MyTask").WithLocation(11, 147) + // (7,71): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(7, 71), + // (7,71): error CS1643: Not all code paths return a value in lambda expression of type 'Func>' + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(7, 71), + // (11,73): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 73), + // (11,133): error CS8031: Async lambda expression converted to a 'Task' returning delegate cannot return a value. Did you intend to return 'Task'? + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequiredLambda, "return").WithLocation(11, 133), + // (11,140): error CS0029: Cannot implicitly convert type 'int' to 'string' + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(11, 140), + // (11,140): error CS4010: Cannot convert async lambda expression to delegate type 'MyTask'. An async lambda expression may return void, Task or Task, none of which are convertible to 'MyTask'. + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 + Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "3").WithArguments("lambda expression", "MyTask").WithLocation(11, 140) ); var tree = compilation.SyntaxTrees.Single(); @@ -1164,7 +914,7 @@ public class C } [Fact] - public void BuilderFactoryOnMethod_OnLambda_NotTaskLikeTypes_ExplicitReturnType() + public void BuilderOnMethod_OnLambda_NotTaskLikeTypes_ExplicitReturnType() { var source = $@" using System; @@ -1195,13 +945,13 @@ public class C // no attribute {AwaitableTypeCode("MyTask", "T", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; // We'll need to adjust this test once explicit return types are allowed on lambdas var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - Assert.Equal(18, compilation.GetDiagnostics().Length); + Assert.Equal(20, compilation.GetDiagnostics().Length); //var tree = compilation.SyntaxTrees.Single(); //var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); @@ -1217,7 +967,7 @@ public class C [Fact] - public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() + public void BuilderOnMethod_TaskPropertyHasObjectType() { var source = $@" using System; @@ -1225,24 +975,21 @@ public void BuilderFactoryOnMethod_TaskPropertyHasObjectType() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task", "public object Task")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task", "public object Task")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1261,7 +1008,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_CreateMissing() + public void BuilderOnMethod_CreateMissing() { var source = $@" using System; @@ -1269,48 +1016,45 @@ public void BuilderFactoryOnMethod_CreateMissing() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T") .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Theory] [InlineData("internal")] [InlineData("private")] - public void BuilderFactoryOnMethod_CreateNotPublic(string accessibility) + public void BuilderOnMethod_CreateNotPublic(string accessibility) { var source = $@" using System; @@ -1318,42 +1062,39 @@ public void BuilderFactoryOnMethod_CreateNotPublic(string accessibility) using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_CreateNotStatic() + public void BuilderOnMethod_CreateNotStatic() { var source = $@" using System; @@ -1361,43 +1102,40 @@ public void BuilderFactoryOnMethod_CreateNotStatic() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_CreateHasParameter() + public void BuilderOnMethod_CreateHasParameter() { var source = $@" using System; @@ -1405,43 +1143,40 @@ public void BuilderFactoryOnMethod_CreateHasParameter() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_CreateIsGeneric() + public void BuilderOnMethod_CreateIsGeneric() { var source = $@" using System; @@ -1449,43 +1184,40 @@ public void BuilderFactoryOnMethod_CreateIsGeneric() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_CreateHasRefReturn() + public void BuilderOnMethod_CreateHasRefReturn() { var source = $@" using System; @@ -1493,50 +1225,48 @@ public void BuilderFactoryOnMethod_CreateHasRefReturn() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") .Replace( "public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "public static ref MyTaskMethodBuilder Create() => throw null;")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T") .Replace( "public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "public static ref MyTaskMethodBuilder Create() => throw null;")} + {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_BuilderFactoryIsInternal() + public void BuilderOnMethod_BuilderIsInternal() { var source = $@" using System; @@ -1547,24 +1277,21 @@ public void BuilderFactoryOnMethod_BuilderFactoryIsInternal() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "internal class MyTaskMethodBuilderFactory")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilder", "internal class MyTaskMethodBuilder")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilder", "internal class MyTaskMethodBuilder")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1572,7 +1299,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_BuilderFactoryIsPrivate() + public void BuilderOnMethod_BuilderIsPrivate() { var source = $@" using System; @@ -1583,23 +1310,20 @@ public void BuilderFactoryOnMethod_BuilderFactoryIsPrivate() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} - {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} - {AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilderFactory", "private class MyTaskMethodBuilderFactory")} + {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilder", "private class MyTaskMethodBuilder")} + {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilder", "private class MyTaskMethodBuilder")} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} {AsyncMethodBuilderAttribute} @@ -1609,7 +1333,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_CreateIsInternal() + public void BuilderOnMethod_CreateIsInternal() { var source = $@" using System; @@ -1617,42 +1341,39 @@ public void BuilderFactoryOnMethod_CreateIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(8, 29), - // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(8, 29), + // (11,38): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(11, 38), - // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(11, 38), + // (14,34): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilderFactory", "Create").WithLocation(14, 34) + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithArguments("MyTaskMethodBuilder", "Create").WithLocation(14, 34) ); } [Fact] - public void BuilderFactoryOnMethod_TwoMethodLevelAttributes() + public void BuilderOnMethod_TwoMethodLevelAttributes() { var source = $@" using System; @@ -1663,27 +1384,24 @@ public void BuilderFactoryOnMethod_TwoMethodLevelAttributes() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] [AsyncMethodBuilder(null)] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] [AsyncMethodBuilder(null)] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] [AsyncMethodBuilder(null)] public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} namespace System.Runtime.CompilerServices {{ @@ -1698,7 +1416,7 @@ class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilde } [Fact] - public void BuilderFactoryOnMethod_TwoMethodLevelAttributes_ReverseOrder() + public void BuilderOnMethod_TwoMethodLevelAttributes_ReverseOrder() { var source = $@" using System; @@ -1708,26 +1426,23 @@ public void BuilderFactoryOnMethod_TwoMethodLevelAttributes_ReverseOrder() class C {{ [AsyncMethodBuilder(null)] - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} [AsyncMethodBuilder(null)] - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} [AsyncMethodBuilder(null)] - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} namespace System.Runtime.CompilerServices {{ @@ -1751,52 +1466,7 @@ class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilde } [Fact] - public void BuilderFactoryOnMethod_WrongArity() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] - static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -}} - -[AsyncMethodBuilder(null)] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics( - // (9,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""F ""); await Task.Delay(0); }").WithLocation(9, 29), - // (12,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { System.Console.Write("G "); await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""G ""); await Task.Delay(0); return t; }").WithLocation(12, 38), - // (15,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask M() { System.Console.Write("M "); await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, @"{ System.Console.Write(""M ""); await F(); return await G(3); }").WithLocation(15, 34) - ); - } - - [Fact] - public void BuilderFactoryOnMethod_BoundGeneric_TypeParameter() + public void BuilderOnMethod_BoundGeneric_TypeParameter() { var source = $@" using System; @@ -1805,27 +1475,26 @@ public void BuilderFactoryOnMethod_BoundGeneric_TypeParameter() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask G(T t) {{ await Task.Delay(0); throw null; }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (8,25): error CS0416: 'MyTaskMethodBuilderFactory': an attribute argument cannot use type parameters - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] - Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(MyTaskMethodBuilderFactory)").WithArguments("MyTaskMethodBuilderFactory").WithLocation(8, 25) + // (8,25): error CS0416: 'MyTaskMethodBuilder': an attribute argument cannot use type parameters + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(MyTaskMethodBuilder)").WithArguments("MyTaskMethodBuilder").WithLocation(8, 25) ); } [Fact] - public void BuilderFactoryOnMethod_BoundGeneric_SpecificType() + public void BuilderOnMethod_BoundGeneric_SpecificType() { var source = $@" using System; @@ -1834,14 +1503,13 @@ public void BuilderFactoryOnMethod_BoundGeneric_SpecificType() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask M() {{ await Task.Delay(0); throw null; }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} {AsyncMethodBuilderAttribute} "; @@ -1854,40 +1522,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_FinalBuilderTypeIsInternal() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] - static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -}} - -[AsyncMethodBuilder(null)] -{AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static class MyTaskMethodBuilder", "internal static class MyTaskMethodBuilder")} -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyEmitDiagnostics(); - } - - [Fact] - public void BuilderFactoryOnMethod_TaskPropertyIsInternal() + public void BuilderOnMethod_TaskPropertyIsInternal() { var source = $@" using System; @@ -1895,24 +1530,21 @@ public void BuilderFactoryOnMethod_TaskPropertyIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task =>", "internal MyTask Task =>")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task =>", "internal MyTask Task =>")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1930,7 +1562,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_TaskPropertyIsStatic() + public void BuilderOnMethod_TaskPropertyIsStatic() { var source = $@" using System; @@ -1938,24 +1570,21 @@ public void BuilderFactoryOnMethod_TaskPropertyIsStatic() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -1973,7 +1602,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_TaskPropertyIsField() + public void BuilderOnMethod_TaskPropertyIsField() { var source = $@" using System; @@ -1981,24 +1610,21 @@ public void BuilderFactoryOnMethod_TaskPropertyIsField() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task = null;")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public MyTask Task => _task;", "public static MyTask Task = null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2016,7 +1642,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_SetExceptionIsInternal() + public void BuilderOnMethod_SetExceptionIsInternal() { var source = $@" using System; @@ -2024,24 +1650,21 @@ public void BuilderFactoryOnMethod_SetExceptionIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException", "internal void SetException")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException", "internal void SetException")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2059,7 +1682,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_SetExceptionReturnsObject() + public void BuilderOnMethod_SetExceptionReturnsObject() { var source = $@" using System; @@ -2067,27 +1690,24 @@ public void BuilderFactoryOnMethod_SetExceptionReturnsObject() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask") - .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") + .Replace("public void SetException(System.Exception e) { }", "public object SetException(System.Exception e) => null;")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T") - .Replace("public void SetException(Exception e) { }", "public object SetException(Exception e) => null;")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetException(System.Exception e) { }", "public object SetException(System.Exception e) => null;")} {AsyncMethodBuilderAttribute} "; @@ -2106,7 +1726,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_SetExceptionLacksParameter() + public void BuilderOnMethod_SetExceptionLacksParameter() { var source = $@" using System; @@ -2114,24 +1734,21 @@ public void BuilderFactoryOnMethod_SetExceptionLacksParameter() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException(Exception e)", "public void SetException()")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(Exception e)", "public void SetException()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetException(System.Exception e)", "public void SetException()")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(System.Exception e)", "public void SetException()")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2149,7 +1766,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_SetResultIsInternal() + public void BuilderOnMethod_SetResultIsInternal() { var source = $@" using System; @@ -2157,24 +1774,21 @@ public void BuilderFactoryOnMethod_SetResultIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetResult", "internal void SetResult")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetResult", "internal void SetResult")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2192,7 +1806,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_AwaitOnCompletedIsInternal() + public void BuilderOnMethod_AwaitOnCompletedIsInternal() { var source = $@" using System; @@ -2200,24 +1814,21 @@ public void BuilderFactoryOnMethod_AwaitOnCompletedIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2235,7 +1846,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_AwaitUnsafeOnCompletedIsInternal() + public void BuilderOnMethod_AwaitUnsafeOnCompletedIsInternal() { var source = $@" using System; @@ -2243,24 +1854,21 @@ public void BuilderFactoryOnMethod_AwaitUnsafeOnCompletedIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2278,7 +1886,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_StartIsInternal() + public void BuilderOnMethod_StartIsInternal() { var source = $@" using System; @@ -2286,24 +1894,21 @@ public void BuilderFactoryOnMethod_StartIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void Start", "internal void Start")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void Start", "internal void Start")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2321,7 +1926,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_SetStateMachineIsInternal() + public void BuilderOnMethod_SetStateMachineIsInternal() { var source = $@" using System; @@ -2329,24 +1934,21 @@ public void BuilderFactoryOnMethod_SetStateMachineIsInternal() using System.Threading.Tasks; class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask")} - -[AsyncMethodBuilder(null)] {AwaitableTypeCode("MyTask", "T")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetStateMachine", "internal void SetStateMachine")} -{AsyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public void SetStateMachine", "internal void SetStateMachine")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -2364,7 +1966,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_AsyncMethodReturnsTask() + public void BuilderOnMethod_AsyncMethodReturnsTask() { var source = $@" using System; @@ -2375,23 +1977,19 @@ public void BuilderFactoryOnMethod_AsyncMethodReturnsTask() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async Task F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async Task G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] public static async Task M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -public class MyTaskMethodBuilderFactory -{{ - public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); -}} - public class MyTaskMethodBuilder {{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); internal MyTaskMethodBuilder() {{ }} public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} @@ -2402,13 +2000,9 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter public Task Task => System.Threading.Tasks.Task.CompletedTask; }} -public class MyTaskMethodBuilderFactory -{{ - public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); -}} - public class MyTaskMethodBuilder {{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); internal MyTaskMethodBuilder() {{ }} public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} @@ -2428,7 +2022,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } [Fact] - public void BuilderFactoryOnMethod_AsyncMethodReturnsValueTask() + public void BuilderOnMethod_AsyncMethodReturnsValueTask() { var source = $@" using System; @@ -2439,23 +2033,19 @@ public void BuilderFactoryOnMethod_AsyncMethodReturnsValueTask() class C {{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async ValueTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async ValueTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] public static async ValueTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -public class MyTaskMethodBuilderFactory -{{ - public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); -}} - public class MyTaskMethodBuilder {{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); internal MyTaskMethodBuilder() {{ }} public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} @@ -2466,13 +2056,9 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter public ValueTask Task => new ValueTask(System.Threading.Tasks.Task.CompletedTask); }} -public class MyTaskMethodBuilderFactory -{{ - public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); -}} - public class MyTaskMethodBuilder {{ + public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(); private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); internal MyTaskMethodBuilder() {{ }} public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} @@ -2489,93 +2075,33 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter var compilation = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (10,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(10, 6), // (13,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(13, 6), // (16,6): warning CS0436: The type 'AsyncMethodBuilderAttribute' in '' conflicts with the imported type 'AsyncMethodBuilderAttribute' in 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Using the type defined in ''. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] + // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "AsyncMethodBuilder").WithArguments("", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute", "System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", "System.Runtime.CompilerServices.AsyncMethodBuilderAttribute").WithLocation(16, 6) ); CompileAndVerify(compilation, expectedOutput: "M F G 3"); } [Fact] - public void BuilderFactoryOnMethod_WrongAccessibilityForFinalBuilderMembers() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -[AsyncMethodBuilder(null)] public class T1 {{ }} -[AsyncMethodBuilder(null)] public class T2 {{ }} -[AsyncMethodBuilder(null)] internal class T3 {{ }} -[AsyncMethodBuilder(null)] internal class T4 {{ }} - -{AsyncBuilderFactoryCode("B1", "T1")} - -{AsyncBuilderFactoryCode("B2", "T2") - .Replace("public class B2", "internal class B2") - .Replace("internal class B2Factory", "public class B2Factory") - .Replace("public static B2 Create()", "internal static B2 Create()")} - -{AsyncBuilderFactoryCode("B3", "T3") - .Replace("public T3 Task =>", "internal T3 Task =>")} - -{AsyncBuilderFactoryCode("B4", "T4") - .Replace("public class B4", "internal class B4") - .Replace("internal class B4Factory", "public class B4Factory") - .Replace("public static B4 Create()", "internal static B4 Create()")} - -class Program -{{ - [AsyncMethodBuilder(typeof(B1Factory))] - async T1 f1() => await Task.Delay(1); - - [AsyncMethodBuilder(typeof(B2Factory))] - async T2 f2() => await Task.Delay(2); - - [AsyncMethodBuilder(typeof(B3Factory))] - async T3 f3() => await Task.Delay(3); - - [AsyncMethodBuilder(typeof(B4Factory))] - async T4 f4() => await Task.Delay(4); -}} - -{AsyncMethodBuilderAttribute} -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - comp.VerifyEmitDiagnostics( - // (97,19): error CS0656: Missing compiler required member 'B2Factory.Create' - // async T2 f2() => await Task.Delay(2); - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(2)").WithArguments("B2Factory", "Create").WithLocation(97, 19), - // (100,19): error CS0656: Missing compiler required member 'B3.Task' - // async T3 f3() => await Task.Delay(3); - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("B3", "Task").WithLocation(100, 19), - // (103,19): error CS0656: Missing compiler required member 'B4Factory.Create' - // async T4 f4() => await Task.Delay(4); - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(4)").WithArguments("B4Factory", "Create").WithLocation(103, 19) - ); - } - - [Fact] - public void BuilderFactoryOnMethod_InternalReturnType() + public void BuilderOnMethod_InternalReturnType() { var source = $@" -using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; [AsyncMethodBuilder(null)] internal class MyTaskType {{ }} // Make the builder factory and the builder internal as well -{AsyncBuilderFactoryCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } +{AsyncBuilderCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } class C {{ - [AsyncMethodBuilder(typeof(MyTaskTypeBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskTypeBuilder))] async MyTaskType M() => await Task.Delay(4); }} @@ -2586,7 +2112,7 @@ class C } [Fact] - public void BuilderFactoryOnMethod_IntReturnType() + public void BuilderOnMethod_IntReturnType() { var source = $@" using System; @@ -2599,17 +2125,13 @@ public void BuilderFactoryOnMethod_IntReturnType() public class C {{ - [AsyncMethodBuilder(typeof(MyTaskTypeBuilderFactory))] + [AsyncMethodBuilder(typeof(MyTaskTypeBuilder))] public async int M() => await Task.Delay(4); }} -public class MyTaskTypeBuilderFactory -{{ - public static MyTaskTypeBuilder Create() => new MyTaskTypeBuilder(); -}} - public class MyTaskTypeBuilder {{ + public static MyTaskTypeBuilder Create() => new MyTaskTypeBuilder(); public void SetStateMachine(IAsyncStateMachine stateMachine) {{ }} public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {{ stateMachine.MoveNext(); }} public void SetException(Exception e) {{ }} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 34fbbf6a8a0f..912e4313b3fe 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -109,10 +109,10 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -162,6 +162,65 @@ .locals init (C.d__1 V_0) }"); } + [Fact] + public void AsyncMethod_NullBuilder() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class C +{ + static async MyTask F() { await Task.Delay(0); } + static async MyTask G(T t) { await Task.Delay(0); return t; } + static async MyTask M() { await F(); return await G(3); } +} +[AsyncMethodBuilder(null)] +struct MyTask +{ + internal Awaiter GetAwaiter() => new Awaiter(); + internal class Awaiter : INotifyCompletion + { + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal void GetResult() { } + } +} +[AsyncMethodBuilder(null)] +struct MyTask +{ + internal T _result; + public T Result => _result; + internal Awaiter GetAwaiter() => new Awaiter(this); + internal class Awaiter : INotifyCompletion + { + private readonly MyTask _task; + internal Awaiter(MyTask task) { _task = task; } + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal T GetResult() => _task.Result; + } +} + +namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } +"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyEmitDiagnostics( + // (6,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask F() { await Task.Delay(0); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await Task.Delay(0); }").WithLocation(6, 29), + // (7,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask G(T t) { await Task.Delay(0); return t; } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await Task.Delay(0); return t; }").WithLocation(7, 38), + // (8,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator + // static async MyTask M() { await F(); return await G(3); } + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await F(); return await G(3); }").WithLocation(8, 34), + // (24,16): warning CS0649: Field 'MyTask._result' is never assigned to, and will always have its default value + // internal T _result; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "_result").WithArguments("MyTask._result", "").WithLocation(24, 16) + ); + } + [Fact] public void AsyncMethod_CreateHasRefReturn() { @@ -434,11 +493,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.F()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.G()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -515,11 +574,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.<>c.b__3_1()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -594,11 +653,11 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : var testData = verifier.TestData; var method = (MethodSymbol)testData.GetMethodData("C.g__F|0_0()").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); method = (MethodSymbol)testData.GetMethodData("C.g__G|0_1(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation, out _)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } From ee207cb9a47d181c2552a94f272b960f3b728b25 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 15:47:04 -0700 Subject: [PATCH 19/24] tweaks --- .../AsyncMethodBuilderMemberCollection.cs | 18 +++---- .../Portable/Symbols/Source/LambdaSymbol.cs | 1 - .../CodeGenAsyncMethodBuilderOverrideTests.cs | 52 +++---------------- 3 files changed, 16 insertions(+), 55 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index dcc1b4969b2f..c7e06193825b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -185,11 +185,11 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool forOverride = method.HasAsyncMethodBuilder(out methodLevelBuilder); + bool useMethodLevelBuilder = method.HasAsyncMethodBuilder(out methodLevelBuilder); bool customBuilder; object builderArgument; - if (forOverride) + if (useMethodLevelBuilder) { customBuilder = true; builderArgument = methodLevelBuilder; @@ -201,7 +201,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false, forOverride); + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false, useMethodLevelBuilder); if ((object)builderType != null) { taskProperty = GetCustomTaskProperty(F, builderType, returnType); @@ -266,11 +266,11 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool forOverride = method.HasAsyncMethodBuilder(out methodLevelBuilder); + bool useMethodLevelBuilder = method.HasAsyncMethodBuilder(out methodLevelBuilder); bool customBuilder; object builderArgument; - if (forOverride) + if (useMethodLevelBuilder) { customBuilder = true; builderArgument = methodLevelBuilder; @@ -282,7 +282,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, forOverride); + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, useMethodLevelBuilder); if ((object)builderType != null) { builderType = builderType.ConstructedFrom.Construct(resultType); @@ -336,14 +336,14 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, throw ExceptionUtilities.UnexpectedValue(method); } - private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric, bool forOverride = false) + private static NamedTypeSymbol ValidateBuilderType(SyntheticBoundNodeFactory F, object builderAttributeArgument, Accessibility desiredAccessibility, bool isGeneric, bool forMethodLevelBuilder = false) { var builderType = builderAttributeArgument as NamedTypeSymbol; if ((object)builderType != null && !builderType.IsErrorType() && !builderType.IsVoidType() && - (forOverride || builderType.DeclaredAccessibility == desiredAccessibility)) + (forMethodLevelBuilder || builderType.DeclaredAccessibility == desiredAccessibility)) { bool isArityOk = isGeneric ? builderType.IsUnboundGenericType && builderType.ContainingType?.IsGenericType != true && builderType.Arity == 1 @@ -456,8 +456,6 @@ private static bool TryGetBuilderMember( return true; } - // For method-level builders, we allow the `Create` method to return a different type. - // We'll just use that type as the final builder type. private static MethodSymbol GetCustomCreateMethod( SyntheticBoundNodeFactory F, NamedTypeSymbol builderType) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index d2f441222b70..7f670a1bc00a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -283,7 +283,6 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) if (this.HasAsyncMethodBuilder(out _)) { - // This will need to be adjusted to account for explicit return type on lambdas addTo.Add(ErrorCode.ERR_BuilderAttributeDisallowed, DiagnosticLocation); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 80d996df8b41..8afde402ce94 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -77,9 +77,10 @@ public void OnCompleted(Action a) {{ }} } [Theory] - [InlineData("typeof(MyTaskMethodBuilder)")] - [InlineData("typeof(object)")] - [InlineData("null")] + [InlineData("[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]")] + [InlineData("[AsyncMethodBuilder(typeof(object))]")] + [InlineData("[AsyncMethodBuilder(null)]")] + [InlineData("")] public void BuilderOnMethod_DummyBuilderOnType(string dummyBuilder) { var source = $@" @@ -101,10 +102,10 @@ class C public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} }} -[AsyncMethodBuilder({dummyBuilder})] +{dummyBuilder} {AwaitableTypeCode("MyTask")} -[AsyncMethodBuilder({dummyBuilder})] +{dummyBuilder} {AwaitableTypeCode("MyTask", "T")} {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} @@ -183,44 +184,7 @@ .locals init (C.d__1 V_0) } [Fact] - public void BuilderOnMethod_NoBuilderOnType() - { - var source = $@" -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -Console.WriteLine(await C.M()); - -class C -{{ - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] - static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} - - [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] - public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} -}} - -// no attribute -{AwaitableTypeCode("MyTask")} - -// no attribute -{AwaitableTypeCode("MyTask", "T")} - -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} -{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} - -{AsyncMethodBuilderAttribute} -"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); - } - - [Fact] - public void BuilderOnMethod_NoBuilderOnType_Nullability() + public void BuilderOnMethod_Nullability() { var source = $@" #nullable enable @@ -274,7 +238,7 @@ public static async MyTask M() } [Fact] - public void BuilderOnMethod_NoBuilderOnType_BadReturns() + public void BuilderOnMethod_BadReturns() { var source = $@" using System; From ec32fb2e450d6b7668e1541d73a2cb67d9c4c8d9 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 18:23:54 -0700 Subject: [PATCH 20/24] Address feedback --- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 23 +++++++- .../BindingAsyncTasklikeMoreTests.cs | 59 ------------------- 2 files changed, 20 insertions(+), 62 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 8afde402ce94..e0a904a5c748 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -694,7 +694,7 @@ class C {AwaitableTypeCode("MyTask", "T")} {asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} -{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T")} +{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); @@ -767,7 +767,22 @@ public void BuilderOnMethod_OnLambda() {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + compilation.VerifyEmitDiagnostics( + // (6,18): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]").WithArguments("lambda attributes").WithLocation(6, 18), + // (6,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(6, 84), + // (8,23): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]").WithArguments("lambda attributes").WithLocation(8, 23), + // (8,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(8, 84) + ); + compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (6,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; @@ -800,7 +815,9 @@ public void BuilderOnMethod_OnLambda_WithExplicitType() {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + //compilation.VerifyEmitDiagnostics(); + compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); // This test will be revisited once explicit lambda return types are allowed Assert.Equal(18, compilation.GetDiagnostics().Length); //var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 912e4313b3fe..896ca5c3e4cb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -162,65 +162,6 @@ .locals init (C.d__1 V_0) }"); } - [Fact] - public void AsyncMethod_NullBuilder() - { - var source = -@"using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -class C -{ - static async MyTask F() { await Task.Delay(0); } - static async MyTask G(T t) { await Task.Delay(0); return t; } - static async MyTask M() { await F(); return await G(3); } -} -[AsyncMethodBuilder(null)] -struct MyTask -{ - internal Awaiter GetAwaiter() => new Awaiter(); - internal class Awaiter : INotifyCompletion - { - public void OnCompleted(Action a) { } - internal bool IsCompleted => true; - internal void GetResult() { } - } -} -[AsyncMethodBuilder(null)] -struct MyTask -{ - internal T _result; - public T Result => _result; - internal Awaiter GetAwaiter() => new Awaiter(this); - internal class Awaiter : INotifyCompletion - { - private readonly MyTask _task; - internal Awaiter(MyTask task) { _task = task; } - public void OnCompleted(Action a) { } - internal bool IsCompleted => true; - internal T GetResult() => _task.Result; - } -} - -namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } -"; - var compilation = CreateCompilationWithMscorlib45(source); - compilation.VerifyEmitDiagnostics( - // (6,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask F() { await Task.Delay(0); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await Task.Delay(0); }").WithLocation(6, 29), - // (7,38): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask G(T t) { await Task.Delay(0); return t; } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await Task.Delay(0); return t; }").WithLocation(7, 38), - // (8,34): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // static async MyTask M() { await F(); return await G(3); } - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "{ await F(); return await G(3); }").WithLocation(8, 34), - // (24,16): warning CS0649: Field 'MyTask._result' is never assigned to, and will always have its default value - // internal T _result; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "_result").WithArguments("MyTask._result", "").WithLocation(24, 16) - ); - } - [Fact] public void AsyncMethod_CreateHasRefReturn() { From 7da7da7c5455a6521b34caf3d4e5468a23b40f73 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 21 Jun 2021 20:09:38 -0700 Subject: [PATCH 21/24] Integrate explicit return types and builder overrides --- .../Portable/Symbols/Source/LambdaSymbol.cs | 2 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 93 +++++++++++-------- 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 37e83d977ec7..5427025ebb4e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -287,7 +287,7 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) GetReturnTypeAttributes(); AsyncMethodChecks(verifyReturnType: HasExplicitReturnType, DiagnosticLocation, _declarationDiagnostics); - if (this.HasAsyncMethodBuilder(out _)) + if (!HasExplicitReturnType && this.HasAsyncMethodBuilder(out _)) { addTo.Add(ErrorCode.ERR_BuilderAttributeDisallowed, DiagnosticLocation); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e0a904a5c748..e31ca9088991 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -772,15 +772,21 @@ public void BuilderOnMethod_OnLambda() // (6,18): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]").WithArguments("lambda attributes").WithLocation(6, 18), - // (6,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (6,84): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(6, 84), + // (6,84): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=>").WithArguments("async method builder override").WithLocation(6, 84), // (8,23): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]").WithArguments("lambda attributes").WithLocation(8, 23), - // (8,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (8,84): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; - Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(8, 84) + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(8, 84), + // (8,84): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=>").WithArguments("async method builder override").WithLocation(8, 84) ); compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( @@ -801,9 +807,9 @@ public void BuilderOnMethod_OnLambda_WithExplicitType() using System.Runtime.CompilerServices; using System.Threading.Tasks; -var f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async MyTask () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; -var m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] async MyTask () => {{ System.Console.Write(""M ""); await f(); return 3; }}; +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async MyTask () => {{ System.Console.Write(""M ""); await f(); return 3; }}; Console.WriteLine(await m()); return; @@ -816,12 +822,30 @@ public void BuilderOnMethod_OnLambda_WithExplicitType() {AsyncMethodBuilderAttribute} "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); - //compilation.VerifyEmitDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (6,18): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]").WithArguments("lambda attributes").WithLocation(6, 18), + // (6,81): error CS8652: The feature 'lambda return type' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "MyTask").WithArguments("lambda return type").WithLocation(6, 81), + // (6,91): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => { System.Console.Write("F "); await Task.Delay(0); }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=>").WithArguments("async method builder override").WithLocation(6, 91), + // (8,23): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async MyTask () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]").WithArguments("lambda attributes").WithLocation(8, 23), + // (8,81): error CS8652: The feature 'lambda return type' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async MyTask () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "MyTask").WithArguments("lambda return type").WithLocation(8, 81), + // (8,96): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async MyTask () => { System.Console.Write("M "); await f(); return 3; }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=>").WithArguments("async method builder override").WithLocation(8, 96) + ); + compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - // This test will be revisited once explicit lambda return types are allowed - Assert.Equal(18, compilation.GetDiagnostics().Length); - //var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); - //verifier.VerifyDiagnostics(); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + verifier.VerifyDiagnostics(); } [Fact] @@ -862,24 +886,12 @@ public class C "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (7,71): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (7,71): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(7, 71), - // (7,71): error CS1643: Not all code paths return a value in lambda expression of type 'Func>' - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 - Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func>").WithLocation(7, 71), - // (11,73): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 73), - // (11,133): error CS8031: Async lambda expression converted to a 'Task' returning delegate cannot return a value. Did you intend to return 'Task'? + // (11,73): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequiredLambda, "return").WithLocation(11, 133), - // (11,140): error CS0029: Cannot implicitly convert type 'int' to 'string' - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(11, 140), - // (11,140): error CS4010: Cannot convert async lambda expression to delegate type 'MyTask'. An async lambda expression may return void, Task or Task, none of which are convertible to 'MyTask'. - // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 - Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "3").WithArguments("lambda expression", "MyTask").WithLocation(11, 140) + Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 73) ); var tree = compilation.SyntaxTrees.Single(); @@ -903,11 +915,11 @@ public void BuilderOnMethod_OnLambda_NotTaskLikeTypes_ExplicitReturnType() using System.Threading.Tasks; C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory))] static async MyTask () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 ); C.F( - [AsyncMethodBuilder(typeof(MyTaskMethodBuilderFactory<>))] static async MyTask () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async MyTask () => {{ System.Console.Write(""Lambda2 ""); await Task.Delay(0); return 3; }} // 2 ); await Task.Delay(0); @@ -930,22 +942,21 @@ public class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - // We'll need to adjust this test once explicit return types are allowed on lambdas var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); - Assert.Equal(20, compilation.GetDiagnostics().Length); - - //var tree = compilation.SyntaxTrees.Single(); - //var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); - //var lambdas = tree.GetRoot().DescendantNodes().OfType().ToArray(); - //var firstLambda = model.GetTypeInfo(lambdas[0]); - //Assert.Null(firstLambda.Type); - //Assert.Equal("System.Func", firstLambda.ConvertedType.ToTestDisplayString()); - - //var secondLambda = model.GetTypeInfo(lambdas[1]); - //Assert.Null(secondLambda.Type); - //Assert.Equal("System.Func", secondLambda.ConvertedType.ToTestDisplayString()); - } + var verifier = CompileAndVerify(compilation, expectedOutput: "Overload1 Lambda1 Overload2 Lambda2"); + verifier.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + var lambdas = tree.GetRoot().DescendantNodes().OfType().ToArray(); + var firstLambda = model.GetTypeInfo(lambdas[0]); + Assert.Null(firstLambda.Type); + Assert.Equal("System.Func", firstLambda.ConvertedType.ToTestDisplayString()); + var secondLambda = model.GetTypeInfo(lambdas[1]); + Assert.Null(secondLambda.Type); + Assert.Equal("System.Func>", secondLambda.ConvertedType.ToTestDisplayString()); + } [Fact] public void BuilderOnMethod_TaskPropertyHasObjectType() From 9440d0ff08c79370e516386c7942047759e932be Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 23 Jun 2021 11:55:58 -0700 Subject: [PATCH 22/24] Adjust error code in tests --- .../CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index e31ca9088991..7879745d7133 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -772,7 +772,7 @@ public void BuilderOnMethod_OnLambda() // (6,18): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]").WithArguments("lambda attributes").WithLocation(6, 18), - // (6,84): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (6,84): error CS8935: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(6, 84), // (6,84): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -781,7 +781,7 @@ public void BuilderOnMethod_OnLambda() // (8,23): error CS8652: The feature 'lambda attributes' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; Diagnostic(ErrorCode.ERR_FeatureInPreview, "[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]").WithArguments("lambda attributes").WithLocation(8, 23), - // (8,84): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (8,84): error CS8935: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(8, 84), // (8,84): error CS8652: The feature 'async method builder override' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -886,10 +886,10 @@ public class C "; var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( - // (7,71): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (7,71): error CS8935: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(7, 71), - // (11,73): error CS8934: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. + // (11,73): error CS8935: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] static async () => { System.Console.Write("Lambda2 "); await Task.Delay(0); return 3; } // 2 Diagnostic(ErrorCode.ERR_BuilderAttributeDisallowed, "=>").WithLocation(11, 73) ); From a576b8cc918352f05d21d774b005ac06ab8a7c24 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 23 Jun 2021 15:08:48 -0700 Subject: [PATCH 23/24] Address feedback --- .../AsyncMethodBuilderMemberCollection.cs | 4 +- .../Symbols/MethodSymbolExtensions.cs | 4 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 2 +- .../SourceMethodSymbolWithAttributes.cs | 2 +- .../Portable/Symbols/SymbolExtensions.cs | 4 +- .../Portable/Symbols/TypeSymbolExtensions.cs | 2 +- .../CodeGenAsyncMethodBuilderOverrideTests.cs | 40 +++++++++---------- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index c7e06193825b..5ee14ef41bb4 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -185,7 +185,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool useMethodLevelBuilder = method.HasAsyncMethodBuilder(out methodLevelBuilder); + bool useMethodLevelBuilder = method.HasAsyncMethodBuilderAttribute(out methodLevelBuilder); bool customBuilder; object builderArgument; @@ -266,7 +266,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - bool useMethodLevelBuilder = method.HasAsyncMethodBuilder(out methodLevelBuilder); + bool useMethodLevelBuilder = method.HasAsyncMethodBuilderAttribute(out methodLevelBuilder); bool customBuilder; object builderArgument; diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index f1a7b7af12a3..a194aea394fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -163,7 +163,7 @@ public static bool IsAsyncEffectivelyReturningTask(this MethodSymbol method, CSh { return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 0 } - && (method.HasAsyncMethodBuilder(builderArgument: out _) || method.ReturnType.IsNonGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilderAttribute(builderArgument: out _) || method.ReturnType.IsNonGenericTaskType(compilation)); } /// @@ -173,7 +173,7 @@ public static bool IsAsyncEffectivelyReturningGenericTask(this MethodSymbol meth { return method.IsAsync && method.ReturnType is NamedTypeSymbol { Arity: 1 } - && (method.HasAsyncMethodBuilder(builderArgument: out _) || method.ReturnType.IsGenericTaskType(compilation)); + && (method.HasAsyncMethodBuilderAttribute(builderArgument: out _) || method.ReturnType.IsGenericTaskType(compilation)); } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 5427025ebb4e..99bcd710cec2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -287,7 +287,7 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) GetReturnTypeAttributes(); AsyncMethodChecks(verifyReturnType: HasExplicitReturnType, DiagnosticLocation, _declarationDiagnostics); - if (!HasExplicitReturnType && this.HasAsyncMethodBuilder(out _)) + if (!HasExplicitReturnType && this.HasAsyncMethodBuilderAttribute(out _)) { addTo.Add(ErrorCode.ERR_BuilderAttributeDisallowed, DiagnosticLocation); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 893e968e49b0..38add35774f9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1062,7 +1062,7 @@ protected void AsyncMethodChecks(bool verifyReturnType, Location errorLocation, } } - if (this.HasAsyncMethodBuilder(out _)) + if (this.HasAsyncMethodBuilderAttribute(out _)) { hasErrors |= MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); } diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs index 904eb8e239c3..725ddccbd34d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs @@ -817,10 +817,10 @@ internal static ImmutableArray GetPublicSymbols(this Immutable } /// - /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the "B". + /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the type B. /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. /// - internal static bool HasAsyncMethodBuilder(this Symbol symbol, [NotNullWhen(true)] out object? builderArgument) + internal static bool HasAsyncMethodBuilderAttribute(this Symbol symbol, [NotNullWhen(true)] out object? builderArgument) { Debug.Assert(symbol is not null); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index fb5952ed7be2..82efcc15fda5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1647,7 +1647,7 @@ internal static bool IsCustomTaskType(this NamedTypeSymbol type, [NotNullWhen(tr var arity = type.Arity; if (arity < 2) { - return type.HasAsyncMethodBuilder(out builderArgument); + return type.HasAsyncMethodBuilderAttribute(out builderArgument); } builderArgument = null; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 7879745d7133..05c335b270a6 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -295,7 +295,7 @@ class C } [Fact] - public void BuilderOnMethod_BadBuilderOnType() + public void BuilderOnMethod_IgnoreBadBuilderOnType() { var source = $@" using System; @@ -333,7 +333,7 @@ class C } [Fact] - public void BuilderOnMethod_BadBuilderOnType_CreateReturnsInt() + public void BuilderOnMethod_IgnoreBadBuilderOnType_CreateReturnsInt() { var source = $@" using System; @@ -371,7 +371,7 @@ class C } [Fact] - public void BuilderOnMethod_BadBuilderOnType_TaskPropertyReturnsInt() + public void BuilderOnMethod_IgnoreBadBuilderOnType_TaskPropertyReturnsInt() { var source = $@" using System; @@ -409,7 +409,7 @@ class C } [Fact] - public void BuilderOnMethod_BadBuilderOnType_SetExceptionIsInternal() + public void BuilderOnMethod_IgnoreBadBuilderOnType_SetExceptionIsInternal() { var source = $@" using System; @@ -449,7 +449,7 @@ class C } [Fact] - public void BuilderOnMethod_BadBuilderOnType_SetResultIsInternal() + public void BuilderOnMethod_IgnoreBadBuilderOnType_SetResultIsInternal() { var source = $@" using System; @@ -629,17 +629,17 @@ class C } [Fact] - public void BuilderOnMethod_WrongAccessibility() + public void BuilderOnMethod_IgnoreBuilderTypeAccessibility() { var source = $@" using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; -[AsyncMethodBuilder(typeof(B1))] public class T1 {{ }} -[AsyncMethodBuilder(typeof(B2))] public class T2 {{ }} -[AsyncMethodBuilder(typeof(B3))] internal class T3 {{ }} -[AsyncMethodBuilder(typeof(B4))] internal class T4 {{ }} +public class T1 {{ }} +public class T2 {{ }} +internal class T3 {{ }} +internal class T4 {{ }} {AsyncBuilderCode("B1", "T1").Replace("public class B1", "public class B1")} {AsyncBuilderCode("B2", "T2").Replace("public class B2", "internal class B2")} @@ -648,23 +648,19 @@ public void BuilderOnMethod_WrongAccessibility() class Program {{ - async T1 f1() => await Task.Delay(1); - async T2 f2() => await Task.Delay(2); - async T3 f3() => await Task.Delay(3); - async T4 f4() => await Task.Delay(4); + [AsyncMethodBuilder(typeof(B1))] public async T1 F1() => await Task.Delay(1); + [AsyncMethodBuilder(typeof(B2))] public async T2 F2() => await Task.Delay(2); + [AsyncMethodBuilder(typeof(B3))] internal async T3 F3() => await Task.Delay(3); + [AsyncMethodBuilder(typeof(B4))] internal async T4 F4() => await Task.Delay(4); }} {AsyncMethodBuilderAttribute} "; - - var comp = CreateCompilation(source); + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyEmitDiagnostics( - // (75,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // async T2 f2() => await Task.Delay(2); - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(2)").WithLocation(75, 19), - // (76,19): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator - // async T3 f3() => await Task.Delay(3); - Diagnostic(ErrorCode.ERR_BadAsyncReturn, "=> await Task.Delay(3)").WithLocation(76, 19) + // (76,61): error CS0656: Missing compiler required member 'B3.Task' + // [AsyncMethodBuilder(typeof(B3))] internal async T3 F3() => await Task.Delay(3); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> await Task.Delay(3)").WithArguments("B3", "Task").WithLocation(76, 61) ); } From 36b5a5dd1071cc9837cb581d3b9c469d4db5d6de Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 23 Jun 2021 15:17:25 -0700 Subject: [PATCH 24/24] typo --- src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs index 725ddccbd34d..7a27991ad852 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs @@ -817,7 +817,7 @@ internal static ImmutableArray GetPublicSymbols(this Immutable } /// - /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns the type B. + /// Returns true if the method has a [AsyncMethodBuilder(typeof(B))] attribute. If so it returns type B. /// Validation of builder type B is left for elsewhere. This method returns B without validation of any kind. /// internal static bool HasAsyncMethodBuilderAttribute(this Symbol symbol, [NotNullWhen(true)] out object? builderArgument)