提交 9d0b3a86 编写于 作者: A AlekseyTs

Test/fix scoping rules for pattern locals in constructor initializers.

上级 df84adde
...@@ -761,6 +761,18 @@ internal Binder WithPatternVariablesIfAny(ExpressionSyntax scopeOpt) ...@@ -761,6 +761,18 @@ internal Binder WithPatternVariablesIfAny(ExpressionSyntax scopeOpt)
return new PatternVariableBinder(scopeOpt, scopeOpt, this); return new PatternVariableBinder(scopeOpt, scopeOpt, this);
} }
internal Binder WithPatternVariablesIfAny(ArgumentListSyntax initializerArgumentListOpt)
{
Debug.Assert(Locals.Length == 0);
if (initializerArgumentListOpt == null || initializerArgumentListOpt.Arguments.Count == 0)
{
return this;
}
return new PatternVariableBinder(initializerArgumentListOpt, initializerArgumentListOpt.Arguments, this);
}
internal BoundExpression WrapWithVariablesIfAny(BoundExpression expression) internal BoundExpression WrapWithVariablesIfAny(BoundExpression expression)
{ {
return (Locals.Length == 0) return (Locals.Length == 0)
......
...@@ -2645,12 +2645,8 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression) ...@@ -2645,12 +2645,8 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
MethodSymbol constructor, MethodSymbol constructor,
DiagnosticBag diagnostics) DiagnosticBag diagnostics)
{ {
// Handle scoping for possible pattern variables declared in the initializer var result = BindConstructorInitializerCore(initializerArgumentListOpt, constructor, diagnostics);
PatternVariableBinder patBinder = (initializerArgumentListOpt != null) return WrapWithVariablesIfAny(result);
? new PatternVariableBinder(initializerArgumentListOpt, initializerArgumentListOpt.Arguments, this)
: null;
var result = (patBinder ?? this).BindConstructorInitializerCore(initializerArgumentListOpt, constructor, diagnostics);
return patBinder?.WrapWithVariablesIfAny(result) ?? result;
} }
private BoundExpression BindConstructorInitializerCore( private BoundExpression BindConstructorInitializerCore(
......
...@@ -1042,7 +1042,9 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node) ...@@ -1042,7 +1042,9 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
(ConstructorInitializerSyntax)node, (ConstructorInitializerSyntax)node,
constructorSymbol, constructorSymbol,
//insert an extra binder to perform constructor initialization checks //insert an extra binder to perform constructor initialization checks
outer.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructorSymbol)); // Handle scoping for possible pattern variables declared in the initializer
outer.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructorSymbol).
WithPatternVariablesIfAny(((ConstructorInitializerSyntax)node).ArgumentList));
} }
case SyntaxKind.Attribute: case SyntaxKind.Attribute:
......
...@@ -1726,7 +1726,9 @@ internal static BoundExpression BindConstructorInitializer(MethodSymbol construc ...@@ -1726,7 +1726,9 @@ internal static BoundExpression BindConstructorInitializer(MethodSymbol construc
} }
// wrap in ConstructorInitializerBinder for appropriate errors // wrap in ConstructorInitializerBinder for appropriate errors
Binder initializerBinder = outerBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructor); // Handle scoping for possible pattern variables declared in the initializer
Binder initializerBinder = outerBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructor).
WithPatternVariablesIfAny(initializerArgumentListOpt);
return initializerBinder.BindConstructorInitializer(initializerArgumentListOpt, constructor, diagnostics); return initializerBinder.BindConstructorInitializer(initializerArgumentListOpt, constructor, diagnostics);
} }
......
...@@ -4556,5 +4556,260 @@ class Test : System.Attribute ...@@ -4556,5 +4556,260 @@ class Test : System.Attribute
VerifyNotInScope(model, x7Ref[1]); VerifyNotInScope(model, x7Ref[1]);
VerifyNotInScope(model, x7Ref[2]); VerifyNotInScope(model, x7Ref[2]);
} }
[Fact]
public void ScopeOfPatternVariables_ConstructorInitializers_01()
{
var source =
@"
public class X
{
public static void Main()
{
}
X(byte x)
: this(3 is int x3 && x3 > 0)
{}
X(sbyte x)
: this(x4 && 4 is int x4)
{}
X(short x)
: this(51 is int x5 &&
52 is int x5 &&
x5 > 0)
{}
X(ushort x)
: this(6 is int x6 && x6 > 0, 6 is int x6 && x6 > 0)
{}
X(int x)
: this(7 is int x7 && x7 > 0)
{}
X(uint x)
: this(x7, 2)
{}
void Test73() { Dummy(x7, 3); }
X(params object[] x) {}
bool Dummy(params object[] x) {return true;}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (13,16): error CS0841: Cannot use local variable 'x4' before it is declared
// : this(x4 && 4 is int x4)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(13, 16),
// (18,26): 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, 26),
// (23,48): error CS0128: A local variable named 'x6' is already defined in this scope
// : this(6 is int x6 && x6 > 0, 6 is int x6 && x6 > 0)
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(23, 48),
// (30,16): error CS0103: The name 'x7' does not exist in the current context
// : this(x7, 2)
Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(30, 16),
// (32,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(32, 27)
);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x3Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x3").Single();
var x3Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x3").Single();
VerifyModelForDeclarationPattern(model, x3Decl, x3Ref);
var x4Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x4").Single();
var x4Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x4").Single();
VerifyModelForDeclarationPattern(model, x4Decl, x4Ref);
var x5Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x5").ToArray();
var x5Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().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<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x6").ToArray();
var x6Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x6").ToArray();
Assert.Equal(2, x6Decl.Length);
Assert.Equal(2, x6Ref.Length);
VerifyModelForDeclarationPattern(model, x6Decl[0], x6Ref);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x6Decl[1]);
var x7Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x7").Single();
var x7Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().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]);
}
[Fact]
public void ScopeOfPatternVariables_ConstructorInitializers_02()
{
var source =
@"
public class X : Y
{
public static void Main()
{
}
X(byte x)
: base(3 is int x3 && x3 > 0)
{}
X(sbyte x)
: base(x4 && 4 is int x4)
{}
X(short x)
: base(51 is int x5 &&
52 is int x5 &&
x5 > 0)
{}
X(ushort x)
: base(6 is int x6 && x6 > 0, 6 is int x6 && x6 > 0)
{}
X(int x)
: base(7 is int x7 && x7 > 0)
{}
X(uint x)
: base(x7, 2)
{}
void Test73() { Dummy(x7, 3); }
bool Dummy(params object[] x) {return true;}
}
public class Y
{
public Y(params object[] x) {}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (13,16): error CS0841: Cannot use local variable 'x4' before it is declared
// : base(x4 && 4 is int x4)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(13, 16),
// (18,26): 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, 26),
// (23,48): error CS0128: A local variable named 'x6' is already defined in this scope
// : base(6 is int x6 && x6 > 0, 6 is int x6 && x6 > 0)
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(23, 48),
// (30,16): error CS0103: The name 'x7' does not exist in the current context
// : base(x7, 2)
Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(30, 16),
// (32,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(32, 27)
);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x3Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x3").Single();
var x3Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x3").Single();
VerifyModelForDeclarationPattern(model, x3Decl, x3Ref);
var x4Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x4").Single();
var x4Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x4").Single();
VerifyModelForDeclarationPattern(model, x4Decl, x4Ref);
var x5Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x5").ToArray();
var x5Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().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<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x6").ToArray();
var x6Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x6").ToArray();
Assert.Equal(2, x6Decl.Length);
Assert.Equal(2, x6Ref.Length);
VerifyModelForDeclarationPattern(model, x6Decl[0], x6Ref);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x6Decl[1]);
var x7Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x7").Single();
var x7Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().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]);
}
[Fact]
public void ScopeOfPatternVariables_ConstructorInitializers_03()
{
var source =
@"using System;
public class X
{
public static void Main()
{
new D(1);
new D(10);
new D(1.2);
}
}
class D
{
public D(object o) : this(o is int x && x >= 5)
{
Console.WriteLine(x);
}
public D(bool b) { Console.WriteLine(b); }
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (15,27): error CS0103: The name 'x' does not exist in the current context
// Console.WriteLine(x);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(15, 27)
);
}
[Fact]
public void ScopeOfPatternVariables_ConstructorInitializers_04()
{
var source =
@"using System;
public class X
{
public static void Main()
{
new D(1);
new D(10);
new D(1.2);
}
}
class D : C
{
public D(object o) : base(o is int x && x >= 5)
{
Console.WriteLine(x);
}
}
class C
{
public C(bool b) { Console.WriteLine(b); }
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (15,27): error CS0103: The name 'x' does not exist in the current context
// Console.WriteLine(x);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(15, 27)
);
}
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册