From 449543ff3392a6c96d20057d6c15b5613985553d Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 09:48:02 -0700 Subject: [PATCH 1/8] Add tests --- .../Parsing/LambdaReturnTypeParsingTests.cs | 260 ++++++++++++++++-- 1 file changed, 240 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index f62f7f99c5a2f..2f175088f2a91 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -164,35 +164,41 @@ void verify() public void IdentifierReturnType_04() { string source = "var (x, y) => default"; - UsingExpression(source); + verify(source, TestOptions.Regular9); + verify(source); - N(SyntaxKind.ParenthesizedLambdaExpression); + void verify(string source, ParseOptions? parseOptions = null) { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "var"); - } - N(SyntaxKind.ParameterList); + UsingExpression(source); + + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierToken, "var"); } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); - { - N(SyntaxKind.DefaultKeyword); } + EOF(); } - EOF(); } [Fact] @@ -5068,6 +5074,220 @@ public void Dynamic_02() EOF(); } + [Fact] + public void Var_01() + { + string source = "var () => default"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions); + + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + EOF(); + } + } + + [Fact] + public void Var_02() + { + string source = "var x => x"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions, + // (1,1): error CS1073: Unexpected token 'x' + // var x => x + Diagnostic(ErrorCode.ERR_UnexpectedToken, "var").WithArguments("x").WithLocation(1, 1)); + + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + EOF(); + } + } + + [Fact] + public void Var_03() + { + string source = "F(var (x, y) => default)"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions); + + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + EOF(); + } + } + + [Fact] + public void Var_04() + { + string source = "F(var x => x)"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions, + // (1,7): error CS1003: Syntax error, ',' expected + // F(var x => x) + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 7)); + + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.SimpleLambdaExpression); + { + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + EOF(); + } + } + + [Fact] + public void Var_05() + { + string source = "var d = var () => default;"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingDeclaration(source, parseOptions); + + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "d"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } + [MemberData(nameof(AsyncAndStaticModifiers))] [Theory] public void Attributes_01(string modifiers, SyntaxKind[] modifierKinds) From 821071d4c1bb5e6ce229f9997e21e653ebcb1291 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 10:36:35 -0700 Subject: [PATCH 2/8] Disallow 'var' as an explicit lambda expression return type --- .../CSharp/Portable/Parser/LanguageParser.cs | 13 +- .../Parsing/LambdaReturnTypeParsingTests.cs | 136 +++++++++++------- 2 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index de8e52359f71a..32a5ef65eb23c 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -12764,15 +12764,18 @@ LambdaExpressionSyntax parseLambdaExpressionWorker() this.IsInAsync = true; } - TypeSyntax returnType; + TypeSyntax returnType = null; var resetPoint = this.GetResetPoint(); try { - returnType = ParseReturnType(); - if (CurrentToken.Kind != SyntaxKind.OpenParenToken) + if (!IsVarType()) { - this.Reset(ref resetPoint); - returnType = null; + returnType = ParseReturnType(); + if (CurrentToken.Kind != SyntaxKind.OpenParenToken) + { + this.Reset(ref resetPoint); + returnType = null; + } } } finally diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index 2f175088f2a91..5a6e647444cbb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -169,32 +169,39 @@ public void IdentifierReturnType_04() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source); + UsingExpression(source, parseOptions, + // (1,5): error CS1003: Syntax error, '=>' expected + // var (x, y) => default + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 5)); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "var"); } - N(SyntaxKind.ParameterList); + M(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); { - N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.DefaultKeyword); } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); - { - N(SyntaxKind.DefaultKeyword); } } EOF(); @@ -5083,23 +5090,30 @@ public void Var_01() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source, parseOptions); + UsingExpression(source, parseOptions, + // (1,5): error CS1003: Syntax error, '=>' expected + // var () => default + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 5)); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "var"); } - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); + M(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.DefaultKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } } } EOF(); @@ -5137,7 +5151,10 @@ public void Var_03() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source, parseOptions); + UsingExpression(source, parseOptions, + // (1,7): error CS1003: Syntax error, '=>' expected + // F(var (x, y) => default) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 7)); N(SyntaxKind.InvocationExpression); { @@ -5150,30 +5167,34 @@ void verify(string source, ParseOptions? parseOptions = null) N(SyntaxKind.OpenParenToken); N(SyntaxKind.Argument); { - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "var"); } - N(SyntaxKind.ParameterList); + M(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); { - N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.DefaultKeyword); } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); - { - N(SyntaxKind.DefaultKeyword); } } } @@ -5246,7 +5267,10 @@ public void Var_05() void verify(string source, ParseOptions? parseOptions = null) { - UsingDeclaration(source, parseOptions); + UsingDeclaration(source, parseOptions, + // (1,13): error CS1003: Syntax error, '=>' expected + // var d = var () => default; + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 13)); N(SyntaxKind.FieldDeclaration); { @@ -5262,21 +5286,25 @@ void verify(string source, ParseOptions? parseOptions = null) N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "var"); } - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); + M(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.DefaultKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } } } } From fd8588a34459f456eed84324895fbc5306685475 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 11:06:25 -0700 Subject: [PATCH 3/8] Parse as type and attach error --- .../CSharp/Portable/Parser/LanguageParser.cs | 19 +-- .../Parsing/LambdaReturnTypeParsingTests.cs | 132 ++++++++---------- 2 files changed, 69 insertions(+), 82 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 32a5ef65eb23c..b1ed3dd74f9e6 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -12764,18 +12764,15 @@ LambdaExpressionSyntax parseLambdaExpressionWorker() this.IsInAsync = true; } - TypeSyntax returnType = null; + TypeSyntax returnType; var resetPoint = this.GetResetPoint(); try { - if (!IsVarType()) + returnType = ParseReturnType(); + if (CurrentToken.Kind != SyntaxKind.OpenParenToken) { - returnType = ParseReturnType(); - if (CurrentToken.Kind != SyntaxKind.OpenParenToken) - { - this.Reset(ref resetPoint); - returnType = null; - } + this.Reset(ref resetPoint); + returnType = null; } } finally @@ -12790,6 +12787,12 @@ LambdaExpressionSyntax parseLambdaExpressionWorker() arrow = CheckFeatureAvailability(arrow, MessageID.IDS_FeatureLambda); var (block, expression) = ParseLambdaBody(); + // Disallow 'var' as explicit return type. + if ((returnType as IdentifierNameSyntax)?.Identifier.ContextualKind == SyntaxKind.VarKeyword) + { + returnType = this.AddError(returnType, ErrorCode.ERR_TypeExpected); + } + return _syntaxFactory.ParenthesizedLambdaExpression( attributes, modifiers, returnType, paramList, arrow, block, expression); } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index 5a6e647444cbb..75dcb97caea78 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -170,38 +170,34 @@ public void IdentifierReturnType_04() void verify(string source, ParseOptions? parseOptions = null) { UsingExpression(source, parseOptions, - // (1,5): error CS1003: Syntax error, '=>' expected + // (1,1): error CS1031: Type expected // var (x, y) => default - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 5)); + Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 1)); - N(SyntaxKind.SimpleLambdaExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); } - M(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.ParameterList); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.IdentifierToken, "x"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.IdentifierToken, "y"); - } - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.DefaultKeyword); + N(SyntaxKind.IdentifierToken, "y"); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); } } EOF(); @@ -5091,29 +5087,25 @@ public void Var_01() void verify(string source, ParseOptions? parseOptions = null) { UsingExpression(source, parseOptions, - // (1,5): error CS1003: Syntax error, '=>' expected + // (1,1): error CS1031: Type expected // var () => default - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 5)); + Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 1)); - N(SyntaxKind.SimpleLambdaExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); } - M(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); - { - N(SyntaxKind.DefaultKeyword); - } + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); } } EOF(); @@ -5152,9 +5144,9 @@ public void Var_03() void verify(string source, ParseOptions? parseOptions = null) { UsingExpression(source, parseOptions, - // (1,7): error CS1003: Syntax error, '=>' expected + // (1,3): error CS1031: Type expected // F(var (x, y) => default) - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 7)); + Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 3)); N(SyntaxKind.InvocationExpression); { @@ -5167,34 +5159,30 @@ void verify(string source, ParseOptions? parseOptions = null) N(SyntaxKind.OpenParenToken); N(SyntaxKind.Argument); { - N(SyntaxKind.SimpleLambdaExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); } - M(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.ParameterList); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.IdentifierToken, "x"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.IdentifierToken, "y"); - } - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.DefaultKeyword); + N(SyntaxKind.IdentifierToken, "y"); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); } } } @@ -5268,9 +5256,9 @@ public void Var_05() void verify(string source, ParseOptions? parseOptions = null) { UsingDeclaration(source, parseOptions, - // (1,13): error CS1003: Syntax error, '=>' expected + // (1,9): error CS1031: Type expected // var d = var () => default; - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=>", "(").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 9)); N(SyntaxKind.FieldDeclaration); { @@ -5286,25 +5274,21 @@ void verify(string source, ParseOptions? parseOptions = null) N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.SimpleLambdaExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "var"); } - M(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.EqualsGreaterThanToken); - N(SyntaxKind.DefaultLiteralExpression); - { - N(SyntaxKind.DefaultKeyword); - } + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); } } } From 6afa818fce5cbc111d3598fe8ecccd99ccf954c1 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 12:30:43 -0700 Subject: [PATCH 4/8] Report error in binding rather than parsing --- .../CSharp/Portable/Binder/Binder_Lambda.cs | 5 + .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../CSharp/Portable/Parser/LanguageParser.cs | 6 - .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Test/Semantic/Semantics/LambdaTests.cs | 194 ++++++++++++++++++ .../Parsing/LambdaReturnTypeParsingTests.cs | 153 ++++++++++++-- 19 files changed, 405 insertions(+), 22 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs index 7cce9af369dc7..ce84a2241399c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs @@ -248,6 +248,11 @@ static void checkAttributes(AnonymousFunctionExpressionSyntax syntax, SyntaxList MessageID.IDS_FeatureLambdaReturnType.CheckFeatureAvailability(diagnostics, syntax); syntax = syntax.SkipRef(out RefKind refKind); + if ((syntax as IdentifierNameSyntax)?.Identifier.ContextualKind() == SyntaxKind.VarKeyword) + { + diagnostics.Add(ErrorCode.ERR_LambdaExplicitReturnTypeVar, syntax.Location); + } + var returnType = BindType(syntax, diagnostics); var type = returnType.Type; diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d3cdb466a752d..f5be7381fcd96 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5845,6 +5845,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The delegate type could not be inferred. + + The contextual keyword 'var' cannot be used as an explicit lambda return type + A single-element deconstruct pattern requires some other syntax for disambiguation. It is recommended to add a discard designator '_' after the close paren ')'. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 21d55131f01bf..7ce1e0b66cc30 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1999,6 +1999,7 @@ internal enum ErrorCode WRN_CompileTimeCheckedOverflow = 8973, WRN_MethGrpToNonDel = 8974, + ERR_LambdaExplicitReturnTypeVar = 8975, #endregion diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index b1ed3dd74f9e6..de8e52359f71a 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -12787,12 +12787,6 @@ LambdaExpressionSyntax parseLambdaExpressionWorker() arrow = CheckFeatureAvailability(arrow, MessageID.IDS_FeatureLambda); var (block, expression) = ParseLambdaBody(); - // Disallow 'var' as explicit return type. - if ((returnType as IdentifierNameSyntax)?.Identifier.ContextualKind == SyntaxKind.VarKeyword) - { - returnType = this.AddError(returnType, ErrorCode.ERR_TypeExpected); - } - return _syntaxFactory.ParenthesizedLambdaExpression( attributes, modifiers, returnType, paramList, arrow, block, expression); } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 17c68a35f6f32..45712796d1018 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -747,6 +747,11 @@ Metoda {0} s blokem iterátoru musí být asynchronní, aby vrátila {1}. + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 42d4b2f97afb8..0a0f6e2178cd0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -747,6 +747,11 @@ Die Methode "{0}" mit einem Iteratorblock muss "async" lauten, um "{1}" zurückzugeben. + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 1cf5621c54202..87ba8bd9c117d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -747,6 +747,11 @@ El método "{0}" con un bloqueo de iterador debe ser "asincrónico" para devolver "{1}" + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index d1dc40719e857..9e0e65b14a357 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -747,6 +747,11 @@ La méthode '{0}' avec un bloc itérateur doit être 'async' pour retourner '{1}' + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 6565507384ca0..0158b5b701cfb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -747,6 +747,11 @@ Il metodo '{0}' con un blocco iteratore deve essere 'async' per restituire '{1}' + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 9ffd07633141f..41ce557c62422 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -747,6 +747,11 @@ 反復子ブロックを伴うメソッド '{0}' が '{1}' を返すには 'async' でなければなりません + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 534bdaf18458f..c33e5051b68b0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -747,6 +747,11 @@ '{1}'을(를) 반환하려면 반복기 블록이 있는 '{0}' 메서드가 '비동기'여야 합니다. + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 04fb087bb5cc7..3085765950f3c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -747,6 +747,11 @@ Metoda „{0}” z blokiem iteratora musi być oznaczona jako „async”, aby zwrócić „{1}” + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index ab7ed9b9af338..213fc677443c3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -747,6 +747,11 @@ O método '{0}' com um bloco do iterador deve ser 'async' para retornar '{1}' + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 153fe6c74979a..3312e78f4ddea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -747,6 +747,11 @@ Чтобы возвращать "{1}", метод "{0}" с блоком итератора должен быть асинхронным ("async"). + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 414c32b574241..9fa4d63428f3d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -747,6 +747,11 @@ Yineleyici bloku olan '{0}' yönteminin '{1}' döndürmek için 'zaman uyumsuz' olması gerekir + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 58a8a5d2036de..93e0f290bd75e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -747,6 +747,11 @@ 具有迭代器块的方法“{0}”必须是“异步的”,这样才能返回“{1}” + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index ad23c36bbf882..577af08185874 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -747,6 +747,11 @@ 具有迭代區塊的方法 '{0}' 必須為「非同步」才能傳回 '{1}' + + The contextual keyword 'var' cannot be used as an explicit lambda return type + The contextual keyword 'var' cannot be used as an explicit lambda return type + + A lambda expression with attributes cannot be converted to an expression tree A lambda expression with attributes cannot be converted to an expression tree diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 082edeb3a0820..009811fe0acf9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -5369,6 +5369,200 @@ static void Main() Diagnostic(ErrorCode.ERR_BogusType, "A").WithArguments("A").WithLocation(7, 11)); } + [Fact] + public void VarReturnType_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Delegate d; + d = var () => throw null; + d = ref var () => throw null; + } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,13): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // d = var () => throw null; + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(7, 13), + // (7,13): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code + // d = var () => throw null; + Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(7, 13), + // (8,17): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // d = ref var () => throw null; + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(8, 17), + // (8,17): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code + // d = ref var () => throw null; + Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(8, 17)); + } + + [Fact] + public void VarReturnType_02() + { + var source = +@"using System; +class var { } +class Program +{ + static void Main() + { + Delegate d; + d = var () => default; + d = ref var (ref var v) => ref v; + d = @var () => default; + d = ref @var (ref var v) => ref v; + } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,13): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // d = var () => default; + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(8, 13), + // (9,17): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // d = ref var (ref var v) => ref v; + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(9, 17)); + } + + [Fact] + public void VarReturnType_03() + { + var source = +@"using System; +class var { } +class Program +{ + static void Main() + { + F(var () => default); + F(ref var (ref var v) => ref v); + F(@var () => default); + F(ref @var (ref var v) => ref v); + F(() => default(var)); + } + static void F(Delegate d) { } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(var () => default); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(7, 11), + // (8,15): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(ref var (ref var v) => ref v); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(8, 15)); + } + + [Fact] + public void VarReturnType_04() + { + var source = +@"using System; +struct var +{ + internal class other { } + internal other o; +} +class Program +{ + static void Main() + { + F(var () => default); + F(ref var () => throw null); + F(var? () => default); + F(var[] () => default); + F(var? (var v) => v); + F(var.other (var v) => v.o); + } + static void F(Delegate d) { } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (11,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(var () => default); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(11, 11), + // (12,15): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(ref var () => throw null); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(12, 15)); + } + + [Fact] + public void VarReturnType_05() + { + var source = +@"using System; +using var = System.Int32; +class Program +{ + static void Main() + { + F(var () => default); + F(@var () => default); + F(() => default(var)); + } + static void F(Delegate d) { } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(var () => default); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(7, 11)); + } + + [Fact] + public void VarReturnType_06() + { + var source = +@"using System; +class Program +{ + static void M() + { + F(var () => default); + F(@var () => default); + F(() => default(var)); + } + static void F(Delegate d) { } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(var () => default); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(6, 11)); + } + + [Fact] + public void VarReturnType_07() + { + var source = +@"using System; +static class var { } +class Program +{ + static void Main() + { + F(var () => default); + } + static void F(Delegate d) { } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type + // F(var () => default); + Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(7, 11), + // (7,11): error CS0722: 'var': static types cannot be used as return types + // F(var () => default); + Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "var").WithArguments("var").WithLocation(7, 11)); + } + [Fact] public void AsyncLambdaParameters_01() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index 75dcb97caea78..4350d251a9d81 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -169,10 +169,7 @@ public void IdentifierReturnType_04() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source, parseOptions, - // (1,1): error CS1031: Type expected - // var (x, y) => default - Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 1)); + UsingExpression(source, parseOptions); N(SyntaxKind.ParenthesizedLambdaExpression); { @@ -5086,10 +5083,7 @@ public void Var_01() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source, parseOptions, - // (1,1): error CS1031: Type expected - // var () => default - Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 1)); + UsingExpression(source, parseOptions); N(SyntaxKind.ParenthesizedLambdaExpression); { @@ -5143,10 +5137,7 @@ public void Var_03() void verify(string source, ParseOptions? parseOptions = null) { - UsingExpression(source, parseOptions, - // (1,3): error CS1031: Type expected - // F(var (x, y) => default) - Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 3)); + UsingExpression(source, parseOptions); N(SyntaxKind.InvocationExpression); { @@ -5255,10 +5246,7 @@ public void Var_05() void verify(string source, ParseOptions? parseOptions = null) { - UsingDeclaration(source, parseOptions, - // (1,9): error CS1031: Type expected - // var d = var () => default; - Diagnostic(ErrorCode.ERR_TypeExpected, "var").WithLocation(1, 9)); + UsingDeclaration(source, parseOptions); N(SyntaxKind.FieldDeclaration); { @@ -5300,6 +5288,139 @@ void verify(string source, ParseOptions? parseOptions = null) } } + [Fact] + public void Var_06() + { + string source = "ref var (ref var x) => x"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions); + + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + EOF(); + } + } + + [Fact] + public void Var_07() + { + string source = "var[] (v) => v"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions); + + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "v"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "v"); + } + } + EOF(); + } + } + + [Fact] + public void Var_08() + { + string source = "var.x () => default"; + verify(source, TestOptions.Regular9); + verify(source); + + void verify(string source, ParseOptions? parseOptions = null) + { + UsingExpression(source, parseOptions); + + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + EOF(); + } + } + [MemberData(nameof(AsyncAndStaticModifiers))] [Theory] public void Attributes_01(string modifiers, SyntaxKind[] modifierKinds) From a2a26a308c1101de7a8cfd6114f2a6878b0f756b Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 15:27:34 -0700 Subject: [PATCH 5/8] Update tests --- .../CSharp/Test/Semantic/Semantics/LambdaTests.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 009811fe0acf9..1a8cb956589fc 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -5473,7 +5473,6 @@ static void Main() { F(var () => default); F(ref var () => throw null); - F(var? () => default); F(var[] () => default); F(var? (var v) => v); F(var.other (var v) => v.o); @@ -5501,8 +5500,8 @@ class Program { static void Main() { - F(var () => default); - F(@var () => default); + F(var (var v) => v); + F(@var (var v) => v); F(() => default(var)); } static void F(Delegate d) { } @@ -5524,8 +5523,8 @@ class Program { static void M() { - F(var () => default); - F(@var () => default); + F(var (var v) => v); + F(@var (var v) => v); F(() => default(var)); } static void F(Delegate d) { } From 633fa57818e7e43832a32f6d36628aeb4d9db1f7 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 16:04:26 -0700 Subject: [PATCH 6/8] Fix build --- src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index 17f180d628916..67ca85e9cd066 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -97,7 +97,7 @@ internal void UsingStatement(string text, ParseOptions? options, params Diagnost UsingNode(node); } - internal void UsingDeclaration(string text, ParseOptions options, params DiagnosticDescription[] expectedErrors) + internal void UsingDeclaration(string text, ParseOptions? options, params DiagnosticDescription[] expectedErrors) { UsingDeclaration(text, offset: 0, options, consumeFullText: true, expectedErrors: expectedErrors); } From 7f74134e9ff49b4ff5562a309de1daf4fc4fa741 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 17:10:11 -0700 Subject: [PATCH 7/8] PR feedback --- .../CSharp/Compiler Breaking Changes - DotNet 6.md | 12 ++++++++++++ .../CSharp/Test/Semantic/Semantics/LambdaTests.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md index a530a0ab2d7dc..b5d573d828985 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md @@ -108,3 +108,15 @@ These are _function_type_conversions_. } } ``` + +4. In Visual Studio 17.1, the contextual keyword `var` cannot be used as an explicit lambda return type. + + ```csharp + using System; + + F(var () => default); // error: 'var' cannot be used as an explicit lambda return type + + static void F(Func f) { } + + class var { } + ``` diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 1a8cb956589fc..626a78d54e862 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -5510,7 +5510,7 @@ static void F(Delegate d) { } var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,11): error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type - // F(var () => default); + // F(var (var v) => v); Diagnostic(ErrorCode.ERR_LambdaExplicitReturnTypeVar, "var").WithLocation(7, 11)); } From e178332d152cfff31b3e42b462d0a7beed77e444 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Fri, 1 Oct 2021 17:33:52 -0700 Subject: [PATCH 8/8] Add success case --- docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md index b5d573d828985..950a3b03535f3 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md @@ -114,7 +114,8 @@ These are _function_type_conversions_. ```csharp using System; - F(var () => default); // error: 'var' cannot be used as an explicit lambda return type + F(var () => default); // error: 'var' cannot be used as an explicit lambda return type + F(@var () => default); // ok static void F(Func f) { }