Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable main methods to be asynchronous #18157

Merged
merged 13 commits into from
Mar 31, 2017
9 changes: 9 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -5041,4 +5041,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_VoidAssignment" xml:space="preserve">
<value>A value of type 'void' may not be assigned.</value>
</data>
<data name="IDS_FeatureAsyncMain" xml:space="preserve">
<value>async main</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Symbols;
using static Microsoft.CodeAnalysis.CSharp.Binder;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

Expand Down Expand Up @@ -1470,9 +1471,9 @@ private MethodSymbol FindEntryPoint(CancellationToken cancellationToken, out Imm
continue;
}

if (candidate.IsAsync && LanguageVersion < LanguageVersion.CSharp7_1)
if (candidate.IsAsync)
{
diagnostics.Add(ErrorCode.ERR_MainCantBeAsync, candidate.Locations.First(), candidate);
CheckFeatureAvailability(candidate.DeclaringSyntaxReferences.Single().GetSyntax(), MessageID.IDS_FeatureAsyncMain, diagnostics);
}

viableEntryPoints.Add(candidate);
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ internal enum ErrorCode
ERR_VarargsAsync = 4006,
ERR_ByRefTypeAndAwait = 4007,
ERR_BadAwaitArgVoidCall = 4008,
ERR_MainCantBeAsync = 4009,
// ERR_MainCantBeAsync = 4009,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we delete the corresponding resource string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

ERR_CantConvAsyncAnonFuncReturns = 4010,
ERR_BadAwaiterPattern = 4011,
ERR_BadSpecialByRefLocal = 4012,
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ internal enum MessageID
IDS_FeatureExpressionBodiedAccessor = MessageBase + 12715,
IDS_FeatureExpressionBodiedDeOrConstructor = MessageBase + 12716,
IDS_ThrowExpression = MessageBase + 12717,
IDS_FeatureAsyncMain = MessageBase + 12718,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -183,6 +184,10 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
// Checks are in the LanguageParser unless otherwise noted.
switch (feature)
{
// C# 7.1 features.
case MessageID.IDS_FeatureAsyncMain:
return LanguageVersion.CSharp7_1;

// C# 7 features.
case MessageID.IDS_FeatureBinaryLiteral:
case MessageID.IDS_FeatureDigitSeparator:
Expand Down
56 changes: 39 additions & 17 deletions src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,13 @@ async static Task Main(string[] args)
}
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
compilation.VerifyDiagnostics(Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23));
compilation.VerifyDiagnostics(
// (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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible for the diagnostic to point to a narrow piece of syntax? For example "Main" or maybe "async"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment and will get back to this shortly

{
await Task.Factory.StartNew(() => { });
}").WithArguments("async main", "7.1").WithLocation(6, 5));
}

[Fact]
Expand Down Expand Up @@ -1325,10 +1331,12 @@ async static void Main()
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
compilation.VerifyDiagnostics(
// (6,23): error CS4009: 'A.Main()': an entry point cannot be marked with the 'async' modifier
// (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
// async static void Main()
Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 23)
);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static void Main()
{
await Task.Factory.StartNew(() => { });
}").WithArguments("async main", "7.1").WithLocation(6, 5));
}

[Fact]
Expand Down Expand Up @@ -1375,10 +1383,14 @@ async static int Main()
compilation.VerifyDiagnostics(
// (6,22): error CS1983: The return type of an async method must be void, Task or Task<T>
// async static int Main()
Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(6, 22),
// (6,22): error CS4009: 'A.Main()': an entry point cannot be marked with the 'async' modifier
Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main"),
// (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
// async static int Main()
Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 22));
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static int Main()
{
return await Task.Factory.StartNew(() => 5);
}").WithArguments("async main", "7.1").WithLocation(6, 5)
);
}

[Fact]
Expand Down Expand Up @@ -1420,9 +1432,13 @@ async static Task<int> Main(string[] args)
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
compilation.VerifyDiagnostics(
// (6,28): error CS4009: 'A.Main(string[])': an entry point cannot be marked with the 'async' modifier
// async static Task<int> Main(string[] args)
Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 28));
// (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
// async static Task<int> Main(string[] args)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task<int> Main(string[] args)
{
return await Task.Factory.StartNew(() => 5);
}").WithArguments("async main", "7.1").WithLocation(6, 5)
);
}

[Fact]
Expand Down Expand Up @@ -1464,9 +1480,13 @@ async static Task<int> Main()
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
compilation.VerifyDiagnostics(
// (6,28): error CS4009: 'A.Main()': an entry point cannot be marked with the 'async' modifier
// (6,5): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
// async static Task<int> Main()
Diagnostic(ErrorCode.ERR_MainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 28));
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async static Task<int> Main()
{
return await Task.Factory.StartNew(() => 5);
}").WithArguments("async main", "7.1").WithLocation(6, 5)
);
}

[Fact]
Expand Down Expand Up @@ -3747,8 +3767,8 @@ async public static Task Main()
}
}";
CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics(
// (4,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 void 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"));
}

Expand All @@ -3766,10 +3786,12 @@ async public static Task Main()
CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics(
// (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,30): error CS4009: 'Test.Main()': an entry point cannot be marked with the 'async' modifier
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main"),
// (5,5): 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_MainCantBeAsync, "Main").WithArguments("Test.Main()").WithLocation(5, 30));
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, @"async public static Task Main()
{
}").WithArguments("async main", "7.1").WithLocation(5, 5));
}

[Fact, WorkItem(547088, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547088")]
Expand Down