diff --git a/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.cs index c56b455bfe22b..f2f06e2f86496 100644 --- a/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionDiagnosticAnalyzer.cs @@ -31,18 +31,21 @@ public ConvertSwitchStatementToExpressionDiagnosticAnalyzer() } protected override void InitializeWorker(AnalysisContext context) - => context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.SwitchStatement); + => context.RegisterCompilationStartAction(context => + { + if (((CSharpCompilation)context.Compilation).LanguageVersion < LanguageVersion.CSharp8) + { + return; + } + + context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.SwitchStatement); + }); private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) { var switchStatement = context.Node; var syntaxTree = switchStatement.SyntaxTree; - if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp8) - { - return; - } - var options = context.Options; var cancellationToken = context.CancellationToken; diff --git a/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticDiagnosticAnalyzer.cs index a8fbf6b30189d..161b1405373c9 100644 --- a/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticDiagnosticAnalyzer.cs @@ -30,8 +30,7 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() protected override void InitializeWorker(AnalysisContext context) => context.RegisterCompilationStartAction(context => { - // All trees are expected to have the same language version. So make the check only once in compilation start . - if (context.Compilation.SyntaxTrees.FirstOrDefault() is SyntaxTree tree && MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(tree)) + if (MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpCompilation)context.Compilation).LanguageVersion)) { context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.LocalFunctionStatement); } diff --git a/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticHelper.cs b/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticHelper.cs index fa231237471cb..aea838130096a 100644 --- a/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticHelper.cs +++ b/src/Analyzers/CSharp/Analyzers/MakeLocalFunctionStatic/MakeLocalFunctionStaticHelper.cs @@ -13,8 +13,8 @@ namespace Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic { internal static class MakeLocalFunctionStaticHelper { - public static bool IsStaticLocalFunctionSupported(SyntaxTree tree) - => tree.Options is CSharpParseOptions csharpOption && csharpOption.LanguageVersion >= LanguageVersion.CSharp8; + public static bool IsStaticLocalFunctionSupported(LanguageVersion languageVersion) + => languageVersion >= LanguageVersion.CSharp8; private static bool TryGetDataFlowAnalysis(LocalFunctionStatementSyntax localFunction, SemanticModel semanticModel, [NotNullWhen(returnValue: true)] out DataFlowAnalysis? dataFlow) { diff --git a/src/Analyzers/CSharp/Analyzers/RemoveUnnecessaryDiscardDesignation/CSharpRemoveUnnecessaryDiscardDesignationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/RemoveUnnecessaryDiscardDesignation/CSharpRemoveUnnecessaryDiscardDesignationDiagnosticAnalyzer.cs index ba718ddb08926..a95e482559fd8 100644 --- a/src/Analyzers/CSharp/Analyzers/RemoveUnnecessaryDiscardDesignation/CSharpRemoveUnnecessaryDiscardDesignationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/RemoveUnnecessaryDiscardDesignation/CSharpRemoveUnnecessaryDiscardDesignationDiagnosticAnalyzer.cs @@ -2,11 +2,9 @@ // 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.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryDiscardDesignation { @@ -32,15 +30,19 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() protected override void InitializeWorker(AnalysisContext context) { - context.RegisterSyntaxNodeAction(AnalyzeDiscardDesignation, SyntaxKind.DiscardDesignation); + context.RegisterCompilationStartAction(context => + { + if (((CSharpCompilation)context.Compilation).LanguageVersion < LanguageVersion.CSharp9) + { + return; + } + + context.RegisterSyntaxNodeAction(AnalyzeDiscardDesignation, SyntaxKind.DiscardDesignation); + }); } private void AnalyzeDiscardDesignation(SyntaxNodeAnalysisContext context) { - var syntaxTree = context.SemanticModel.SyntaxTree; - if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp9) - return; - var discard = (DiscardDesignationSyntax)context.Node; if (discard.Parent is DeclarationPatternSyntax) { diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs index 8991f49e506e9..7c799f9af62d9 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs @@ -22,8 +22,8 @@ internal class CSharpUseCollectionInitializerDiagnosticAnalyzer : ExpressionStatementSyntax, VariableDeclaratorSyntax> { - protected override bool AreCollectionInitializersSupported(SyntaxNodeAnalysisContext context) - => ((CSharpParseOptions)context.Node.SyntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp3; + protected override bool AreCollectionInitializersSupported(Compilation compilation) + => ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp3; protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; } diff --git a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForCastAndEqualityOperatorDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForCastAndEqualityOperatorDiagnosticAnalyzer.cs index b7b54e7ea9c99..30287bc049515 100644 --- a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForCastAndEqualityOperatorDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForCastAndEqualityOperatorDiagnosticAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -32,7 +30,15 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; protected override void InitializeWorker(AnalysisContext context) - => context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression); + => context.RegisterCompilationStartAction(context => + { + if (((CSharpCompilation)context.Compilation).LanguageVersion < LanguageVersion.CSharp7) + { + return; + } + + context.RegisterSyntaxNodeAction(n => AnalyzeSyntax(n), SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression); + }); private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) { @@ -41,11 +47,6 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) var semanticModel = context.SemanticModel; var syntaxTree = semanticModel.SyntaxTree; - if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp7) - { - return; - } - var option = context.Options.GetOption(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, semanticModel.Language, syntaxTree, cancellationToken); if (!option.Value) { diff --git a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.cs index ea5674f5ad0cc..44bd1fca2e535 100644 --- a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.cs @@ -17,11 +17,11 @@ public CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer() { } - protected override bool IsLanguageVersionSupported(ParseOptions options) - => ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp7; + protected override bool IsLanguageVersionSupported(Compilation compilation) + => ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp7; - protected override bool IsUnconstrainedGenericSupported(ParseOptions options) - => ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp8; + protected override bool IsUnconstrainedGenericSupported(Compilation compilation) + => ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp8; protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; diff --git a/src/Analyzers/CSharp/Analyzers/UseNullPropagation/CSharpUseNullPropagationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseNullPropagation/CSharpUseNullPropagationDiagnosticAnalyzer.cs index a07f8852d5877..ed6603c859ffb 100644 --- a/src/Analyzers/CSharp/Analyzers/UseNullPropagation/CSharpUseNullPropagationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseNullPropagation/CSharpUseNullPropagationDiagnosticAnalyzer.cs @@ -25,8 +25,8 @@ internal class CSharpUseNullPropagationDiagnosticAnalyzer : ConditionalAccessExpressionSyntax, ElementAccessExpressionSyntax> { - protected override bool ShouldAnalyze(ParseOptions options) - => ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp6; + protected override bool ShouldAnalyze(Compilation compilation) + => ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp6; protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; diff --git a/src/Analyzers/CSharp/Analyzers/UseObjectInitializer/CSharpUseObjectInitializerDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseObjectInitializer/CSharpUseObjectInitializerDiagnosticAnalyzer.cs index ad4499cee50b2..74fd38b60904b 100644 --- a/src/Analyzers/CSharp/Analyzers/UseObjectInitializer/CSharpUseObjectInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseObjectInitializer/CSharpUseObjectInitializerDiagnosticAnalyzer.cs @@ -23,11 +23,11 @@ internal class CSharpUseObjectInitializerDiagnosticAnalyzer : { protected override bool FadeOutOperatorToken => true; - protected override bool AreObjectInitializersSupported(SyntaxNodeAnalysisContext context) + protected override bool AreObjectInitializersSupported(Compilation compilation) { // object initializers are only available in C# 3.0 and above. Don't offer this refactoring // in projects targeting a lesser version. - return ((CSharpParseOptions)context.Node.SyntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp3; + return ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp3; } protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpUseNotPatternDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpUseNotPatternDiagnosticAnalyzer.cs index 193abe6b07fad..2ac35553102e6 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpUseNotPatternDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternMatching/CSharpUseNotPatternDiagnosticAnalyzer.cs @@ -40,7 +40,15 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() protected override void InitializeWorker(AnalysisContext context) { - context.RegisterSyntaxNodeAction(SyntaxNodeAction, SyntaxKind.LogicalNotExpression); + context.RegisterCompilationStartAction(context => + { + // "x is not Type y" is only available in C# 9.0 and above. Don't offer this refactoring + // in projects targeting a lesser version. + if (!((CSharpCompilation)context.Compilation).LanguageVersion.IsCSharp9OrAbove()) + return; + + context.RegisterSyntaxNodeAction(n => SyntaxNodeAction(n), SyntaxKind.LogicalNotExpression); + }); } private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) @@ -48,11 +56,6 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) var node = syntaxContext.Node; var syntaxTree = node.SyntaxTree; - // "x is not Type y" is only available in C# 9.0 and above. Don't offer this refactoring - // in projects targeting a lesser version. - if (!((CSharpParseOptions)syntaxTree.Options).LanguageVersion.IsCSharp9OrAbove()) - return; - var options = syntaxContext.Options; var cancellationToken = syntaxContext.CancellationToken; diff --git a/src/Analyzers/CSharp/Analyzers/UseThrowExpression/CSharpUseThrowExpressionDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseThrowExpression/CSharpUseThrowExpressionDiagnosticAnalyzer.cs index 8b1fde6a78e21..814b536e2be7d 100644 --- a/src/Analyzers/CSharp/Analyzers/UseThrowExpression/CSharpUseThrowExpressionDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseThrowExpression/CSharpUseThrowExpressionDiagnosticAnalyzer.cs @@ -20,10 +20,9 @@ public CSharpUseThrowExpressionDiagnosticAnalyzer() { } - protected override bool IsSupported(ParseOptions options) + protected override bool IsSupported(Compilation compilation) { - var csOptions = (CSharpParseOptions)options; - return csOptions.LanguageVersion >= LanguageVersion.CSharp7; + return ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp7; } protected override bool IsInExpressionTree(SemanticModel semanticModel, SyntaxNode node, INamedTypeSymbol expressionTypeOpt, CancellationToken cancellationToken) diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs index 76b71f6619ed0..f38ca3a28b7d0 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs @@ -47,6 +47,11 @@ protected override void InitializeWorker(AnalysisContext context) private void OnCompilationStart(CompilationStartAnalysisContext context) { + if (!AreCollectionInitializersSupported(context.Compilation)) + { + return; + } + var ienumerableType = context.Compilation.GetTypeByMetadataName(typeof(IEnumerable).FullName!); if (ienumerableType != null) { @@ -57,15 +62,10 @@ private void OnCompilationStart(CompilationStartAnalysisContext context) } } - protected abstract bool AreCollectionInitializersSupported(SyntaxNodeAnalysisContext context); + protected abstract bool AreCollectionInitializersSupported(Compilation compilation); private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ienumerableType) { - if (!AreCollectionInitializersSupported(context)) - { - return; - } - var semanticModel = context.SemanticModel; var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; diff --git a/src/Analyzers/Core/Analyzers/UseIsNullCheck/AbstractUseIsNullForReferenceEqualsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseIsNullCheck/AbstractUseIsNullForReferenceEqualsDiagnosticAnalyzer.cs index 7291e43a8ca6e..62530ec8162f3 100644 --- a/src/Analyzers/Core/Analyzers/UseIsNullCheck/AbstractUseIsNullForReferenceEqualsDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseIsNullCheck/AbstractUseIsNullForReferenceEqualsDiagnosticAnalyzer.cs @@ -29,10 +29,10 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; protected override void InitializeWorker(AnalysisContext context) - => context.RegisterCompilationStartAction(compilationContext => + => context.RegisterCompilationStartAction(context => { - var objectType = compilationContext.Compilation.GetSpecialType(SpecialType.System_Object); - if (objectType != null) + var objectType = context.Compilation.GetSpecialType(SpecialType.System_Object); + if (objectType != null && IsLanguageVersionSupported(context.Compilation)) { var referenceEqualsMethod = objectType.GetMembers(nameof(ReferenceEquals)) .OfType() @@ -41,27 +41,23 @@ protected override void InitializeWorker(AnalysisContext context) if (referenceEqualsMethod != null) { var syntaxKinds = GetSyntaxFacts().SyntaxKinds; + var unconstraintedGenericSupported = IsUnconstrainedGenericSupported(context.Compilation); context.RegisterSyntaxNodeAction( - c => AnalyzeSyntax(c, referenceEqualsMethod), + c => AnalyzeSyntax(c, referenceEqualsMethod, unconstraintedGenericSupported), syntaxKinds.Convert(syntaxKinds.InvocationExpression)); } } }); - protected abstract bool IsLanguageVersionSupported(ParseOptions options); - protected abstract bool IsUnconstrainedGenericSupported(ParseOptions options); + protected abstract bool IsLanguageVersionSupported(Compilation compilation); + protected abstract bool IsUnconstrainedGenericSupported(Compilation compilation); protected abstract ISyntaxFacts GetSyntaxFacts(); - private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol referenceEqualsMethod) + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol referenceEqualsMethod, bool unconstraintedGenericSupported) { var cancellationToken = context.CancellationToken; var semanticModel = context.SemanticModel; - var syntaxTree = semanticModel.SyntaxTree; - if (!IsLanguageVersionSupported(syntaxTree.Options)) - { - return; - } var option = context.GetOption(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, semanticModel.Language); if (!option.Value) @@ -125,7 +121,7 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol refe // HasReferenceTypeConstraint returns false for base type constraint. // IsReferenceType returns true. - if (!genericParameterSymbol.IsReferenceType && !IsUnconstrainedGenericSupported(syntaxTree.Options)) + if (!genericParameterSymbol.IsReferenceType && !unconstraintedGenericSupported) { // Needs special casing for C# as long as // 'is null' over unconstrained generic is implemented in C# 8. diff --git a/src/Analyzers/Core/Analyzers/UseNullPropagation/AbstractUseNullPropagationDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseNullPropagation/AbstractUseNullPropagationDiagnosticAnalyzer.cs index 1a43358bf74ba..ea9f9e977b8c3 100644 --- a/src/Analyzers/Core/Analyzers/UseNullPropagation/AbstractUseNullPropagationDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseNullPropagation/AbstractUseNullPropagationDiagnosticAnalyzer.cs @@ -47,7 +47,7 @@ protected AbstractUseNullPropagationDiagnosticAnalyzer() public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - protected abstract bool ShouldAnalyze(ParseOptions options); + protected abstract bool ShouldAnalyze(Compilation compilation); protected abstract ISyntaxFacts GetSyntaxFacts(); protected abstract bool IsInExpressionTree(SemanticModel semanticModel, SyntaxNode node, INamedTypeSymbol? expressionTypeOpt, CancellationToken cancellationToken); @@ -60,6 +60,11 @@ protected override void InitializeWorker(AnalysisContext context) { context.RegisterCompilationStartAction(startContext => { + if (!ShouldAnalyze(startContext.Compilation)) + { + return; + } + var expressionTypeOpt = startContext.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1"); var objectType = startContext.Compilation.GetSpecialType(SpecialType.System_Object); @@ -82,10 +87,6 @@ private void AnalyzeSyntax( IMethodSymbol? referenceEqualsMethodOpt) { var conditionalExpression = (TConditionalExpressionSyntax)context.Node; - if (!ShouldAnalyze(conditionalExpression.SyntaxTree.Options)) - { - return; - } var option = context.GetOption(CodeStyleOptions2.PreferNullPropagation, conditionalExpression.Language); if (!option.Value) diff --git a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs index f5289a98739af..594e19e567d0a 100644 --- a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs @@ -42,21 +42,24 @@ protected AbstractUseObjectInitializerDiagnosticAnalyzer() protected override void InitializeWorker(AnalysisContext context) { var syntaxKinds = GetSyntaxFacts().SyntaxKinds; - context.RegisterSyntaxNodeAction( - AnalyzeNode, syntaxKinds.Convert(syntaxKinds.ObjectCreationExpression)); + context.RegisterCompilationStartAction(context => + { + if (!AreObjectInitializersSupported(context.Compilation)) + { + return; + } + + context.RegisterSyntaxNodeAction( + AnalyzeNode, syntaxKinds.Convert(syntaxKinds.ObjectCreationExpression)); + }); } - protected abstract bool AreObjectInitializersSupported(SyntaxNodeAnalysisContext context); + protected abstract bool AreObjectInitializersSupported(Compilation compilation); protected abstract bool IsValidContainingStatement(TStatementSyntax node); private void AnalyzeNode(SyntaxNodeAnalysisContext context) { - if (!AreObjectInitializersSupported(context)) - { - return; - } - var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node; var language = objectCreationExpression.Language; var option = context.GetOption(CodeStyleOptions2.PreferObjectInitializer, language); diff --git a/src/Analyzers/Core/Analyzers/UseThrowExpression/AbstractUseThrowExpressionDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseThrowExpression/AbstractUseThrowExpressionDiagnosticAnalyzer.cs index 2dd41cdd8d6a4..4b513c65bd2ee 100644 --- a/src/Analyzers/Core/Analyzers/UseThrowExpression/AbstractUseThrowExpressionDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseThrowExpression/AbstractUseThrowExpressionDiagnosticAnalyzer.cs @@ -52,12 +52,17 @@ protected AbstractUseThrowExpressionDiagnosticAnalyzer(Option2 DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - protected abstract bool IsSupported(ParseOptions options); + protected abstract bool IsSupported(Compilation compilation); protected override void InitializeWorker(AnalysisContext context) { context.RegisterCompilationStartAction(startContext => { + if (!IsSupported(startContext.Compilation)) + { + return; + } + var expressionTypeOpt = startContext.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1"); startContext.RegisterOperationAction(operationContext => AnalyzeOperation(operationContext, expressionTypeOpt), OperationKind.Throw); }); @@ -65,12 +70,6 @@ protected override void InitializeWorker(AnalysisContext context) private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol expressionTypeOpt) { - var syntaxTree = context.Operation.Syntax.SyntaxTree; - if (!IsSupported(syntaxTree.Options)) - { - return; - } - var cancellationToken = context.CancellationToken; var throwOperation = (IThrowOperation)context.Operation; diff --git a/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicUseCollectionInitializerDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicUseCollectionInitializerDiagnosticAnalyzer.vb index c2989fb540790..65c1409ee484f 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicUseCollectionInitializerDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicUseCollectionInitializerDiagnosticAnalyzer.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer ExpressionStatementSyntax, VariableDeclaratorSyntax) - Protected Overrides Function AreCollectionInitializersSupported(context As SyntaxNodeAnalysisContext) As Boolean + Protected Overrides Function AreCollectionInitializersSupported(compilation As Compilation) As Boolean Return True End Function diff --git a/src/Analyzers/VisualBasic/Analyzers/UseIsNullCheck/VisualBasicUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseIsNullCheck/VisualBasicUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.vb index d9e5b5be74811..f528c0a7aa400 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseIsNullCheck/VisualBasicUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseIsNullCheck/VisualBasicUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer.vb @@ -16,11 +16,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseIsNullCheck MyBase.New(VisualBasicAnalyzersResources.Use_Is_Nothing_check) End Sub - Protected Overrides Function IsLanguageVersionSupported(options As ParseOptions) As Boolean + Protected Overrides Function IsLanguageVersionSupported(compilation As Compilation) As Boolean Return True End Function - Protected Overrides Function IsUnconstrainedGenericSupported(options As ParseOptions) As Boolean + Protected Overrides Function IsUnconstrainedGenericSupported(compilation As Compilation) As Boolean Return True End Function diff --git a/src/Analyzers/VisualBasic/Analyzers/UseNullPropagation/VisualBasicUseNullPropagationDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseNullPropagation/VisualBasicUseNullPropagationDiagnosticAnalyzer.vb index f016303bd7d38..925ce785b3e2b 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseNullPropagation/VisualBasicUseNullPropagationDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseNullPropagation/VisualBasicUseNullPropagationDiagnosticAnalyzer.vb @@ -22,8 +22,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation ConditionalAccessExpressionSyntax, InvocationExpressionSyntax) - Protected Overrides Function ShouldAnalyze(options As ParseOptions) As Boolean - Return DirectCast(options, VisualBasicParseOptions).LanguageVersion >= LanguageVersion.VisualBasic14 + Protected Overrides Function ShouldAnalyze(compilation As Compilation) As Boolean + Return DirectCast(compilation, VisualBasicCompilation).LanguageVersion >= LanguageVersion.VisualBasic14 End Function Protected Overrides Function GetSyntaxFacts() As ISyntaxFacts diff --git a/src/Analyzers/VisualBasic/Analyzers/UseObjectInitializer/VisualBasicUseObjectInitializerDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseObjectInitializer/VisualBasicUseObjectInitializerDiagnosticAnalyzer.vb index 5f5dad08c996d..73088cd3cec6d 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseObjectInitializer/VisualBasicUseObjectInitializerDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseObjectInitializer/VisualBasicUseObjectInitializerDiagnosticAnalyzer.vb @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseObjectInitializer End Get End Property - Protected Overrides Function AreObjectInitializersSupported(context As SyntaxNodeAnalysisContext) As Boolean + Protected Overrides Function AreObjectInitializersSupported(compilation As Compilation) As Boolean 'Object Initializers are supported in all the versions of Visual Basic we support Return True End Function diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 984acdf2d1bcd..24f36003c8f29 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -8640,15 +8640,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: @@ -8678,13 +8678,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); } 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 61b2fc8a05b18..71e10dcfc1e58 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); } public BoundStatement BindExpressionStatement(ExpressionStatementSyntax node, BindingDiagnosticBag diagnostics) @@ -2656,16 +2656,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); } - 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); } protected bool IsIAsyncEnumerableOrIAsyncEnumeratorReturningAsyncMethod() @@ -2768,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() || IsEffectivelyTaskReturningAsyncMethod()) { if (arg != null) { @@ -2808,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 = IsEffectivelyGenericTaskReturningAsyncMethod() ? retType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single() : retType; @@ -2851,7 +2851,7 @@ internal BoundExpression CreateReturnConversion( { Debug.Assert(returnRefKind == RefKind.None); - if (!IsGenericTaskReturningAsyncMethod()) + if (!IsEffectivelyGenericTaskReturningAsyncMethod()) { conversion = Conversion.NoConversion; badAsyncReturnAlreadyReported = true; @@ -2888,7 +2888,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); @@ -3177,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() || 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 c1782b14daabb..6b2a7b7bcd5f1 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -570,21 +570,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 { }); @@ -716,7 +701,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); @@ -731,8 +716,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) && + !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/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 9ebd949e96a0c..101de6a04cc5a 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6588,6 +6588,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 @@ -6713,4 +6716,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The using directive appeared previously as global using + + 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 4e2345bfefc9a..14dccabc41a11 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1957,10 +1957,10 @@ internal enum ErrorCode ERR_InterfaceImplementedByUnmanagedCallersOnlyMethod = 8932, HDN_DuplicateWithGlobalUsing = 8933, ERR_CantConvAnonMethReturnType = 8934, + ERR_BuilderAttributeDisallowed = 8935, #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/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index b0f72bd3bc10b..f546e04f67af6 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -227,6 +227,7 @@ internal enum MessageID IDS_FeatureExtendedPropertyPatterns = MessageBase + 12802, IDS_FeatureStaticAbstractMembersInInterfaces = MessageBase + 12803, IDS_FeatureLambdaReturnType = MessageBase + 12804, + IDS_AsyncMethodBuilderOverride = MessageBase + 12805, } // Message IDs may refer to strings that need to be localized. @@ -346,6 +347,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureExtendedPropertyPatterns: case MessageID.IDS_FeatureStaticAbstractMembersInInterfaces: // semantic check case MessageID.IDS_FeatureLambdaReturnType: // semantic check + case MessageID.IDS_AsyncMethodBuilderOverride: // semantic check return LanguageVersion.Preview; // C# 9.0 features. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index a138883fe13ba..cb6480c0e4ef7 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)) { // 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 c7fbfd6fbb9ab..6cad61e9557d2 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2558,7 +2558,7 @@ private bool TryGetReturnType(out TypeWithAnnotations type, out FlowAnalysisAnno return true; } - if (returnType.Type.IsGenericTaskType(compilation)) + 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 f2d72b5841fdf..5ee14ef41bb43 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( @@ -178,18 +178,30 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningTask(F.Compilation)) + object methodLevelBuilder = null; + if (method.IsAsyncEffectivelyReturningTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - + bool useMethodLevelBuilder = method.HasAsyncMethodBuilderAttribute(out methodLevelBuilder); + bool customBuilder; object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); + + if (useMethodLevelBuilder) + { + customBuilder = true; + builderArgument = methodLevelBuilder; + } + else + { + customBuilder = returnType.IsCustomTaskType(out builderArgument); + } + if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false, useMethodLevelBuilder); if ((object)builderType != null) { taskProperty = GetCustomTaskProperty(F, builderType, returnType); @@ -213,13 +225,15 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, customBuilder, out taskProperty); } + if ((object)builderType == null || (object)createBuilderMethod == null || (object)taskProperty == null) { - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, @@ -236,7 +250,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, collection: out collection); } - if (method.IsAsyncReturningGenericTask(F.Compilation)) + if (method.IsAsyncEffectivelyReturningGenericTask(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType; var resultType = returnType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; @@ -252,12 +266,23 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; - + bool useMethodLevelBuilder = method.HasAsyncMethodBuilderAttribute(out methodLevelBuilder); + bool customBuilder; object builderArgument; - bool customBuilder = returnType.IsCustomTaskType(out builderArgument); + + if (useMethodLevelBuilder) + { + customBuilder = true; + builderArgument = methodLevelBuilder; + } + else + { + customBuilder = returnType.IsCustomTaskType(out builderArgument); + } + if (customBuilder) { - builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); + builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true, useMethodLevelBuilder); if ((object)builderType != null) { builderType = builderType.ConstructedFrom.Construct(resultType); @@ -283,13 +308,15 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, customBuilder, out taskProperty); } + if ((object)builderType == null || (object)taskProperty == null || (object)createBuilderMethod == null) { - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } + return TryCreate( F, customBuilder: customBuilder, @@ -309,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) + 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() && - builderType.DeclaredAccessibility == desiredAccessibility) + (forMethodLevelBuilder || builderType.DeclaredAccessibility == desiredAccessibility)) { bool isArityOk = isGeneric ? builderType.IsUnboundGenericType && builderType.ContainingType?.IsGenericType != true && builderType.Arity == 1 @@ -376,7 +403,7 @@ private static bool TryCreate( return true; } - collection = default(AsyncMethodBuilderMemberCollection); + collection = default; return false; } @@ -448,6 +475,7 @@ private static MethodSymbol GetCustomCreateMethod( method.IsStatic && method.ParameterCount == 0 && !method.IsGenericMethod && + method.RefKind == RefKind.None && 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 d0a1e0d94bdfc..de5d554e25fa2 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) ? 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) ? 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)); 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 6ff5ef7702a84..a194aea394fcc 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 { @@ -146,6 +147,7 @@ private static bool CanBeHiddenByMethodPropertyOrType(MethodSymbol method) } } +#nullable enable /// /// Returns whether this method is async and returns void. /// @@ -155,21 +157,23 @@ 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) { return method.IsAsync - && method.ReturnType.IsNonGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 0 } + && (method.HasAsyncMethodBuilderAttribute(builderArgument: out _) || 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) { return method.IsAsync - && method.ReturnType.IsGenericTaskType(compilation); + && method.ReturnType is NamedTypeSymbol { Arity: 1 } + && (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 87528154a4d92..99bcd710cec2f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -287,6 +287,11 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) GetReturnTypeAttributes(); AsyncMethodChecks(verifyReturnType: HasExplicitReturnType, DiagnosticLocation, _declarationDiagnostics); + if (!HasExplicitReturnType && this.HasAsyncMethodBuilderAttribute(out _)) + { + addTo.Add(ErrorCode.ERR_BuilderAttributeDisallowed, DiagnosticLocation); + } + addTo.AddRange(_declarationDiagnostics, allowMismatchInDependencyAccumulation: true); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 1a15a16564f7e..38add35774f99 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1055,13 +1055,18 @@ protected void AsyncMethodChecks(bool verifyReturnType, Location errorLocation, ReportBadRefToken(returnTypeSyntax, diagnostics); hasErrors = true; } - else if (ReturnType.IsBadAsyncReturn(this.DeclaringCompilation)) + else if (isBadAsyncReturn(this)) { diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, errorLocation); hasErrors = true; } } + if (this.HasAsyncMethodBuilderAttribute(out _)) + { + hasErrors |= MessageID.IDS_AsyncMethodBuilderOverride.CheckFeatureAvailability(diagnostics, this.DeclaringCompilation, errorLocation); + } + // Avoid checking attributes on containing types to avoid a potential cycle when a lambda // is used in an attribute argument - see https://github.com/dotnet/roslyn/issues/54074. // (ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct was never reported @@ -1111,6 +1116,18 @@ protected void AsyncMethodChecks(bool verifyReturnType, Location errorLocation, } } } + + 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) && + !methodSymbol.IsAsyncEffectivelyReturningGenericTask(declaringCompilation); + } } private static FlowAnalysisAnnotations DecodeReturnTypeAnnotationAttributes(ReturnTypeWellKnownAttributeData attributeData) diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs index eb072757a2b2e..7a27991ad8521 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 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) + { + 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 3a591f09912b0..82efcc15fda5e 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 AsyncBuilder 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.HasAsyncMethodBuilderAttribute(out builderArgument); } builderArgument = null; @@ -1938,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/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 9164dd9543b06..59d825d7da375 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 470382fd1bf1d..e9f447119329a 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 ea303496baa89..bb633c2ce8821 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 c4653c2128624..3b853ad18cdda 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 30968e1a96522..02d1eb287ffad 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 17607739a3dbf..a74e38ed2cc86 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 0c89d13191ea3..70922f4ba8a6f 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 cc30f229c917b..dc03bb3294151 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 4c067444dc231..4d2226d58d979 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 5bea2ab0ddac8..1135d72b83a5e 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 187ac6098100b..4b5b79e20b7dd 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 666e7e2b04687..bb6ccf4ed5f12 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 296ac3afde3e7..d53c890a82f76 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. @@ -1077,6 +1082,11 @@ The using directive appeared previously as global using + + 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 0000000000000..05c335b270a69 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -0,0 +1,2140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.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; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen +{ + 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 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("[AsyncMethodBuilder(typeof(MyTaskMethodBuilder))]")] + [InlineData("[AsyncMethodBuilder(typeof(object))]")] + [InlineData("[AsyncMethodBuilder(null)]")] + [InlineData("")] + 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); }} +}} + +{dummyBuilder} +{AwaitableTypeCode("MyTask")} + +{dummyBuilder} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + 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); } + 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, 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.IsAsyncEffectivelyReturningTask(compilation)); + method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; + Assert.True(method.IsAsync); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); + 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 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 53 (0x35) + .maxstack 2 + .locals init (C.d__1 V_0) + 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 +} +"); + } + + [Fact] + public void BuilderOnMethod_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_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,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) + ); + } + + [Fact] + public void BuilderOnMethod_IgnoreBadBuilderOnType() + { + 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_IgnoreBadBuilderOnType_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_IgnoreBadBuilderOnType_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_IgnoreBadBuilderOnType_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_IgnoreBadBuilderOnType_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)")] + [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} +"; + 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); } + 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, 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_IgnoreBuilderTypeAccessibility() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +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")} +{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 +{{ + [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, parseOptions: TestOptions.RegularPreview); + comp.VerifyEmitDiagnostics( + // (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) + ); + } + + [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); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask")} +{asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + 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) + ); + + 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; +}} +"; + } + } + + [Fact] + public void BuilderOnMethod_OnLambda() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; + +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => {{ System.Console.Write(""M ""); await f(); return 3; }}; + +Console.WriteLine(await m()); +return; + +{AwaitableTypeCode("MyTask", isStruct: true)} +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + 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 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. + // 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 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. + // 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( + // (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 BuilderOnMethod_OnLambda_WithExplicitType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => {{ System.Console.Write(""F ""); await Task.Delay(0); }}; + +Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async MyTask () => {{ System.Console.Write(""M ""); await f(); return 3; }}; + +Console.WriteLine(await m()); +return; + +{AwaitableTypeCode("MyTask", isStruct: true)} +{AwaitableTypeCode("MyTask", "T", isStruct: true)} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + 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 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); + var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_OnLambda_NotTaskLikeTypes_InferReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 +); + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] 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)} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (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 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) + ); + + 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_OnLambda_NotTaskLikeTypes_ExplicitReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => {{ System.Console.Write(""Lambda1 ""); await Task.Delay(0); }} // 1 +); + +C.F( + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] 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)} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + 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() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_CreateMissing() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") + .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Theory] + [InlineData("internal")] + [InlineData("private")] + public void BuilderOnMethod_CreateNotPublic(string accessibility) + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_CreateNotStatic() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_CreateHasParameter() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_CreateIsGeneric() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_CreateHasRefReturn() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") + .Replace( + "public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", + "public static ref MyTaskMethodBuilder Create() => throw null;")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_BuilderIsInternal() + { + 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); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderOnMethod_BuilderIsPrivate() + { + 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); }} + + {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask").Replace("public class MyTaskMethodBuilder", "private class MyTaskMethodBuilder")} + {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilder", "private class MyTaskMethodBuilder")} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(compilation, expectedOutput: "M F G 3"); + } + + [Fact] + public void BuilderOnMethod_CreateIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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 '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("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("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("MyTaskMethodBuilder", "Create").WithLocation(14, 34) + ); + } + + [Fact] + public void BuilderOnMethod_TwoMethodLevelAttributes() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + [AsyncMethodBuilder(null)] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + [AsyncMethodBuilder(null)] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + [AsyncMethodBuilder(null)] + public static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", isStruct: true)} +{AsyncBuilderCode("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 BuilderOnMethod_TwoMethodLevelAttributes_ReverseOrder() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(null)] + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask")} +{AsyncBuilderCode("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 BuilderOnMethod_BoundGeneric_TypeParameter() + { + var source = $@" +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); throw null; }} +}} + +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T")} + +{AsyncMethodBuilderAttribute} +"; + var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyEmitDiagnostics( + // (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 BuilderOnMethod_BoundGeneric_SpecificType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async MyTask M() {{ await Task.Delay(0); throw null; }} +}} + +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("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 BuilderOnMethod_TaskPropertyIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_TaskPropertyIsStatic() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_TaskPropertyIsField() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_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(MyTaskMethodBuilder<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_SetExceptionReturnsObject() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask") + .Replace("public void SetException(System.Exception e) { }", "public object SetException(System.Exception e) => null;")} + +{AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T") + .Replace("public void SetException(System.Exception e) { }", "public object SetException(System.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 BuilderOnMethod_SetExceptionLacksParameter() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_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(MyTaskMethodBuilder<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_AwaitOnCompletedIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_AwaitUnsafeOnCompletedIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_StartIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_SetStateMachineIsInternal() + { + 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<>))] + static async MyTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +{AwaitableTypeCode("MyTask")} +{AwaitableTypeCode("MyTask", "T")} + +{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); + 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 BuilderOnMethod_AsyncMethodReturnsTask() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async Task F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async Task G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async Task M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +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(); }} + 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 MyTaskMethodBuilder +{{ + public static MyTaskMethodBuilder Create() => new 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 BuilderOnMethod_AsyncMethodReturnsValueTask() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +Console.WriteLine(await C.M()); + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] + static async ValueTask F() {{ System.Console.Write(""F ""); await Task.Delay(0); }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + static async ValueTask G(T t) {{ System.Console.Write(""G ""); await Task.Delay(0); return t; }} + + [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] + public static async ValueTask M() {{ System.Console.Write(""M ""); await F(); return await G(3); }} +}} + +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(); }} + 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 MyTaskMethodBuilder +{{ + public static MyTaskMethodBuilder Create() => new 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(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(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(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 BuilderOnMethod_InternalReturnType() + { + var source = $@" +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +[AsyncMethodBuilder(null)] internal class MyTaskType {{ }} + +// Make the builder factory and the builder internal as well +{AsyncBuilderCode("MyTaskTypeBuilder", "MyTaskType").Replace("public class MyTaskType", "internal class MyTaskType") } + +class C +{{ + [AsyncMethodBuilder(typeof(MyTaskTypeBuilder))] + async MyTaskType M() => await Task.Delay(4); +}} + +{AsyncMethodBuilderAttribute} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void BuilderOnMethod_IntReturnType() + { + var source = $@" +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +System.Console.Write(new C().M()); + +[AsyncMethodBuilder(typeof(IgnoredTaskMethodBuilder))] public class MyTaskType {{ }} + +public class C +{{ + [AsyncMethodBuilder(typeof(MyTaskTypeBuilder))] + public async int M() => await Task.Delay(4); +}} + +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) {{ }} + 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); + 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 58ea912c7c82c..896ca5c3e4cbe 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)); method = (MethodSymbol)testData.GetMethodData("C.G(T)").Method; Assert.True(method.IsAsync); - Assert.True(method.IsAsyncReturningGenericTask(compilation)); + Assert.True(method.IsAsyncEffectivelyReturningGenericTask(compilation)); verifier.VerifyIL("C.F()", @"{ // Code size 49 (0x31) @@ -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() { @@ -254,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)); 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)); Assert.Equal("C.MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -335,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)); 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)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } @@ -414,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)); 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)); Assert.Equal("MyTask", method.ReturnTypeWithAnnotations.ToDisplayString()); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 6ba5ae11f78a7..226260166b8ab 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) diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs index 233566094f888..2132e02303889 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs @@ -27,7 +27,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var (document, textSpan, cancellationToken) = context; var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false))!; - if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(syntaxTree)) + if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)syntaxTree.Options).LanguageVersion)) { return; } diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs index f1d0a0b23f14c..d2d9b23211f3c 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs @@ -78,7 +78,7 @@ private static async Task WrapFixAsync( // Even when the language version doesn't support staic local function, the compiler will still // generate this error. So we need to check to make sure we don't provide incorrect fix. - if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(root.SyntaxTree)) + if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)root.SyntaxTree.Options).LanguageVersion)) { return; }