diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 9e078424051a2..b64ffb101ed45 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -1512,9 +1512,8 @@ bool CheckValid(MethodSymbol candidate, bool isCandidate, DiagnosticBag specific { foreach (var (IsValid, Candidate, SpecificDiagnostics) in taskEntryPoints) { - // PROTOTYPE(async-main): Get the diagnostic to point to a smaller syntax piece. if (CheckValid(Candidate, IsValid, SpecificDiagnostics) && - CheckFeatureAvailability(Candidate.GetNonNullSyntaxNode(), MessageID.IDS_FeatureAsyncMain, diagnostics)) + CheckFeatureAvailability(Candidate.ExtractReturnTypeSyntax(), MessageID.IDS_FeatureAsyncMain, diagnostics)) { diagnostics.AddRange(SpecificDiagnostics); viableEntryPoints.Add(Candidate); @@ -1611,7 +1610,6 @@ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, DiagnosticBag dia var syntax = method.ExtractReturnTypeSyntax(); var dumbInstance = new BoundLiteral(syntax, ConstantValue.Null, method.ReturnType); - // PROTOTYPE(async-main): We might need to adjust the containing member of the binder to be the Main method var binder = GetBinder(syntax); BoundExpression result; var success = binder.GetAwaitableExpressionInfo(dumbInstance, out _, out _, out _, out result, syntax, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 731985d09b33f..d16155984fb51 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -206,9 +206,9 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul // entryPoint can be a SynthesizedEntryPointSymbol if a script is being compiled. SynthesizedEntryPointSymbol synthesizedEntryPoint = entryPoint as SynthesizedEntryPointSymbol; - if ((object)synthesizedEntryPoint == null && compilation.ReturnsAwaitableToVoidOrInt(entryPoint, diagnostics)) + if ((object)synthesizedEntryPoint == null && (entryPoint.ReturnType.IsGenericTaskType(compilation) || entryPoint.ReturnType.IsNonGenericTaskType(compilation))) { - synthesizedEntryPoint = new SynthesizedEntryPointSymbol.AsyncForwardEntryPoint(compilation, diagnostics, entryPoint.ContainingType, entryPoint); + synthesizedEntryPoint = new SynthesizedEntryPointSymbol.AsyncForwardEntryPoint(compilation, entryPoint.ContainingType, entryPoint); entryPoint = synthesizedEntryPoint; if ((object)moduleBeingBuilt != null) { @@ -221,13 +221,44 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul !hasDeclarationErrors && !diagnostics.HasAnyErrors()) { - var body = synthesizedEntryPoint.CreateBody(); + BoundStatement body = synthesizedEntryPoint.CreateBody(); + + var dynamicAnalysisSpans = ImmutableArray.Empty; + VariableSlotAllocator lazyVariableSlotAllocator = null; + var lambdaDebugInfoBuilder = ArrayBuilder.GetInstance(); + var closureDebugInfoBuilder = ArrayBuilder.GetInstance(); + StateMachineTypeSymbol stateMachineTypeOpt = null; const int methodOrdinal = -1; + + var loweredBody = LowerBodyOrInitializer( + synthesizedEntryPoint, + methodOrdinal, + body, + null, + new TypeCompilationState(synthesizedEntryPoint.ContainingType, compilation, moduleBeingBuilt), + false, + null, + ref dynamicAnalysisSpans, + diagnostics, + ref lazyVariableSlotAllocator, + lambdaDebugInfoBuilder, + closureDebugInfoBuilder, + out stateMachineTypeOpt); + + Debug.Assert((object)lazyVariableSlotAllocator == null); + Debug.Assert((object)stateMachineTypeOpt == null); + Debug.Assert(dynamicAnalysisSpans.IsEmpty); + Debug.Assert(lambdaDebugInfoBuilder.IsEmpty()); + Debug.Assert(closureDebugInfoBuilder.IsEmpty()); + + lambdaDebugInfoBuilder.Free(); + closureDebugInfoBuilder.Free(); + var emittedBody = GenerateMethodBody( moduleBeingBuilt, synthesizedEntryPoint, methodOrdinal, - body, + loweredBody, ImmutableArray.Empty, ImmutableArray.Empty, stateMachineTypeOpt: null, diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 826b6d3ae3d80..7dff9eb3426f5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -19,8 +19,6 @@ internal abstract class SynthesizedEntryPointSymbol : MethodSymbol internal const string FactoryName = ""; private readonly NamedTypeSymbol _containingType; - // PROTOTYPE(async-main): remove this and move it out into inheriting classes? - private TypeSymbol _returnType; internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitializerMethod initializerMethod, DiagnosticBag diagnostics) { @@ -57,12 +55,11 @@ internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitial } } - private SynthesizedEntryPointSymbol(NamedTypeSymbol containingType, TypeSymbol returnType = null) + private SynthesizedEntryPointSymbol(NamedTypeSymbol containingType) { Debug.Assert((object)containingType != null); _containingType = containingType; - _returnType = returnType; } internal override bool GenerateDebugInfo @@ -130,11 +127,6 @@ internal override RefKind RefKind get { return RefKind.None; } } - public override TypeSymbol ReturnType - { - get { return _returnType; } - } - public override ImmutableArray ReturnTypeCustomModifiers { get { return ImmutableArray.Empty; } @@ -162,7 +154,7 @@ public override int Arity public override bool ReturnsVoid { - get { return _returnType.SpecialType == SpecialType.System_Void; } + get { return ReturnType.SpecialType == SpecialType.System_Void; } } public override MethodKind MethodKind @@ -341,7 +333,7 @@ internal sealed class AsyncForwardEntryPoint : SynthesizedEntryPointSymbol private readonly ImmutableArray _parameters; - internal AsyncForwardEntryPoint(CSharpCompilation compilation, DiagnosticBag diagnosticBag, NamedTypeSymbol containingType, MethodSymbol userMain) : + internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol containingType, MethodSymbol userMain) : base(containingType) { // There should be no way for a userMain to be passed in unless it already passed the @@ -349,7 +341,6 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, DiagnosticBag dia Debug.Assert(userMain.ParameterCount == 0 || userMain.ParameterCount == 1); _userMainReturnTypeSyntax = userMain.ExtractReturnTypeSyntax(); - // PROTOTYPE(async-main): we might need to adjust the containing member of the binder to be the Main method. var binder = compilation.GetBinder(_userMainReturnTypeSyntax); _parameters = SynthesizedParameterSymbol.DeriveParameters(userMain, this); @@ -371,9 +362,10 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, DiagnosticBag dia type: userMain.ReturnType) { WasCompilerGenerated = true }; - // PROTOTYPE(async-main): lower the tree. - var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _, out _, out _, out _getAwaiterGetResultCall, _userMainReturnTypeSyntax, diagnosticBag); - _returnType = _getAwaiterGetResultCall.Type; + // The diagnostics that would be produced here will already have been captured and returned. + var droppedBag = DiagnosticBag.GetInstance(); + var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _, out _, out _, out _getAwaiterGetResultCall, _userMainReturnTypeSyntax, droppedBag); + droppedBag.Free(); Debug.Assert( ReturnType.SpecialType == SpecialType.System_Void || @@ -384,6 +376,8 @@ internal AsyncForwardEntryPoint(CSharpCompilation compilation, DiagnosticBag dia public override ImmutableArray Parameters => _parameters; + public override TypeSymbol ReturnType => _getAwaiterGetResultCall.Type; + internal override BoundBlock CreateBody() { var syntax = _userMainReturnTypeSyntax; @@ -432,21 +426,25 @@ private sealed class ScriptEntryPoint : SynthesizedEntryPointSymbol { private readonly MethodSymbol _getAwaiterMethod; private readonly MethodSymbol _getResultMethod; + private readonly TypeSymbol _returnType; internal ScriptEntryPoint(NamedTypeSymbol containingType, TypeSymbol returnType, MethodSymbol getAwaiterMethod, MethodSymbol getResultMethod) : - base(containingType, returnType) + base(containingType) { Debug.Assert(containingType.IsScriptClass); Debug.Assert(returnType.SpecialType == SpecialType.System_Void); _getAwaiterMethod = getAwaiterMethod; _getResultMethod = getResultMethod; + _returnType = returnType; } public override string Name => MainName; public override ImmutableArray Parameters => ImmutableArray.Empty; + public override TypeSymbol ReturnType => _returnType; + // private static void
() // { // var script = new Script(); @@ -516,13 +514,15 @@ internal override BoundBlock CreateBody() private sealed class SubmissionEntryPoint : SynthesizedEntryPointSymbol { private readonly ImmutableArray _parameters; + private readonly TypeSymbol _returnType; internal SubmissionEntryPoint(NamedTypeSymbol containingType, TypeSymbol returnType, TypeSymbol submissionArrayType) : - base(containingType, returnType) + base(containingType) { Debug.Assert(containingType.IsSubmissionClass); Debug.Assert(returnType.SpecialType != SpecialType.System_Void); _parameters = ImmutableArray.Create(SynthesizedParameterSymbol.Create(this, submissionArrayType, 0, RefKind.None, "submissionArray")); + _returnType = returnType; } public override string Name @@ -535,6 +535,8 @@ public override ImmutableArray Parameters get { return _parameters; } } + public override TypeSymbol ReturnType => _returnType; + // private static T (object[] submissionArray) // { // var submission = new Submission#N(submissionArray); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs index fbaae3a50786b..34bd9f103093a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs @@ -658,14 +658,33 @@ async static Task Main(string[] args) }"; var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( - // error CS5001: Program does not contain a static 'Main' method suitable for an entry point - Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1), - // (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main(string[] args) - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task Main(string[] args) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); + } + + [Fact] + public void MainCantBeAsyncWithArgs_CSharp7_NoAwait() + { + var source = @" +using System.Threading.Tasks; + +class A +{ + static Task Main(string[] args) { - await Task.Factory.StartNew(() => { }); - }").WithArguments("async main", "7.1").WithLocation(6, 5)); + return Task.Factory.StartNew(() => { }); + } +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + compilation.VerifyDiagnostics( + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // async static Task Main(string[] args) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } [Fact] @@ -836,14 +855,33 @@ async static Task Main(string[] args) }"; var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( - // error CS5001: Program does not contain a static 'Main' method suitable for an entry point - Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1), - // (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. - // async static Task Main(string[] args) - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task Main(string[] args) + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // async static Task Main(string[] args) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); + } + + [Fact] + public void MainCantBeAsyncAndGenericOnInt_WithArgs_Csharp7_NoAsync() + { + var source = @" +using System.Threading.Tasks; + +class A +{ + static Task Main(string[] args) { - return await Task.Factory.StartNew(() => 5); - }").WithArguments("async main", "7.1").WithLocation(6, 5)); + return Task.Factory.StartNew(() => 5); + } +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + compilation.VerifyDiagnostics( + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // async static Task Main(string[] args) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } [Fact] @@ -901,12 +939,31 @@ async static Task Main() }"; var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( - // (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main() - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task Main() + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); + } + + [Fact] + public void MainCantBeAsyncAndGenericOnInt_CSharp7_NoAsync() + { + var source = @" +using System.Threading.Tasks; + +class A +{ + static Task Main() { - return await Task.Factory.StartNew(() => 5); - }").WithArguments("async main", "7.1").WithLocation(6, 5), + return Task.Factory.StartNew(() => 5); + } +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + compilation.VerifyDiagnostics( + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // async static Task Main() + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } @@ -1146,13 +1203,9 @@ async static Task Main(string[] args) // (12,30): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(12, 30), - // (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main() - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task Main() - { - System.Console.WriteLine(""Task""); - return 0; - }").WithArguments("async main", "7.1").WithLocation(6, 5), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18), // (12,30): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(12, 30), @@ -1160,6 +1213,36 @@ async static Task Main(string[] args) Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } + [Fact] + public void TaskIntAndTaskFloat_CSharp7_NoAsync() + { + var source = @" +using System.Threading.Tasks; + +class A +{ + static Task Main() + { + System.Console.WriteLine(""Task""); + return Task.FromResult(0); + } + + static Task Main(string[] args) + { + System.Console.WriteLine(""Task""); + return Task.FromResult(0.0F); + } +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics( + // (6,12): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // static Task Main() + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12), + // (12,24): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point + // static Task Main(string[] args) + Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(12, 24), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); + } [Fact] public void TaskOfFloatMainAndNonTaskMain() @@ -1185,7 +1268,7 @@ async static Task Main(string[] args) // (10,30): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(11, 30)); - CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0); + CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0); } [Fact] @@ -1211,5 +1294,169 @@ async static Task Main(string[] args) var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0); } + + [Fact] + public void ImplementGetAwaiterGetResultViaExtensionMethods() + { + var source = @" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices { + public class ExtensionAttribute {} +} + +namespace System.Runtime.CompilerServices { + public interface INotifyCompletion { + void OnCompleted(Action action); + } +} + +namespace System.Threading.Tasks { + public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion { + public bool IsCompleted => true; + public void OnCompleted(Action action) {} + public void GetResult() { + System.Console.Write(""GetResult called""); + } + } + public class Task {} +} + +public static class MyExtensions { + public static Awaiter GetAwaiter(this Task task) { + System.Console.Write(""GetAwaiter called | ""); + return new Awaiter(); + } +} + +static class Program { + static Task Main() { + return new Task(); + } +}"; + var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var verifier = sourceCompilation.VerifyEmitDiagnostics( + // (26,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // public static Awaiter GetAwaiter(this Task task) { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(26, 43), + // (33,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // static Task Main() { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(33, 12), + // (34,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // return new Task(); + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(34, 20)); + CompileAndVerify(sourceCompilation, expectedOutput: "GetAwaiter called | GetResult called"); + } + + [Fact] + public void ImplementGetAwaiterGetResultViaExtensionMethods_Obsolete() + { + var source = @" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices { + public class ExtensionAttribute {} +} + +namespace System.Runtime.CompilerServices { + public interface INotifyCompletion { + void OnCompleted(Action action); + } +} + +namespace System.Threading.Tasks { + public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion { + public bool IsCompleted => true; + public void OnCompleted(Action action) {} + public void GetResult() { + System.Console.Write(""GetResult called""); + } + } + public class Task {} +} + +public static class MyExtensions { + [System.Obsolete(""test"")] + public static Awaiter GetAwaiter(this Task task) { + System.Console.Write(""GetAwaiter called | ""); + return new Awaiter(); + } +} + +static class Program { + static Task Main() { + return new Task(); + } +}"; + var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var verifier = sourceCompilation.VerifyEmitDiagnostics( + // (34,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // static Task Main() { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(34, 12), + // (27,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // public static Awaiter GetAwaiter(this Task task) { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(27, 43), + // (35,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // return new Task(); + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(35, 20), + // (34,12): warning CS0618: 'MyExtensions.GetAwaiter(Task)' is obsolete: 'test' + // static Task Main() { + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Task").WithArguments("MyExtensions.GetAwaiter(System.Threading.Tasks.Task)", "test").WithLocation(34, 12)); + + CompileAndVerify(sourceCompilation, expectedOutput: "GetAwaiter called | GetResult called"); + } + + [Fact] + public void ImplementGetAwaiterGetResultViaExtensionMethods_ObsoleteFailing() + { + var source = @" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices { + public class ExtensionAttribute {} +} + +namespace System.Runtime.CompilerServices { + public interface INotifyCompletion { + void OnCompleted(Action action); + } +} + +namespace System.Threading.Tasks { + public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion { + public bool IsCompleted => true; + public void OnCompleted(Action action) {} + public void GetResult() {} + } + public class Task {} +} + +public static class MyExtensions { + [System.Obsolete(""test"", true)] + public static Awaiter GetAwaiter(this Task task) { + return null; + } +} + +static class Program { + static Task Main() { + return new Task(); + } +}"; + var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var verifier = sourceCompilation.VerifyEmitDiagnostics( + // (25,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // public static Awaiter GetAwaiter(this Task task) { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(25, 43), + // (31,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // static Task Main() { + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(31, 12), + // (32,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''. + // return new Task(); + Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(32, 20), + // (31,12): warning CS0618: 'MyExtensions.GetAwaiter(Task)' is obsolete: 'test' + // static Task Main() { + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Task").WithArguments("MyExtensions.GetAwaiter(System.Threading.Tasks.Task)", "test").WithLocation(31, 12)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs index b5ceade1893ea..8ca2ec00d7152 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs @@ -3434,11 +3434,9 @@ async public static Task Main() // (5,30): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // async public static Task Main() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(5, 30), - // (5,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. + // (5,25): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async public static Task Main() - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async public static Task Main() - { - }").WithArguments("async main", "7.1").WithLocation(5, 5), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(5, 25), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); }