未验证 提交 0643513e 编写于 作者: C Charles Stoner 提交者: GitHub

Erase nullability for unconstrained type parameters in constraints from...

Erase nullability for unconstrained type parameters in constraints from unannotated assemblies (#28282)
上级 3f9c5ef8
...@@ -903,9 +903,6 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost ...@@ -903,9 +903,6 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost
} }
else else
{ {
// Treat reference types as nullable if inferring nullability.
declTypeOpt = declTypeOpt.AsNullableReferenceTypeIfInferLocalNullability(declarator);
if (ReferenceEquals(equalsClauseSyntax, null)) if (ReferenceEquals(equalsClauseSyntax, null))
{ {
initializerOpt = null; initializerOpt = null;
...@@ -959,9 +956,6 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost ...@@ -959,9 +956,6 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost
hasErrors = true; hasErrors = true;
} }
// Treat reference types as nullable if inferring nullability.
declTypeOpt = declTypeOpt.AsNullableReferenceTypeIfInferLocalNullability(declarator);
localSymbol.SetTypeSymbol(declTypeOpt); localSymbol.SetTypeSymbol(declTypeOpt);
if (initializerOpt != null) if (initializerOpt != null)
......
...@@ -3718,7 +3718,7 @@ public override BoundNode VisitSuppressNullableWarningExpression(BoundSuppressNu ...@@ -3718,7 +3718,7 @@ public override BoundNode VisitSuppressNullableWarningExpression(BoundSuppressNu
//if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability? //if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability?
{ {
_resultType = _resultType?.WithTopLevelNonNullability(); _resultType = _resultType?.WithTopLevelNonNullabilityForReferenceTypes();
} }
return null; return null;
......
...@@ -11,7 +11,7 @@ internal enum NullableReferenceFlags ...@@ -11,7 +11,7 @@ internal enum NullableReferenceFlags
{ {
None = 0, None = 0,
//AllowNullAsNonNull = 0x1, //AllowNullAsNonNull = 0x1,
InferLocalNullability = 0x2, //InferLocalNullability = 0x2,
AllowMemberOptOut = 0x4, AllowMemberOptOut = 0x4,
AllowAssemblyOptOut = 0x8, AllowAssemblyOptOut = 0x8,
Enabled = 0x1000, Enabled = 0x1000,
......
...@@ -346,11 +346,6 @@ private TypeSymbolWithAnnotations GetTypeSymbol() ...@@ -346,11 +346,6 @@ private TypeSymbolWithAnnotations GetTypeSymbol()
declType = TypeSymbolWithAnnotations.Create(typeBinder.CreateErrorType("var")); declType = TypeSymbolWithAnnotations.Create(typeBinder.CreateErrorType("var"));
} }
} }
else
{
// Treat reference types as nullable if inferring nullability.
declType = declType.AsNullableReferenceTypeIfInferLocalNullability(_typeSyntax);
}
Debug.Assert((object)declType != null); Debug.Assert((object)declType != null);
......
...@@ -249,7 +249,7 @@ public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilatio ...@@ -249,7 +249,7 @@ public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilatio
// In this case we delay asking this question as long as possible. // In this case we delay asking this question as long as possible.
if (typeSymbol.TypeKind != TypeKind.TypeParameter) if (typeSymbol.TypeKind != TypeKind.TypeParameter)
{ {
if (typeSymbol.IsReferenceType) if (!typeSymbol.IsValueType)
{ {
return new NonLazyType(typeSymbol, isNullable: true, this.CustomModifiers); return new NonLazyType(typeSymbol, isNullable: true, this.CustomModifiers);
} }
...@@ -262,23 +262,6 @@ public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilatio ...@@ -262,23 +262,6 @@ public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilatio
return new LazyNullableType(compilation, this); return new LazyNullableType(compilation, this);
} }
/// <summary>
/// Return nullable type if the type is a non-nullable
/// reference type and local nullability is inferred.
/// </summary>
public TypeSymbolWithAnnotations AsNullableReferenceTypeIfInferLocalNullability(SyntaxNode syntax)
{
if (IsReferenceType && IsNullable == false)
{
var flags = ((CSharpParseOptions)syntax.SyntaxTree.Options).GetNullableReferenceFlags();
if ((flags & NullableReferenceFlags.InferLocalNullability) != 0)
{
return AsNullableReferenceType();
}
}
return this;
}
/// <summary> /// <summary>
/// Adjust types in signatures coming from metadata. /// Adjust types in signatures coming from metadata.
/// </summary> /// </summary>
...@@ -519,7 +502,7 @@ public bool ContainsNullableReferenceTypes() ...@@ -519,7 +502,7 @@ public bool ContainsNullableReferenceTypes()
{ {
var typeSymbol = TypeSymbol; var typeSymbol = TypeSymbol;
if (IsNullable == true && !typeSymbol.IsNullableType() && typeSymbol.IsReferenceType) if (IsNullable == true && !typeSymbol.IsValueType)
{ {
return true; return true;
} }
...@@ -595,10 +578,10 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypesIfNecessa ...@@ -595,10 +578,10 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypesIfNecessa
this.SetUnknownNullabilityForReferenceTypes(); this.SetUnknownNullabilityForReferenceTypes();
} }
public TypeSymbolWithAnnotations WithTopLevelNonNullability() public TypeSymbolWithAnnotations WithTopLevelNonNullabilityForReferenceTypes()
{ {
var typeSymbol = TypeSymbol; var typeSymbol = TypeSymbol;
if (IsNullable == false || !typeSymbol.IsReferenceType) if (IsNullable == false || typeSymbol.IsValueType)
{ {
return this; return this;
} }
...@@ -612,7 +595,7 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes() ...@@ -612,7 +595,7 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes()
if (IsNullable.HasValue) if (IsNullable.HasValue)
{ {
if (!typeSymbol.IsNullableType() && typeSymbol.IsReferenceType) if (!typeSymbol.IsValueType)
{ {
typeSymbol = typeSymbol.SetUnknownNullabilityForReferenceTypes(); typeSymbol = typeSymbol.SetUnknownNullabilityForReferenceTypes();
return new NonLazyType(typeSymbol, isNullable: null, CustomModifiers); return new NonLazyType(typeSymbol, isNullable: null, CustomModifiers);
......
...@@ -28741,8 +28741,6 @@ public void GetNullableReferenceFlags() ...@@ -28741,8 +28741,6 @@ public void GetNullableReferenceFlags()
TestOptions.Regular8.WithFeature("staticNullChecking").GetNullableReferenceFlags()); TestOptions.Regular8.WithFeature("staticNullChecking").GetNullableReferenceFlags());
Assert.Equal(NullableReferenceFlags.Enabled, Assert.Equal(NullableReferenceFlags.Enabled,
TestOptions.Regular8.WithFeature("staticNullChecking", "0").GetNullableReferenceFlags()); TestOptions.Regular8.WithFeature("staticNullChecking", "0").GetNullableReferenceFlags());
Assert.Equal(NullableReferenceFlags.Enabled | NullableReferenceFlags.InferLocalNullability,
TestOptions.Regular8.WithFeature("staticNullChecking", "2").GetNullableReferenceFlags());
Assert.Equal(NullableReferenceFlags.Enabled | NullableReferenceFlags.AllowMemberOptOut | NullableReferenceFlags.AllowAssemblyOptOut, Assert.Equal(NullableReferenceFlags.Enabled | NullableReferenceFlags.AllowMemberOptOut | NullableReferenceFlags.AllowAssemblyOptOut,
TestOptions.Regular8.WithFeature("staticNullChecking", "12").GetNullableReferenceFlags()); TestOptions.Regular8.WithFeature("staticNullChecking", "12").GetNullableReferenceFlags());
Assert.Equal(NullableReferenceFlags.Enabled | (NullableReferenceFlags)0x123, Assert.Equal(NullableReferenceFlags.Enabled | (NullableReferenceFlags)0x123,
...@@ -28914,23 +28912,11 @@ static void G(string s) ...@@ -28914,23 +28912,11 @@ static void G(string s)
// F(y); // F(y);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("s", "string? C.F(string s)").WithLocation(11, 11)); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("s", "string? C.F(string s)").WithLocation(11, 11));
comp = CreateCompilation(
source,
parseOptions: TestOptions.Regular8.WithNullCheckingFeature(NullableReferenceFlags.InferLocalNullability));
comp.VerifyDiagnostics(
// (8,11): warning CS8604: Possible null reference argument for parameter 's' in 'string? C.F(string s)'.
// F(x);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("s", "string? C.F(string s)").WithLocation(8, 11),
// (11,11): warning CS8604: Possible null reference argument for parameter 's' in 'string? C.F(string s)'.
// F(y);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("s", "string? C.F(string s)").WithLocation(11, 11));
var tree = comp.SyntaxTrees[0]; var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree); var model = comp.GetSemanticModel(tree);
var declarator = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().First(); var declarator = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().First();
var symbol = (LocalSymbol)model.GetDeclaredSymbol(declarator); var symbol = (LocalSymbol)model.GetDeclaredSymbol(declarator);
Assert.Equal("System.String?", symbol.Type.ToTestDisplayString()); Assert.Equal("System.String!", symbol.Type.ToTestDisplayString(true));
Assert.Equal(true, symbol.Type.IsNullable);
} }
[Fact] [Fact]
...@@ -34171,6 +34157,80 @@ static void F(IEnumerable<C> c) ...@@ -34171,6 +34157,80 @@ static void F(IEnumerable<C> c)
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "E").WithArguments("C.E", "").WithLocation(5, 10)); Diagnostic(ErrorCode.WRN_UnassignedInternalField, "E").WithArguments("C.E", "").WithLocation(5, 10));
} }
[Fact]
public void Constraints_01()
{
var source =
@"interface I<T>
{
T P { get; set; }
}
class A { }
class B
{
static void F1<T>(T t1) where T : A
{
t1.ToString();
t1 = default; // 1
}
static void F2<T>(T t2) where T : A?
{
t2.ToString(); // 2
t2 = default; // 3
}
static void F3<T>(T t3) where T : I<T>
{
t3.P.ToString(); // 4
t3 = default; // 5
}
static void F4<T>(T t4) where T : I<T>?
{
t4.P.ToString(); // 6 and 7
t4.P = default; // 8
t4 = default;
}
static void F5<T>(T t5) where T : I<T?>
{
t5.P.ToString(); // 9
t5.P = default;
t5 = default; // 10
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
// PROTOTYPE(NullableReferenceTypes): Various differences from expected warnings.
comp.VerifyDiagnostics(
// (11,14): warning CS8600: Converting null literal or possible null value to non-nullable type.
// t1 = default; // 1
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "default").WithLocation(11, 14),
// (16,14): warning CS8600: Converting null literal or possible null value to non-nullable type.
// t2 = default; // 3
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "default").WithLocation(16, 14),
// (20,9): warning CS8602: Possible dereference of a null reference.
// t3.P.ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t3").WithLocation(20, 9),
// (20,9): warning CS8602: Possible dereference of a null reference.
// t3.P.ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t3.P").WithLocation(20, 9),
// (25,9): warning CS8602: Possible dereference of a null reference.
// t4.P.ToString(); // 6 and 7
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t4").WithLocation(25, 9),
// (25,9): warning CS8602: Possible dereference of a null reference.
// t4.P.ToString(); // 6 and 7
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t4.P").WithLocation(25, 9),
// (26,9): warning CS8602: Possible dereference of a null reference.
// t4.P = default; // 8
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t4").WithLocation(26, 9),
// (31,9): warning CS8602: Possible dereference of a null reference.
// t5.P.ToString(); // 9
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t5").WithLocation(31, 9),
// (31,9): warning CS8602: Possible dereference of a null reference.
// t5.P.ToString(); // 9
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t5.P").WithLocation(31, 9),
// (32,9): warning CS8602: Possible dereference of a null reference.
// t5.P = default;
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t5").WithLocation(32, 9));
}
// PROTOTYPE(NullableReferenceTypes): Should report CS8600 for `T1 t = (T1)NullableObject();` // PROTOTYPE(NullableReferenceTypes): Should report CS8600 for `T1 t = (T1)NullableObject();`
// and `T3 t = (T3)NullableObject();`. (See VisitConversion which skips reporting because the // and `T3 t = (T3)NullableObject();`. (See VisitConversion which skips reporting because the
// `object?` has an Unboxing conversion. Should report warning on unconverted operand // `object?` has an Unboxing conversion. Should report warning on unconverted operand
...@@ -35467,6 +35527,9 @@ static void Main() ...@@ -35467,6 +35527,9 @@ static void Main()
// (8,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter. // (8,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// A<B2>.F(null); // warning // A<B2>.F(null); // warning
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 17)); Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 17));
var constraintTypes = comp.GetMember<NamedTypeSymbol>("A").TypeParameters[0].ConstraintTypesNoUseSiteDiagnostics;
Assert.Equal("I<T>", constraintTypes[0].ToTestDisplayString(true));
} }
[Fact] [Fact]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册