提交 0183aa22 编写于 作者: N Neal Gafter

Improve definite-assignment behavior in error cases for switch and is-pattern

Also reduce cascaded diagnostics in attribute argument binding.
Fixes #9154
上级 fcf0011c
......@@ -1187,7 +1187,7 @@ private TypedConstant VisitArrayCreation(BoundArrayCreation node, DiagnosticBag
if (typedConstantKind == TypedConstantKind.Error)
{
if (!curArgumentHasErrors)
if (!curArgumentHasErrors && !attrHasErrors)
{
Binder.Error(diagnostics, ErrorCode.ERR_BadAttributeArgument, node.Syntax);
attrHasErrors = true;
......
......@@ -727,16 +727,6 @@ private BoundExpression BindConditionalLogicalOperator(BinaryExpressionSyntax no
Debug.Assert(kind == BinaryOperatorKind.LogicalAnd || kind == BinaryOperatorKind.LogicalOr);
// If either operand is bad, don't try to do binary operator overload resolution; that will just
// make cascading errors.
if (left.HasAnyErrors || right.HasAnyErrors)
{
// NOTE: no candidate user-defined operators.
return new BoundBinaryOperator(node, kind, left, right, ConstantValue.NotAvailable, methodOpt: null,
resultKind: LookupResultKind.Empty, type: GetBinaryOperatorErrorType(kind, diagnostics, node), hasErrors: true);
}
// Let's take an easy out here. The vast majority of the time the operands will
// both be bool. This is the only situation in which the expression can be a
// constant expression, so do the folding now if we can.
......@@ -751,6 +741,16 @@ private BoundExpression BindConditionalLogicalOperator(BinaryExpressionSyntax no
resultKind: LookupResultKind.Viable, type: left.Type, hasErrors: constantValue != null && constantValue.IsBad);
}
// If either operand is bad, don't try to do binary operator overload resolution; that will just
// make cascading errors.
if (left.HasAnyErrors || right.HasAnyErrors)
{
// NOTE: no candidate user-defined operators.
return new BoundBinaryOperator(node, kind, left, right, ConstantValue.NotAvailable, methodOpt: null,
resultKind: LookupResultKind.Empty, type: GetBinaryOperatorErrorType(kind, diagnostics, node), hasErrors: true);
}
if (left.HasDynamicType() || right.HasDynamicType())
{
return BindDynamicBinaryOperator(node, kind, left, right, diagnostics);
......
......@@ -2764,6 +2764,11 @@ public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
SetState(dispatchState.Clone());
VisitPattern(node.Expression, arm.Pattern);
SetState(StateWhenTrue);
if (arm.Pattern.HasErrors)
{
// suppress definite assignment errors on broken switch arms
SetUnreachable();
}
if (arm.Guard != null)
{
VisitCondition(arm.Guard);
......
......@@ -6577,12 +6577,9 @@ public class A : Attribute
class C<T, U> { public enum E {} }";
CreateCompilation(source).VerifyDiagnostics(
// (7,31): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [A(new object[] { default(E), default(E) })]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "default(E)").WithLocation(7, 31),
// (7,19): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [A(new object[] { default(E), default(E) })]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "default(E)").WithLocation(7, 19));
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "default(E)").WithLocation(7, 19)
}
[Fact]
......
......@@ -1975,7 +1975,7 @@ class Test : System.Attribute
// (9,15): error CS0841: Cannot use local variable 'x4' before it is declared
// [Test(p = x4 && TakeOutParam(out int x4))]
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(9, 15),
// (11,40): error CS0128: A local variable named 'x5' is already defined in this scope
// (11,40): error CS0128: A local variable or function named 'x5' is already defined in this scope
// TakeOutParam(52, out int x5) &&
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(11, 40),
// (10,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
......@@ -1983,15 +1983,12 @@ class Test : System.Attribute
Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"TakeOutParam(51, out int x5) &&
TakeOutParam(52, out int x5) &&
x5 > 0").WithLocation(10, 15),
// (14,37): error CS0128: A local variable named 'x6' is already defined in this scope
// (14,37): error CS0128: A local variable or function named 'x6' is already defined in this scope
// p2 = TakeOutParam(out int x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(14, 37),
// (13,16): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(p1 = TakeOutParam(out int x6) && x6 > 0,
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x6) && x6 > 0").WithLocation(13, 16),
// (14,16): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// p2 = TakeOutParam(out int x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x6) && x6 > 0").WithLocation(14, 16),
// (15,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(p = TakeOutParam(out int x7) && x7 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x7) && x7 > 0").WithLocation(15, 15),
......@@ -2085,7 +2082,7 @@ class Test : System.Attribute
// (9,11): error CS0841: Cannot use local variable 'x4' before it is declared
// [Test(x4 && TakeOutParam(out int x4))]
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(9, 11),
// (11,36): error CS0128: A local variable named 'x5' is already defined in this scope
// (11,36): error CS0128: A local variable or function named 'x5' is already defined in this scope
// TakeOutParam(52, out int x5) &&
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(11, 36),
// (10,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
......@@ -2093,15 +2090,12 @@ class Test : System.Attribute
Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"TakeOutParam(51, out int x5) &&
TakeOutParam(52, out int x5) &&
x5 > 0").WithLocation(10, 11),
// (14,32): error CS0128: A local variable named 'x6' is already defined in this scope
// (14,32): error CS0128: A local variable or function named 'x6' is already defined in this scope
// TakeOutParam(out int x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(14, 32),
// (13,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(TakeOutParam(out int x6) && x6 > 0,
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x6) && x6 > 0").WithLocation(13, 11),
// (14,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// TakeOutParam(out int x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x6) && x6 > 0").WithLocation(14, 11),
// (15,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(TakeOutParam(out int x7) && x7 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out int x7) && x7 > 0").WithLocation(15, 11),
......@@ -2197,7 +2191,7 @@ class Test : System.Attribute
// (9,15): error CS0841: Cannot use local variable 'x4' before it is declared
// [Test(p = x4 && TakeOutParam(out var x4))]
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(9, 15),
// (11,40): error CS0128: A local variable named 'x5' is already defined in this scope
// (11,40): error CS0128: A local variable or function named 'x5' is already defined in this scope
// TakeOutParam(52, out var x5) &&
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(11, 40),
// (10,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
......@@ -2205,15 +2199,12 @@ class Test : System.Attribute
Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"TakeOutParam(51, out var x5) &&
TakeOutParam(52, out var x5) &&
x5 > 0").WithLocation(10, 15),
// (14,37): error CS0128: A local variable named 'x6' is already defined in this scope
// (14,37): error CS0128: A local variable or function named 'x6' is already defined in this scope
// p2 = TakeOutParam(out var x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(14, 37),
// (13,16): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(p1 = TakeOutParam(out var x6) && x6 > 0,
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x6) && x6 > 0").WithLocation(13, 16),
// (14,16): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// p2 = TakeOutParam(out var x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x6) && x6 > 0").WithLocation(14, 16),
// (15,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(p = TakeOutParam(out var x7) && x7 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x7) && x7 > 0").WithLocation(15, 15),
......@@ -2307,7 +2298,7 @@ class Test : System.Attribute
// (9,11): error CS0841: Cannot use local variable 'x4' before it is declared
// [Test(x4 && TakeOutParam(out var x4))]
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(9, 11),
// (11,36): error CS0128: A local variable named 'x5' is already defined in this scope
// (11,36): error CS0128: A local variable or function named 'x5' is already defined in this scope
// TakeOutParam(52, out var x5) &&
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(11, 36),
// (10,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
......@@ -2315,15 +2306,12 @@ class Test : System.Attribute
Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"TakeOutParam(51, out var x5) &&
TakeOutParam(52, out var x5) &&
x5 > 0").WithLocation(10, 11),
// (14,32): error CS0128: A local variable named 'x6' is already defined in this scope
// (14,32): error CS0128: A local variable or function named 'x6' is already defined in this scope
// TakeOutParam(out var x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x6").WithArguments("x6").WithLocation(14, 32),
// (13,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(TakeOutParam(out var x6) && x6 > 0,
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x6) && x6 > 0").WithLocation(13, 11),
// (14,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// TakeOutParam(out var x6) && x6 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x6) && x6 > 0").WithLocation(14, 11),
// (15,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Test(TakeOutParam(out var x7) && x7 > 0)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "TakeOutParam(out var x7) && x7 > 0").WithLocation(15, 11),
......@@ -11472,9 +11460,6 @@ static bool TakeOutParam<T>(T y, out T x)
// (94,15): error CS0103: The name 'u7' does not exist in the current context
// Dummy(u7);
Diagnostic(ErrorCode.ERR_NameNotInContext, "u7").WithArguments("u7").WithLocation(94, 15),
// (88,68): error CS0165: Use of unassigned local variable 'u7'
// x > y7 && TakeOutParam(1, out var u7) && u7 ==
Diagnostic(ErrorCode.ERR_UseDefViolation, "u7").WithArguments("u7").WithLocation(88, 68),
// (102,15): error CS0103: The name 'z8' does not exist in the current context
// Dummy(z8);
Diagnostic(ErrorCode.ERR_NameNotInContext, "z8").WithArguments("z8").WithLocation(102, 15),
......@@ -24125,10 +24110,7 @@ static bool TakeOutParam<T>(T y, out T x)
Diagnostic(ErrorCode.ERR_NameNotInContext, "z9").WithArguments("z9").WithLocation(82, 7),
// (83,7): error CS0103: The name 'u9' does not exist in the current context
// Dummy(u9);
Diagnostic(ErrorCode.ERR_NameNotInContext, "u9").WithArguments("u9").WithLocation(83, 7),
// (62,62): error CS0165: Use of unassigned local variable 'u7'
// x > y7 && TakeOutParam(1, out var u7) && u7 ==
Diagnostic(ErrorCode.ERR_UseDefViolation, "u7").WithArguments("u7").WithLocation(62, 62)
Diagnostic(ErrorCode.ERR_NameNotInContext, "u9").WithArguments("u9").WithLocation(83, 7)
);
var tree = compilation.SyntaxTrees.Single();
......@@ -32989,18 +32971,12 @@ class MyAttribute: System.Attribute
// (2,5): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [My(C.M(nameof(C.M(out int z1)), z1), z1)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out int z1)), z1)").WithLocation(2, 5),
// (2,39): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [My(C.M(nameof(C.M(out int z1)), z1), z1)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "z1").WithLocation(2, 39),
// (3,16): error CS8081: Expression does not have a name.
// [My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "C.M(out var z2)").WithLocation(3, 16),
// (3,5): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out var z2)), z2)").WithLocation(3, 5),
// (3,39): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "z2").WithLocation(3, 39)
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out var z2)), z2)").WithLocation(3, 5)
);
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
......@@ -33043,18 +33019,12 @@ class MyAttribute: System.Attribute
// (2,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [assembly: My(C.M(nameof(C.M(out int z1)), z1), z1)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out int z1)), z1)").WithLocation(2, 15),
// (2,49): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [assembly: My(C.M(nameof(C.M(out int z1)), z1), z1)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "z1").WithLocation(2, 49),
// (3,26): error CS8081: Expression does not have a name.
// [assembly: My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "C.M(out var z2)").WithLocation(3, 26),
// (3,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [assembly: My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out var z2)), z2)").WithLocation(3, 15),
// (3,49): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [assembly: My(C.M(nameof(C.M(out var z2)), z2), z2)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "z2").WithLocation(3, 49)
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(nameof(C.M(out var z2)), z2)").WithLocation(3, 15)
);
var tree = compilation.SyntaxTrees[0];
var model = compilation.GetSemanticModel(tree);
......@@ -1048,6 +1048,53 @@ public static void M(object o)
);
}
[Fact]
public void ErroneousSwitchArmDefiniteAssignment()
{
// When a switch expression arm is erroneous, ensure that the expression is treated as unreachable (e.g. for definite assignment purposes).
var source =
@"class Program2
{
public static int Main() => 0;
public static void M(string s)
{
int i;
int j = s switch { ""frog"" => 1, 0 => i, _ => 2 };
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,41): error CS0029: Cannot implicitly convert type 'int' to 'string'
// int j = s switch { "frog" => 1, 0 => i, _ => 2 };
Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "string").WithLocation(7, 41)
);
}
[Fact, WorkItem(9154, "https://github.com/dotnet/roslyn/issues/9154")]
public void ErroneousIsPatternDefiniteAssignment()
{
var source =
@"class Program2
{
public static int Main() => 0;
void Dummy(object o) {}
void Test5()
{
Dummy((System.Func<object, object, bool>) ((o1, o2) => o1 is int x5 &&
o2 is int x5 &&
x5 > 0));
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (8,74): error CS0128: A local variable or function named 'x5' is already defined in this scope
// o2 is int x5 &&
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(8, 74)
);
}
// PROTOTYPE(patterns2): Need to have tests that exercise:
// PROTOTYPE(patterns2): Building the decision tree for the var-pattern
// PROTOTYPE(patterns2): Definite assignment for the var-pattern
......
......@@ -7267,10 +7267,7 @@ into g
Diagnostic(ErrorCode.ERR_NameNotInContext, "z9").WithArguments("z9").WithLocation(82, 7),
// (83,7): error CS0103: The name 'u9' does not exist in the current context
// Dummy(u9);
Diagnostic(ErrorCode.ERR_NameNotInContext, "u9").WithArguments("u9").WithLocation(83, 7),
// (62,46): error CS0165: Use of unassigned local variable 'u7'
// x > y7 && 1 is var u7 && u7 ==
Diagnostic(ErrorCode.ERR_UseDefViolation, "u7").WithArguments("u7").WithLocation(62, 46)
Diagnostic(ErrorCode.ERR_NameNotInContext, "u9").WithArguments("u9").WithLocation(83, 7)
);
var tree = compilation.SyntaxTrees.Single();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册