提交 cb6761e4 编写于 作者: N Neal Gafter

Merge pull request #331 from gafter/fix324

Allow 'is' for static classes for compatibility. Fixes #324.
......@@ -2537,12 +2537,12 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa
return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}
// BREAKING CHANGE: The native compiler allows "x is C" where C is a static class. This
// BREAKING CHANGE: is strictly illegal according to the specification (see the section
// BREAKING CHANGE: called "Referencing Static Class Types".) We break with the native
// BREAKING CHANGE: compiler here and turn this into an error, as it should be.
if (targetType.IsStatic)
// The native compiler allows "x is C" where C is a static class. This
// is strictly illegal according to the specification (see the section
// called "Referencing Static Class Types".) To retain compatibility we
// allow it, but when /feature:strict is enabled we break with the native
// compiler and turn this into an error, as it should be.
if (targetType.IsStatic && Compilation.FeatureStrictEnabled)
{
Error(diagnostics, ErrorCode.ERR_StaticInAsOrIs, node, targetType);
return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
......@@ -2924,15 +2924,16 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}
// BREAKING CHANGE: The C# specification states in the section called
// BREAKING CHANGE: "Referencing Static Class Types" that it is always
// BREAKING CHANGE: illegal to use "as" with a static type. The
// BREAKING CHANGE: native compiler actually allows "null as C" for
// BREAKING CHANGE: a static type C to be an expression of type C.
// BREAKING CHANGE: It also allows "someObject as C" if "someObject"
// BREAKING CHANGE: is of type object.
if (targetType.IsStatic)
// The C# specification states in the section called
// "Referencing Static Class Types" that it is always
// illegal to use "as" with a static type. The
// native compiler actually allows "null as C" for
// a static type C to be an expression of type C.
// It also allows "someObject as C" if "someObject"
// is of type object. To retain compatibility we
// allow it, but when /feature:strict is enabled we break with the native
// compiler and turn this into an error, as it should be.
if (targetType.IsStatic && Compilation.FeatureStrictEnabled)
{
Error(diagnostics, ErrorCode.ERR_StaticInAsOrIs, node, targetType);
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
......
......@@ -43,7 +43,7 @@ private bool Strict
get
{
if (_strict.HasValue) return _strict.Value;
bool value = _binder.Compilation.Feature("strict") != null;
bool value = _binder.Compilation.FeatureStrictEnabled;
_strict = value;
return value;
}
......
......@@ -155,6 +155,13 @@ internal override CommonAnonymousTypeManager CommonAnonymousTypeManager
}
}
/// <summary>
/// True when the compiler is run in "strict" mode, in which it enforces the language specification
/// in some cases even at the expense of full compatibility. Such differences typically arise when
/// earlier versions of the compiler failed to enforce the full language specification.
/// </summary>
internal bool FeatureStrictEnabled => Feature("strict") != null;
/// <summary>
/// The language version that was used to parse the syntax trees of this compilation.
/// </summary>
......
......@@ -123,7 +123,7 @@ protected override void Free()
_sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly;
this.currentMethodOrLambda = member as MethodSymbol;
_unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes;
bool strict = compilation.Feature("strict") != null; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility
bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility
_emptyStructTypeCache = new EmptyStructTypeCache(compilation, !strict);
_requireOutParamsAssigned = requireOutParamsAssigned;
this.topLevelMethod = member as MethodSymbol;
......@@ -142,7 +142,7 @@ protected override void Free()
_sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly;
this.currentMethodOrLambda = member as MethodSymbol;
_unassignedVariableAddressOfSyntaxes = null;
bool strict = compilation.Feature("strict") != null; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility
bool strict = compilation.FeatureStrictEnabled; // Compiler flag /features:strict removes the relaxed DA checking we have for backward compatibility
_emptyStructTypeCache = emptyStructs ?? new EmptyStructTypeCache(compilation, !strict);
_requireOutParamsAssigned = true;
this.topLevelMethod = member as MethodSymbol;
......
......@@ -12462,8 +12462,30 @@ static void M(object o)
}
}
";
CreateCompilationWithMscorlib(text).VerifyDiagnostics(
var comp = CreateCompilationWithMscorlib(text);
// these diagnostics correspond to those produced by the native compiler.
comp.VerifyDiagnostics(
// (9,11): error CS0039: Cannot convert type 'int' to 'C' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
// M(1 as C);
Diagnostic(ErrorCode.ERR_NoExplicitBuiltinConv, "1 as C").WithArguments("int", "C").WithLocation(9, 11),
// (10,11): error CS0039: Cannot convert type 'string' to 'C' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
// M("a" as C);
Diagnostic(ErrorCode.ERR_NoExplicitBuiltinConv, @"""a"" as C").WithArguments("string", "C").WithLocation(10, 11),
// (14,11): warning CS0184: The given expression is never of the provided ('C') type
// M(null is C); // legal in native, warns
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "null is C").WithArguments("C").WithLocation(14, 11),
// (15,11): warning CS0184: The given expression is never of the provided ('C') type
// M(1 is C); // legal in native, warns
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1 is C").WithArguments("C").WithLocation(15, 11),
// (16,11): warning CS0184: The given expression is never of the provided ('C') type
// M("a" is C); // legal in native, warns
Diagnostic(ErrorCode.WRN_IsAlwaysFalse, @"""a"" is C").WithArguments("C").WithLocation(16, 11)
);
// in strict mode we also diagnose "is" and "as" operators with a static type.
comp = comp.WithOptions(comp.Options.WithFeatures(new string[] { "strict" }.ToImmutableArray()));
comp.VerifyDiagnostics(
// In the native compiler these three produce no errors.
Diagnostic(ErrorCode.ERR_StaticInAsOrIs, "o as C").WithArguments("C"),
......@@ -12487,7 +12509,8 @@ static void M(object o)
Diagnostic(ErrorCode.ERR_StaticInAsOrIs, "null is C").WithArguments("C"),
Diagnostic(ErrorCode.ERR_StaticInAsOrIs, "1 is C").WithArguments("C"),
Diagnostic(ErrorCode.ERR_StaticInAsOrIs, "\"a\" is C").WithArguments("C"));
Diagnostic(ErrorCode.ERR_StaticInAsOrIs, "\"a\" is C").WithArguments("C")
);
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册