diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 2f67fe262779b85887f326dc65f9fe82959629db..9e1430cd6b8137750dba7ef56fa8862da9fb5915 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -457,7 +457,7 @@ private BoundStatement BindLocalFunctionStatement(LocalFunctionStatementSyntax n } else if (node.ExpressionBody != null) { - block = binder.BindExpressionBodyAsBlock(node.ExpressionBody, diagnostics); + block = binder.GetBinder(node.ExpressionBody).BindExpressionBodyAsBlock(node.ExpressionBody, diagnostics); } else { @@ -3575,9 +3575,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr DiagnosticBag diagnostics) { RefKind refKind = expressionBody.RefKeyword.Kind().GetRefKind(); - PatternVariableBinder patternBinder = new PatternVariableBinder(expressionBody, expressionBody.Expression, this); - BoundExpression expression = patternBinder.BindValue(expressionBody.Expression, diagnostics, refKind != RefKind.None ? BindValueKind.RefReturn : BindValueKind.RValue); - expression = patternBinder.WrapWithPatternVariables(expression); + BoundExpression expression = BindValue(expressionBody.Expression, diagnostics, refKind != RefKind.None ? BindValueKind.RefReturn : BindValueKind.RValue); return CreateBlockFromExpression(expressionBody, this.Locals, refKind, expression, expressionBody.Expression, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index f06fd7678c324bee6fe3249555cb233106b98c5d..4e9d4fa621808fbe579093d605d3b14a03bb90e6 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -187,9 +187,8 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no public override void VisitArrowExpressionClause(ArrowExpressionClauseSyntax node) { - // TODO: Pattern variables in the => expression are local - //var arrowBinder = new PatternVariableBinder(node, node.Expression, _enclosing); - //AddToMap(node, arrowBinder); + var arrowBinder = new PatternVariableBinder(node, node.Expression, _enclosing); + AddToMap(node, arrowBinder); } public override void VisitAnonymousMethodExpression(AnonymousMethodExpressionSyntax node) diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 7dcba4182cb9a4bd99b85d7da1b7dad6950df4d5..1120d46e783c2c1180b08c3e099dc6a6404b48c4 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -43,6 +43,12 @@ protected MemberSemanticModel(CSharpCompilation compilation, CSharpSyntaxNode ro _compilation = compilation; _root = root; _memberSymbol = memberSymbol; + + if (root.Kind() == SyntaxKind.ArrowExpressionClause) + { + rootBinder = rootBinder.WithPatternVariablesIfAny(((ArrowExpressionClauseSyntax)root).Expression); + } + this.RootBinder = rootBinder.WithAdditionalFlags(GetSemanticModelBinderFlags()); _parentSemanticModelOpt = parentSemanticModelOpt; _speculatedPosition = speculatedPosition; @@ -215,11 +221,16 @@ private Binder GetEnclosingBinder(CSharpSyntaxNode node, int position) binder = RootBinder.GetBinder(current); } } + else if (current.Kind() == SyntaxKind.ArrowExpressionClause && current.Parent?.Kind() == SyntaxKind.LocalFunctionStatement) + { + binder = RootBinder.GetBinder(current); + } else { // If this ever breaks, make sure that all callers of // CanHaveAssociatedLocalBinder are in sync. - Debug.Assert(!current.CanHaveAssociatedLocalBinder()); + Debug.Assert(!current.CanHaveAssociatedLocalBinder() || + (current == _root && current.Kind() == SyntaxKind.ArrowExpressionClause)); } if (current == _root) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 686352d374d970f022dbbea7bb6951580b5bb61b..9a93afb0bd7acec694868c73c4982a268956537d 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -1549,7 +1549,7 @@ private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSta binder = new ExecutableCodeBinder(arrowExpression, sourceMethod, binder); importChain = binder.ImportChain; // Add locals - return binder.BindExpressionBodyAsBlock(arrowExpression, diagnostics); + return binder.WithPatternVariablesIfAny(arrowExpression.Expression).BindExpressionBodyAsBlock(arrowExpression, diagnostics); } else { diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index 275a29b0380e58b038cf7767a35b28f2857aec66..9decb4dcb834e4f0653688aea275b1bc947f92a5 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -60,11 +60,13 @@ public static bool IsQuery(this CSharpSyntaxNode syntax) /// internal static bool CanHaveAssociatedLocalBinder(this CSharpSyntaxNode syntax) { + SyntaxKind kind; return syntax.IsAnonymousFunction() || syntax is StatementSyntax || - syntax.Kind() == SyntaxKind.CatchClause || - syntax.Kind() == SyntaxKind.CatchFilterClause || - syntax.Kind() == SyntaxKind.SwitchSection; + (kind = syntax.Kind()) == SyntaxKind.CatchClause || + kind == SyntaxKind.CatchFilterClause || + kind == SyntaxKind.SwitchSection || + kind == SyntaxKind.ArrowExpressionClause; } /// diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs index 2b87b239707595a6df96cfc5af01322c89005f11..83d9498a52518dbd77fcd0364ba7ad8234616db6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs @@ -3438,5 +3438,433 @@ void Test11() VerifyModelForDeclarationPattern(model, y11Decl, y11Ref[0]); VerifyNotAPatternLocal(model, y11Ref[1]); } + + [Fact] + public void ScopeOfPatternVariables_ExpressionBodiedLocalFunctions_01() + { + var source = +@" +public class X +{ + public static void Main() + { + } + + bool Dummy(params object[] x) {return true;} + + void Test1() + { + void f(object o) => let x1 = o; + f(null); + } + + void Test2() + { + void f(object o) => let var x2 = o; + f(null); + } + + void Test3() + { + bool f (object o) => o is int x3 && x3 > 0; + f(null); + } + + void Test4() + { + bool f (object o) => x4 && o is int x4; + f(null); + } + + void Test5() + { + bool f (object o1, object o2) => o1 is int x5 && + o2 is int x5 && + x5 > 0; + f(null, null); + } + + void Test6() + { + bool f1 (object o) => o is int x6 && x6 > 0; bool f2 (object o) => o is int x6 && x6 > 0; + f1(null); + f2(null); + } + + void Test7() + { + Dummy(x7, 1); + + bool f (object o) => o is int x7 && x7 > 0; + + Dummy(x7, 2); + f(null); + } + + void Test11() + { + var x11 = 11; + Dummy(x11); + bool f (object o) => o is int x11 && + x11 > 0; + f(null); + } + + void Test12() + { + bool f (object o) => o is int x12 && + x12 > 0; + var x12 = 11; + Dummy(x12); + f(null); + } +} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions.WithLocalFunctionsFeature()); + compilation.VerifyDiagnostics( + // (12,33): error CS1002: ; expected + // void f(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "x1").WithLocation(12, 33), + // (18,33): error CS1002: ; expected + // void f(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "var").WithLocation(18, 33), + // (12,29): error CS0103: The name 'let' does not exist in the current context + // void f(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(12, 29), + // (12,29): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // void f(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_IllegalStatement, "let").WithLocation(12, 29), + // (12,33): error CS0103: The name 'x1' does not exist in the current context + // void f(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(12, 33), + // (12,38): error CS0103: The name 'o' does not exist in the current context + // void f(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(12, 38), + // (18,29): error CS0103: The name 'let' does not exist in the current context + // void f(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(18, 29), + // (18,29): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // void f(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_IllegalStatement, "let").WithLocation(18, 29), + // (18,42): error CS0103: The name 'o' does not exist in the current context + // void f(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(18, 42), + // (30,30): error CS0841: Cannot use local variable 'x4' before it is declared + // bool f (object o) => x4 && o is int x4; + Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(30, 30), + // (37,52): error CS0128: A local variable named 'x5' is already defined in this scope + // o2 is int x5 && + Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(37, 52), + // (38,42): error CS0165: Use of unassigned local variable 'x5' + // x5 > 0; + Diagnostic(ErrorCode.ERR_UseDefViolation, "x5").WithArguments("x5").WithLocation(38, 42), + // (51,15): error CS0103: The name 'x7' does not exist in the current context + // Dummy(x7, 1); + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(51, 15), + // (55,15): error CS0103: The name 'x7' does not exist in the current context + // Dummy(x7, 2); + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(55, 15), + // (63,39): error CS0136: A local or parameter named 'x11' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // bool f (object o) => o is int x11 && + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x11").WithArguments("x11").WithLocation(63, 39), + // (70,39): error CS0136: A local or parameter named 'x12' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // bool f (object o) => o is int x12 && + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x12").WithArguments("x12").WithLocation(70, 39) + ); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree); + + var x3Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x3").Single(); + var x3Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x3").Single(); + VerifyModelForDeclarationPattern(model, x3Decl, x3Ref); + + var x4Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x4").Single(); + var x4Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x4").Single(); + VerifyModelForDeclarationPattern(model, x4Decl, x4Ref); + + var x5Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x5").ToArray(); + var x5Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x5").Single(); + Assert.Equal(2, x5Decl.Length); + VerifyModelForDeclarationPattern(model, x5Decl[0], x5Ref); + VerifyModelForDeclarationPatternDuplicateInSameScope(model, x5Decl[1]); + + var x6Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x6").ToArray(); + var x6Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x6").ToArray(); + Assert.Equal(2, x6Decl.Length); + Assert.Equal(2, x6Ref.Length); + VerifyModelForDeclarationPattern(model, x6Decl[0], x6Ref[0]); + VerifyModelForDeclarationPattern(model, x6Decl[1], x6Ref[1]); + + var x7Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x7").Single(); + var x7Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x7").ToArray(); + Assert.Equal(3, x7Ref.Length); + VerifyNotInScope(model, x7Ref[0]); + VerifyModelForDeclarationPattern(model, x7Decl, x7Ref[1]); + VerifyNotInScope(model, x7Ref[2]); + + var x11Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x11").Single(); + var x11Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x11").ToArray(); + Assert.Equal(2, x11Ref.Length); + VerifyNotAPatternLocal(model, x11Ref[0]); + VerifyModelForDeclarationPattern(model, x11Decl, x11Ref[1]); + + var x12Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x12").Single(); + var x12Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x12").ToArray(); + Assert.Equal(2, x12Ref.Length); + VerifyModelForDeclarationPattern(model, x12Decl, x12Ref[0]); + VerifyNotAPatternLocal(model, x12Ref[1]); + } + + [Fact] + public void ScopeOfPatternVariables_ExpressionBodiedFunctions_01() + { + var source = +@" +public class X +{ + public static void Main() + { + } + + + void Test1(object o) => let x1 = o; + + void Test2(object o) => let var x2 = o; + + bool Test3(object o) => o is int x3 && x3 > 0; + + bool Test4(object o) => x4 && o is int x4; + + bool Test5(object o1, object o2) => o1 is int x5 && + o2 is int x5 && + x5 > 0; + + bool Test61 (object o) => o is int x6 && x6 > 0; bool Test62 (object o) => o is int x6 && x6 > 0; + + bool Test71(object o) => o is int x7 && x7 > 0; + void Test72() => Dummy(x7, 2); + void Test73() { Dummy(x7, 3); } + + bool Test11(object x11) => 1 is int x11 && + x11 > 0; + + bool Dummy(params object[] x) {return true;} +} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions.WithLocalFunctionsFeature()); + compilation.VerifyDiagnostics( + // (9,33): error CS1002: ; expected + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "x1").WithLocation(9, 33), + // (9,36): error CS1519: Invalid token '=' in class, struct, or interface member declaration + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(9, 36), + // (9,36): error CS1519: Invalid token '=' in class, struct, or interface member declaration + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(9, 36), + // (9,39): error CS1519: Invalid token ';' in class, struct, or interface member declaration + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(9, 39), + // (9,39): error CS1519: Invalid token ';' in class, struct, or interface member declaration + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(9, 39), + // (11,33): error CS1002: ; expected + // void Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "var").WithLocation(11, 33), + // (11,33): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code + // void Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(11, 33), + // (11,42): error CS0103: The name 'o' does not exist in the current context + // void Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(11, 42), + // (9,29): error CS0103: The name 'let' does not exist in the current context + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(9, 29), + // (9,29): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // void Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_IllegalStatement, "let").WithLocation(9, 29), + // (11,29): error CS0103: The name 'let' does not exist in the current context + // void Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(11, 29), + // (11,29): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement + // void Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_IllegalStatement, "let").WithLocation(11, 29), + // (15,29): error CS0841: Cannot use local variable 'x4' before it is declared + // bool Test4(object o) => x4 && o is int x4; + Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(15, 29), + // (18,52): error CS0128: A local variable named 'x5' is already defined in this scope + // o2 is int x5 && + Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(18, 52), + // (19,42): error CS0165: Use of unassigned local variable 'x5' + // x5 > 0; + Diagnostic(ErrorCode.ERR_UseDefViolation, "x5").WithArguments("x5").WithLocation(19, 42), + // (24,28): error CS0103: The name 'x7' does not exist in the current context + // void Test72() => Dummy(x7, 2); + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(24, 28), + // (25,27): error CS0103: The name 'x7' does not exist in the current context + // void Test73() { Dummy(x7, 3); } + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(25, 27), + // (27,41): error CS0136: A local or parameter named 'x11' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // bool Test11(object x11) => 1 is int x11 && + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x11").WithArguments("x11").WithLocation(27, 41) + ); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree); + + var x3Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x3").Single(); + var x3Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x3").Single(); + VerifyModelForDeclarationPattern(model, x3Decl, x3Ref); + + var x4Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x4").Single(); + var x4Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x4").Single(); + VerifyModelForDeclarationPattern(model, x4Decl, x4Ref); + + var x5Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x5").ToArray(); + var x5Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x5").Single(); + Assert.Equal(2, x5Decl.Length); + VerifyModelForDeclarationPattern(model, x5Decl[0], x5Ref); + VerifyModelForDeclarationPatternDuplicateInSameScope(model, x5Decl[1]); + + var x6Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x6").ToArray(); + var x6Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x6").ToArray(); + Assert.Equal(2, x6Decl.Length); + Assert.Equal(2, x6Ref.Length); + VerifyModelForDeclarationPattern(model, x6Decl[0], x6Ref[0]); + VerifyModelForDeclarationPattern(model, x6Decl[1], x6Ref[1]); + + var x7Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x7").Single(); + var x7Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x7").ToArray(); + Assert.Equal(3, x7Ref.Length); + VerifyModelForDeclarationPattern(model, x7Decl, x7Ref[0]); + VerifyNotInScope(model, x7Ref[1]); + VerifyNotInScope(model, x7Ref[2]); + + var x11Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x11").Single(); + var x11Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x11").Single(); + VerifyModelForDeclarationPattern(model, x11Decl, x11Ref); + } + + [Fact] + public void ScopeOfPatternVariables_ExpressionBodiedProperties_01() + { + var source = +@" +public class X +{ + public static void Main() + { + } + + + bool Test1(object o) => let x1 = o; + + bool Test2(object o) => let var x2 = o; + + bool Test3 => 3 is int x3 && x3 > 0; + + bool Test4 => x4 && 4 is int x4; + + bool Test5 => 51 is int x5 && + 52 is int x5 && + x5 > 0; + + bool Test61 => 6 is int x6 && x6 > 0; bool Test62 => 6 is int x6 && x6 > 0; + + bool Test71 => 7 is int x7 && x7 > 0; + bool Test72 => Dummy(x7, 2); + void Test73() { Dummy(x7, 3); } + + bool this[object x11] => 1 is int x11 && + x11 > 0; + + bool Dummy(params object[] x) {return true;} +} +"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions.WithLocalFunctionsFeature()); + compilation.VerifyDiagnostics( + // (9,33): error CS1002: ; expected + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "x1").WithLocation(9, 33), + // (9,36): error CS1519: Invalid token '=' in class, struct, or interface member declaration + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(9, 36), + // (9,36): error CS1519: Invalid token '=' in class, struct, or interface member declaration + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(9, 36), + // (9,39): error CS1519: Invalid token ';' in class, struct, or interface member declaration + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(9, 39), + // (9,39): error CS1519: Invalid token ';' in class, struct, or interface member declaration + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(9, 39), + // (11,33): error CS1002: ; expected + // bool Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "var").WithLocation(11, 33), + // (11,33): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code + // bool Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(11, 33), + // (11,42): error CS0103: The name 'o' does not exist in the current context + // bool Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(11, 42), + // (9,29): error CS0103: The name 'let' does not exist in the current context + // bool Test1(object o) => let x1 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(9, 29), + // (11,29): error CS0103: The name 'let' does not exist in the current context + // bool Test2(object o) => let var x2 = o; + Diagnostic(ErrorCode.ERR_NameNotInContext, "let").WithArguments("let").WithLocation(11, 29), + // (15,19): error CS0841: Cannot use local variable 'x4' before it is declared + // bool Test4 => x4 && 4 is int x4; + Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(15, 19), + // (18,29): error CS0128: A local variable named 'x5' is already defined in this scope + // 52 is int x5 && + Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(18, 29), + // (24,26): error CS0103: The name 'x7' does not exist in the current context + // bool Test72 => Dummy(x7, 2); + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(24, 26), + // (25,27): error CS0103: The name 'x7' does not exist in the current context + // void Test73() { Dummy(x7, 3); } + Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(25, 27), + // (27,39): error CS0136: A local or parameter named 'x11' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // bool this[object x11] => 1 is int x11 && + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x11").WithArguments("x11").WithLocation(27, 39) + ); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree); + + var x3Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x3").Single(); + var x3Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x3").Single(); + VerifyModelForDeclarationPattern(model, x3Decl, x3Ref); + + var x4Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x4").Single(); + var x4Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x4").Single(); + VerifyModelForDeclarationPattern(model, x4Decl, x4Ref); + + var x5Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x5").ToArray(); + var x5Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x5").Single(); + Assert.Equal(2, x5Decl.Length); + VerifyModelForDeclarationPattern(model, x5Decl[0], x5Ref); + VerifyModelForDeclarationPatternDuplicateInSameScope(model, x5Decl[1]); + + var x6Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x6").ToArray(); + var x6Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x6").ToArray(); + Assert.Equal(2, x6Decl.Length); + Assert.Equal(2, x6Ref.Length); + VerifyModelForDeclarationPattern(model, x6Decl[0], x6Ref[0]); + VerifyModelForDeclarationPattern(model, x6Decl[1], x6Ref[1]); + + var x7Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x7").Single(); + var x7Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x7").ToArray(); + Assert.Equal(3, x7Ref.Length); + VerifyModelForDeclarationPattern(model, x7Decl, x7Ref[0]); + VerifyNotInScope(model, x7Ref[1]); + VerifyNotInScope(model, x7Ref[2]); + + var x11Decl = tree.GetRoot().DescendantNodes().OfType().Where(p => p.Identifier.ValueText == "x11").Single(); + var x11Ref = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "x11").Single(); + VerifyModelForDeclarationPattern(model, x11Decl, x11Ref); + } } }