未验证 提交 fc15d5ee 编写于 作者: J Julien Couvreur 提交者: GitHub

Suppression operator produces non-null result (#27317)

上级 95d9eee4
......@@ -1177,6 +1177,11 @@ protected virtual void AssignImpl(BoundNode node, BoundExpression value, bool is
((BoundTupleExpression)node).VisitAllElements((x, self) => self.Assign(x, value: null, isRef: isRef), this);
break;
case BoundKind.SuppressNullableWarningExpression:
// for example, assigning to `x!` in `M(out x!)` assigns to `x`
AssignImpl(((BoundSuppressNullableWarningExpression)node).Expression, value, isRef, written, read);
break;
default:
// Other kinds of left-hand-sides either represent things not tracked (e.g. array elements)
// or errors that have been reported earlier (e.g. assignment to a unary increment)
......@@ -1871,7 +1876,6 @@ protected void CheckAssigned(BoundExpression expr, SyntaxNode node)
case BoundKind.BaseReference:
CheckAssigned(MethodThisParameter, node);
break;
//CheckAssigned(expr,
}
}
......
......@@ -343,6 +343,9 @@ private static object GetTypeAsDiagnosticArgument(TypeSymbol typeOpt)
return typeOpt ?? (object)"<null>";
}
/// <summary>
/// Reports top-level nullability problem in assignment.
/// </summary>
private bool ReportNullReferenceAssignmentIfNecessary(BoundExpression value, TypeSymbolWithAnnotations targetType, TypeSymbolWithAnnotations valueType, bool useLegacyWarnings)
{
Debug.Assert(value != null);
......@@ -1427,6 +1430,7 @@ TypeSymbol getLeftResultType(TypeSymbol leftType, TypeSymbol rightType)
{
return rightType;
}
GenerateConversionForConditionalOperator(node.RightOperand, rightType, leftType, reportMismatch: true);
return leftType;
}
......@@ -1971,34 +1975,49 @@ private void VisitArgumentEvaluate(ImmutableArray<BoundExpression> arguments, Im
}
break;
case RefKind.Out:
if (argument is BoundLocal local && local.DeclarationKind == BoundLocalDeclarationKind.WithInferredType)
{
_variableTypes[local.LocalSymbol] = parameterType;
resultType = parameterType;
}
if (!ReportNullReferenceAssignmentIfNecessary(argument, resultType, parameterType, useLegacyWarnings: UseLegacyWarnings(argument)))
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (!_conversions.HasIdentityOrImplicitReferenceConversion(parameterType.TypeSymbol, argumentType, ref useSiteDiagnostics))
bool reportedWarning = false;
if (argument is BoundLocal local && local.DeclarationKind == BoundLocalDeclarationKind.WithInferredType)
{
ReportNullabilityMismatchInArgument(argument, argumentType, parameter, parameterType.TypeSymbol);
_variableTypes[local.LocalSymbol] = parameterType;
resultType = parameterType;
}
if (argument.Kind != BoundKind.SuppressNullableWarningExpression)
{
reportedWarning = ReportNullReferenceAssignmentIfNecessary(argument, resultType, parameterType, useLegacyWarnings: UseLegacyWarnings(argument));
}
if (!reportedWarning)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (!_conversions.HasIdentityOrImplicitReferenceConversion(parameterType.TypeSymbol, argumentType, ref useSiteDiagnostics))
{
ReportNullabilityMismatchInArgument(argument, argumentType, parameter, parameterType.TypeSymbol);
}
}
// Set nullable state of argument to parameter type.
TrackNullableStateForAssignment(argument, resultType, result.Slot, parameterType);
break;
}
// Set nullable state of argument to parameter type.
TrackNullableStateForAssignment(argument, resultType, result.Slot, parameterType);
break;
case RefKind.Ref:
if (!ReportNullReferenceArgumentIfNecessary(argument, resultType, parameter, parameterType) &&
!ReportNullReferenceAssignmentIfNecessary(argument, resultType, parameterType, useLegacyWarnings: UseLegacyWarnings(argument)))
{
if ((object)argumentType != null && IsNullabilityMismatch(argumentType, parameterType.TypeSymbol))
bool reportedWarning = false;
if (argument.Kind != BoundKind.SuppressNullableWarningExpression)
{
ReportNullabilityMismatchInArgument(argument, argumentType, parameter, parameterType.TypeSymbol);
reportedWarning = ReportNullReferenceArgumentIfNecessary(argument, resultType, parameter, parameterType) ||
ReportNullReferenceAssignmentIfNecessary(argument, resultType, parameterType, useLegacyWarnings: UseLegacyWarnings(argument));
}
if (!reportedWarning)
{
if ((object)argumentType != null &&
IsNullabilityMismatch(argumentType, parameterType.TypeSymbol))
{
ReportNullabilityMismatchInArgument(argument, argumentType, parameter, parameterType.TypeSymbol);
}
}
// Set nullable state of argument to parameter type.
TrackNullableStateForAssignment(argument, resultType, result.Slot, parameterType);
break;
}
// Set nullable state of argument to parameter type.
TrackNullableStateForAssignment(argument, resultType, result.Slot, parameterType);
break;
default:
throw ExceptionUtilities.UnexpectedValue(refKind);
}
......@@ -3414,14 +3433,14 @@ public override BoundNode VisitAsOperator(BoundAsOperator node)
public override BoundNode VisitSuppressNullableWarningExpression(BoundSuppressNullableWarningExpression node)
{
var result = base.VisitSuppressNullableWarningExpression(node);
base.VisitSuppressNullableWarningExpression(node);
//if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability?
{
_result = _result.Type?.SetUnknownNullabilityForReferenceTypes();
_result = _result.Type?.WithTopLevelNonNullability();
}
return result;
return null;
}
public override BoundNode VisitSizeOfOperator(BoundSizeOfOperator node)
......
......@@ -551,6 +551,10 @@ protected void VisitLvalue(BoundExpression node)
((BoundTupleExpression)node).VisitAllElements((x, self) => self.VisitLvalue(x), this);
break;
case BoundKind.SuppressNullableWarningExpression:
VisitLvalue(((BoundSuppressNullableWarningExpression)node).Expression);
break;
default:
VisitRvalue(node);
break;
......
......@@ -580,6 +580,17 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypesIfNecessa
this.SetUnknownNullabilityForReferenceTypes();
}
public TypeSymbolWithAnnotations WithTopLevelNonNullability()
{
var typeSymbol = TypeSymbol;
if (IsNullable == false || !typeSymbol.IsReferenceType)
{
return this;
}
return new NonLazyType(typeSymbol, isNullable: false, CustomModifiers);
}
public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes()
{
var typeSymbol = TypeSymbol;
......
......@@ -49,10 +49,15 @@ static void F(object x, object? y)
a[0].ToString();
var b = new[] { y };
b[0].ToString();
}
static void F(object[] a, object?[] b)
{
var c = new[] { a, b };
c[0][0].ToString();
var d = new[] { a, b! };
d[0][0].ToString();
var e = new[] { b!, a };
e[0][0].ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
......@@ -60,9 +65,15 @@ static void F(object x, object? y)
// (8,9): warning CS8602: Possible dereference of a null reference.
// b[0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b[0]").WithLocation(8, 9),
// (10,9): warning CS8602: Possible dereference of a null reference.
// (13,9): warning CS8602: Possible dereference of a null reference.
// c[0][0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c[0][0]").WithLocation(10, 9));
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c[0][0]").WithLocation(13, 9),
// (15,9): warning CS8602: Possible dereference of a null reference.
// d[0][0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "d[0][0]").WithLocation(15, 9),
// (17,9): warning CS8602: Possible dereference of a null reference.
// e[0][0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "e[0][0]").WithLocation(17, 9));
}
[Fact]
......@@ -2742,8 +2753,7 @@ static void F(IOut<object> x, IOut<object?> y, IOut<object>? z, IOut<object?>? w
}
// PROTOTYPE(NullableReferenceTypes): Update this method to use types from unannotated assemblies
// rather than `x!`, particularly because `x!` should result in IsNullable=false rather than IsNullable=null.
// PROTOTYPE(NullableReferenceTypes): Should report the same warnings (or no warnings) for { x, x! } and { x!, x }.
// rather than `x!`, particularly because `x!` results in IsNullable=false rather than IsNullable=null.
[Fact]
public void IdentityConversion_ArrayInitializer_IsNullableNull()
{
......@@ -2760,6 +2770,7 @@ static void F(object? x, object y)
{
(new[] { x, x! })[0].ToString();
(new[] { x!, x })[0].ToString();
(new[] { x!, x! })[0].ToString();
(new[] { y, y! })[0].ToString();
(new[] { y!, y })[0].ToString();
}
......@@ -2767,6 +2778,7 @@ static void F(A<object?> z, A<object> w)
{
(new[] { z, z! })[0].F.ToString();
(new[] { z!, z })[0].F.ToString();
(new[] { z!, z! })[0].F.ToString();
(new[] { w, w! })[0].F.ToString();
(new[] { w!, w })[0].F.ToString();
}
......@@ -2776,14 +2788,23 @@ static void F(A<object?> z, A<object> w)
// (11,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x, x! })[0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x, x! })[0]").WithLocation(11, 9),
// (18,9): warning CS8602: Possible dereference of a null reference.
// (12,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x!, x })[0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x!, x })[0]").WithLocation(12, 9),
// (19,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z, z! })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, z! })[0].F").WithLocation(18, 9));
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, z! })[0].F").WithLocation(19, 9),
// (20,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, z })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z })[0].F").WithLocation(20, 9),
// (21,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, z! })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z! })[0].F").WithLocation(21, 9)
);
}
// PROTOTYPE(NullableReferenceTypes): Update this method to use types from unannotated assemblies
// rather than `x!`, particularly because `x!` should result in IsNullable=false rather than IsNullable=null.
// PROTOTYPE(NullableReferenceTypes): Should report the same warnings (or no warnings) for (x, x!) and (x!, x).
// rather than `x!`, particularly because `x!` results in IsNullable=false rather than IsNullable=null.
[Fact]
public void IdentityConversion_TypeInference_IsNullableNull()
{
......@@ -2821,9 +2842,15 @@ static void G(A<object?> z, A<object> w)
// (12,9): warning CS8602: Possible dereference of a null reference.
// F1(x, x!).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F1(x, x!)").WithLocation(12, 9),
// (13,9): warning CS8602: Possible dereference of a null reference.
// F1(x!, x).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F1(x!, x)").WithLocation(13, 9),
// (23,9): warning CS8602: Possible dereference of a null reference.
// F2(z, z!).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F2(z, z!)").WithLocation(23, 9));
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F2(z, z!)").WithLocation(23, 9),
// (24,9): warning CS8602: Possible dereference of a null reference.
// F2(z!, z).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F2(z!, z)").WithLocation(24, 9));
}
[Fact]
......@@ -3518,12 +3545,18 @@ static void F3(B<object>? x3)
// (8,14): warning CS8619: Nullability of reference types in value of type 'B<object>' doesn't match target type 'A<object?>'.
// y1 = x1;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("B<object>", "A<object?>").WithLocation(8, 14),
// (9,14): warning CS8619: Nullability of reference types in value of type 'B<object>' doesn't match target type 'A<object?>'.
// y1 = x1!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1!").WithArguments("B<object>", "A<object?>").WithLocation(9, 14),
// (13,24): warning CS8619: Nullability of reference types in value of type 'B<object?>' doesn't match target type 'A<object>'.
// A<object> y2 = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("B<object?>", "A<object>").WithLocation(13, 24),
// (14,14): warning CS8619: Nullability of reference types in value of type 'B<object?>' doesn't match target type 'A<object>'.
// y2 = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("B<object?>", "A<object>").WithLocation(14, 14),
// (15,14): warning CS8619: Nullability of reference types in value of type 'B<object?>' doesn't match target type 'A<object>'.
// y2 = x2!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2!").WithArguments("B<object?>", "A<object>").WithLocation(15, 14),
// (19,25): warning CS8600: Converting null literal or possible null value to non-nullable type.
// A<object?> y3 = x3;
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x3").WithLocation(19, 25),
......@@ -3535,7 +3568,11 @@ static void F3(B<object>? x3)
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x3").WithLocation(20, 14),
// (20,14): warning CS8619: Nullability of reference types in value of type 'B<object>' doesn't match target type 'A<object?>'.
// y3 = x3;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("B<object>", "A<object?>").WithLocation(20, 14));
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("B<object>", "A<object?>").WithLocation(20, 14),
// (21,14): warning CS8619: Nullability of reference types in value of type 'B<object>' doesn't match target type 'A<object?>'.
// y3 = x3!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3!").WithArguments("B<object>", "A<object?>").WithLocation(21, 14)
);
}
[Fact]
......@@ -3573,12 +3610,18 @@ static void F3(IB<object>? x3)
// (8,14): warning CS8619: Nullability of reference types in value of type 'IB<object>' doesn't match target type 'IA<object?>'.
// y1 = x1;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("IB<object>", "IA<object?>").WithLocation(8, 14),
// (9,14): warning CS8619: Nullability of reference types in value of type 'IB<object>' doesn't match target type 'IA<object?>'.
// y1 = x1!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1!").WithArguments("IB<object>", "IA<object?>").WithLocation(9, 14),
// (13,25): warning CS8619: Nullability of reference types in value of type 'IB<object?>' doesn't match target type 'IA<object>'.
// IA<object> y2 = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("IB<object?>", "IA<object>").WithLocation(13, 25),
// (14,14): warning CS8619: Nullability of reference types in value of type 'IB<object?>' doesn't match target type 'IA<object>'.
// y2 = x2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("IB<object?>", "IA<object>").WithLocation(14, 14),
// (15,14): warning CS8619: Nullability of reference types in value of type 'IB<object?>' doesn't match target type 'IA<object>'.
// y2 = x2!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2!").WithArguments("IB<object?>", "IA<object>").WithLocation(15, 14),
// (19,26): warning CS8600: Converting null literal or possible null value to non-nullable type.
// IA<object?> y3 = x3;
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x3").WithLocation(19, 26),
......@@ -3590,7 +3633,10 @@ static void F3(IB<object>? x3)
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x3").WithLocation(20, 14),
// (20,14): warning CS8619: Nullability of reference types in value of type 'IB<object>' doesn't match target type 'IA<object?>'.
// y3 = x3;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IB<object>", "IA<object?>").WithLocation(20, 14));
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IB<object>", "IA<object?>").WithLocation(20, 14),
// (21,14): warning CS8619: Nullability of reference types in value of type 'IB<object>' doesn't match target type 'IA<object?>'.
// y3 = x3!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3!").WithArguments("IB<object>", "IA<object?>").WithLocation(21, 14));
}
[Fact]
......
......@@ -595,13 +595,17 @@ public void LocalVar_FlowAnalysis_08()
static void F(string? s)
{
var t = s!;
t.ToString();
t/*T:string!*/.ToString();
t = null;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (7,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
// t = null;
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(7, 13));
comp.VerifyTypes();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册