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

Assert MaybeNull is not used for value types other than Nullable<T> (#34630)

上级 ed576ba3
...@@ -841,7 +841,7 @@ private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol inputType, ...@@ -841,7 +841,7 @@ private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol inputType,
} }
case SyntaxKind.SingleVariableDesignation: case SyntaxKind.SingleVariableDesignation:
{ {
var declType = new TypeWithState(inputType, NullableFlowState.MaybeNull).ToTypeWithAnnotations(); var declType = TypeWithState.ForType(inputType).ToTypeWithAnnotations();
BindPatternDesignation( BindPatternDesignation(
designation: node, declType: declType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors, designation: node, declType: declType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors,
variableSymbol: out Symbol variableSymbol, variableAccess: out BoundExpression variableAccess); variableSymbol: out Symbol variableSymbol, variableAccess: out BoundExpression variableAccess);
......
...@@ -141,7 +141,7 @@ public VisitArgumentResult(VisitResult visitResult, Optional<LocalState> stateFo ...@@ -141,7 +141,7 @@ public VisitArgumentResult(VisitResult visitResult, Optional<LocalState> stateFo
/// Invalid type, used only to catch Visit methods that do not set /// Invalid type, used only to catch Visit methods that do not set
/// _result.Type. See VisitExpressionWithoutStackGuard. /// _result.Type. See VisitExpressionWithoutStackGuard.
/// </summary> /// </summary>
private static readonly TypeWithState _invalidType = new TypeWithState(ErrorTypeSymbol.UnknownResultType, NullableFlowState.NotNull); private static readonly TypeWithState _invalidType = TypeWithState.Create(ErrorTypeSymbol.UnknownResultType, NullableFlowState.NotNull);
/// <summary> /// <summary>
/// The result and l-value type of the last visited expression. /// The result and l-value type of the last visited expression.
...@@ -1409,7 +1409,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre ...@@ -1409,7 +1409,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
VisitObjectCreationInitializer(null, slot, initializerOpt); VisitObjectCreationInitializer(null, slot, initializerOpt);
} }
ResultType = new TypeWithState(type, resultState); ResultType = TypeWithState.Create(type, resultState);
} }
private void VisitObjectCreationInitializer(Symbol containingSymbol, int containingSlot, BoundExpression node) private void VisitObjectCreationInitializer(Symbol containingSymbol, int containingSlot, BoundExpression node)
...@@ -1502,7 +1502,7 @@ private new void VisitCollectionElementInitializer(BoundCollectionElementInitial ...@@ -1502,7 +1502,7 @@ private new void VisitCollectionElementInitializer(BoundCollectionElementInitial
private void SetNotNullResult(BoundExpression node) private void SetNotNullResult(BoundExpression node)
{ {
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
} }
private int GetOrCreatePlaceholderSlot(BoundExpression node) private int GetOrCreatePlaceholderSlot(BoundExpression node)
...@@ -1552,7 +1552,7 @@ public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousO ...@@ -1552,7 +1552,7 @@ public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousO
} }
} }
ResultType = new TypeWithState(anonymousType, NullableFlowState.NotNull); ResultType = TypeWithState.Create(anonymousType, NullableFlowState.NotNull);
return null; return null;
} }
...@@ -1563,7 +1563,7 @@ public override BoundNode VisitArrayCreation(BoundArrayCreation node) ...@@ -1563,7 +1563,7 @@ public override BoundNode VisitArrayCreation(BoundArrayCreation node)
VisitRvalue(expr); VisitRvalue(expr);
} }
TypeSymbol resultType = (node.InitializerOpt == null) ? node.Type : VisitArrayInitializer(node); TypeSymbol resultType = (node.InitializerOpt == null) ? node.Type : VisitArrayInitializer(node);
ResultType = new TypeWithState(resultType, NullableFlowState.NotNull); ResultType = TypeWithState.Create(resultType, NullableFlowState.NotNull);
return null; return null;
} }
...@@ -1797,12 +1797,12 @@ private TypeWithState InferResultNullability(BinaryOperatorKind operatorKind, Me ...@@ -1797,12 +1797,12 @@ private TypeWithState InferResultNullability(BinaryOperatorKind operatorKind, Me
} }
} }
if (operatorKind.IsLifted()) if (operatorKind.IsLifted() && !operatorKind.IsComparison())
{ {
resultState = leftType.State.Join(rightType.State); resultState = leftType.State.Join(rightType.State);
} }
return new TypeWithState(resultType, resultState); return TypeWithState.Create(resultType, resultState);
} }
protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary) protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
...@@ -2104,7 +2104,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato ...@@ -2104,7 +2104,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
rightResult = VisitRvalueWithState(rightOperand); rightResult = VisitRvalueWithState(rightOperand);
// Should be able to use rightResult for the result of the operator but // Should be able to use rightResult for the result of the operator but
// binding may have generated a different result type in the case of errors. // binding may have generated a different result type in the case of errors.
ResultType = new TypeWithState(node.Type, rightResult.State); ResultType = TypeWithState.Create(node.Type, rightResult.State);
return null; return null;
} }
...@@ -2202,7 +2202,7 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr) ...@@ -2202,7 +2202,7 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr)
private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResult, TypeSymbol resultType) private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResult, TypeSymbol resultType)
{ {
NullableFlowState resultState = rightResult.State; NullableFlowState resultState = rightResult.State;
return new TypeWithState(resultType, resultState); return TypeWithState.Create(resultType, resultState);
} }
public override BoundNode VisitConditionalAccess(BoundConditionalAccess node) public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
...@@ -2230,6 +2230,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node) ...@@ -2230,6 +2230,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
var accessExpressionType = VisitRvalueWithState(node.AccessExpression); var accessExpressionType = VisitRvalueWithState(node.AccessExpression);
Join(ref this.State, ref receiverState); Join(ref this.State, ref receiverState);
// Per LDM 2019-02-13 decision, the result of a conditional access might be null even if // Per LDM 2019-02-13 decision, the result of a conditional access might be null even if
// both the receiver and right-hand-side are believed not to be null. // both the receiver and right-hand-side are believed not to be null.
NullableFlowState resultState = NullableFlowState.MaybeNull; NullableFlowState resultState = NullableFlowState.MaybeNull;
...@@ -2247,7 +2248,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node) ...@@ -2247,7 +2248,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
_currentConditionalReceiverVisitResult = default; _currentConditionalReceiverVisitResult = default;
_lastConditionalAccessSlot = previousConditionalAccessSlot; _lastConditionalAccessSlot = previousConditionalAccessSlot;
ResultType = new TypeWithState(type, resultState); ResultType = TypeWithState.Create(type, resultState);
return null; return null;
} }
...@@ -2284,7 +2285,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node ...@@ -2284,7 +2285,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
var lValueAnnotation = consequenceLValue.NullableAnnotation.EnsureCompatible(alternativeLValue.NullableAnnotation); var lValueAnnotation = consequenceLValue.NullableAnnotation.EnsureCompatible(alternativeLValue.NullableAnnotation);
var rValueState = consequenceRValue.State.Join(alternativeRValue.State); var rValueState = consequenceRValue.State.Join(alternativeRValue.State);
SetResult(new TypeWithState(refResultType, rValueState), TypeWithAnnotations.Create(refResultType, lValueAnnotation)); SetResult(TypeWithState.Create(refResultType, rValueState), TypeWithAnnotations.Create(refResultType, lValueAnnotation));
return null; return null;
} }
...@@ -2379,7 +2380,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node ...@@ -2379,7 +2380,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
resultState = convertedConsequenceResult.State.Join(convertedAlternativeResult.State); resultState = convertedConsequenceResult.State.Join(convertedAlternativeResult.State);
} }
ResultType = new TypeWithState(resultType, resultState); ResultType = TypeWithState.Create(resultType, resultState);
return null; return null;
(BoundExpression, Conversion, TypeWithState) visitConditionalOperand(LocalState state, BoundExpression operand) (BoundExpression, Conversion, TypeWithState) visitConditionalOperand(LocalState state, BoundExpression operand)
...@@ -2444,7 +2445,7 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node ...@@ -2444,7 +2445,7 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node
{ {
rvalueType = rvalueType.GetNullableUnderlyingType(); rvalueType = rvalueType.GetNullableUnderlyingType();
} }
ResultType = new TypeWithState(rvalueType, NullableFlowState.NotNull); ResultType = TypeWithState.Create(rvalueType, NullableFlowState.NotNull);
return null; return null;
} }
...@@ -3373,7 +3374,7 @@ private TypeWithState GetAdjustedResult(TypeWithState type, int slot) ...@@ -3373,7 +3374,7 @@ private TypeWithState GetAdjustedResult(TypeWithState type, int slot)
if (slot > 0 && slot < this.State.Capacity) if (slot > 0 && slot < this.State.Capacity)
{ {
NullableFlowState state = this.State[slot]; NullableFlowState state = this.State[slot];
return new TypeWithState(type.Type, state); return TypeWithState.Create(type.Type, state);
} }
return type; return type;
...@@ -3608,7 +3609,7 @@ private void VisitTupleExpression(BoundTupleExpression node) ...@@ -3608,7 +3609,7 @@ private void VisitTupleExpression(BoundTupleExpression node)
tupleOpt = tupleOpt.WithElementTypes(elementTypesWithAnnotations); tupleOpt = tupleOpt.WithElementTypes(elementTypesWithAnnotations);
var locations = tupleOpt.TupleElements.SelectAsArray((element, location) => element.Locations.FirstOrDefault() ?? location, node.Syntax.Location); var locations = tupleOpt.TupleElements.SelectAsArray((element, location) => element.Locations.FirstOrDefault() ?? location, node.Syntax.Location);
tupleOpt.CheckConstraints(_conversions, includeNullability: true, node.Syntax, locations, compilation, diagnosticsOpt: null, nullabilityDiagnosticsOpt: Diagnostics); tupleOpt.CheckConstraints(_conversions, includeNullability: true, node.Syntax, locations, compilation, diagnosticsOpt: null, nullabilityDiagnosticsOpt: Diagnostics);
ResultType = new TypeWithState(tupleOpt, NullableFlowState.NotNull); ResultType = TypeWithState.Create(tupleOpt, NullableFlowState.NotNull);
} }
} }
...@@ -3939,7 +3940,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi ...@@ -3939,7 +3940,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
ReportNullabilityMismatchWithTargetDelegate(node.Syntax, delegateType, unboundLambda); ReportNullabilityMismatchWithTargetDelegate(node.Syntax, delegateType, unboundLambda);
} }
return new TypeWithState(targetType, NullableFlowState.NotNull); return TypeWithState.Create(targetType, NullableFlowState.NotNull);
} }
break; break;
...@@ -3962,6 +3963,9 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi ...@@ -3962,6 +3963,9 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
break; break;
case ConversionKind.NoConversion: case ConversionKind.NoConversion:
resultState = operandType.State;
break;
case ConversionKind.DefaultOrNullLiteral: case ConversionKind.DefaultOrNullLiteral:
checkConversion = false; checkConversion = false;
goto case ConversionKind.Identity; goto case ConversionKind.Identity;
...@@ -4117,7 +4121,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi ...@@ -4117,7 +4121,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
resultState = NullableFlowState.MaybeNull; resultState = NullableFlowState.MaybeNull;
} }
var resultType = new TypeWithState(targetType, resultState); var resultType = TypeWithState.Create(targetType, resultState);
if (operandType.Type?.IsErrorType() != true && !targetType.IsErrorType()) if (operandType.Type?.IsErrorType() != true && !targetType.IsErrorType())
{ {
...@@ -4175,7 +4179,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi ...@@ -4175,7 +4179,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
// cf. Binder.CreateUserDefinedConversion // cf. Binder.CreateUserDefinedConversion
if (!conversion.IsValid) if (!conversion.IsValid)
{ {
return new TypeWithState(targetType, NullableFlowState.NotNull); return TypeWithState.Create(targetType, NullableFlowState.NotNull);
} }
// operand -> conversion "from" type // operand -> conversion "from" type
...@@ -4254,7 +4258,7 @@ private TypeWithState LiftedReturnType(TypeWithAnnotations returnType, NullableF ...@@ -4254,7 +4258,7 @@ private TypeWithState LiftedReturnType(TypeWithAnnotations returnType, NullableF
? compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(returnType)) ? compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(returnType))
: returnType.Type; : returnType.Type;
NullableFlowState state = returnType.ToTypeWithState().State.Join(operandState); NullableFlowState state = returnType.ToTypeWithState().State.Join(operandState);
return new TypeWithState(type, state); return TypeWithState.Create(type, state);
} }
private TypeWithState ClassifyAndApplyConversion( private TypeWithState ClassifyAndApplyConversion(
...@@ -4374,7 +4378,7 @@ public override BoundNode VisitThisReference(BoundThisReference node) ...@@ -4374,7 +4378,7 @@ public override BoundNode VisitThisReference(BoundThisReference node)
private void VisitThisOrBaseReference(BoundExpression node) private void VisitThisOrBaseReference(BoundExpression node)
{ {
var rvalueResult = new TypeWithState(node.Type, NullableFlowState.NotNull); var rvalueResult = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
var lvalueResult = TypeWithAnnotations.Create(node.Type, NullableAnnotation.NotAnnotated); var lvalueResult = TypeWithAnnotations.Create(node.Type, NullableAnnotation.NotAnnotated);
SetResult(rvalueResult, lvalueResult); SetResult(rvalueResult, lvalueResult);
} }
...@@ -4418,7 +4422,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) ...@@ -4418,7 +4422,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
} }
TrackNullableStateForAssignment(right, leftLValueType, MakeSlot(left), rightType, MakeSlot(right)); TrackNullableStateForAssignment(right, leftLValueType, MakeSlot(left), rightType, MakeSlot(right));
SetResult(new TypeWithState(leftLValueType.Type, rightType.State), leftLValueType); SetResult(TypeWithState.Create(leftLValueType.Type, rightType.State), leftLValueType);
} }
return null; return null;
...@@ -4578,7 +4582,7 @@ private void VisitDeconstructionArguments(ArrayBuilder<DeconstructionVariable> v ...@@ -4578,7 +4582,7 @@ private void VisitDeconstructionArguments(ArrayBuilder<DeconstructionVariable> v
valueSlot = MakeSlot(rightPart); valueSlot = MakeSlot(rightPart);
if (valueSlot > 0) if (valueSlot > 0)
{ {
var valueBeforeNullableWrapping = new TypeWithState(underlyingType.Type, NullableFlowState.NotNull); var valueBeforeNullableWrapping = TypeWithState.Create(underlyingType.Type, NullableFlowState.NotNull);
TrackNullableStateOfNullableValue(targetSlot, targetType.Type, rightPart, valueBeforeNullableWrapping, valueSlot); TrackNullableStateOfNullableValue(targetSlot, targetType.Type, rightPart, valueBeforeNullableWrapping, valueSlot);
} }
} }
...@@ -4823,7 +4827,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen ...@@ -4823,7 +4827,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen
} }
else else
{ {
resultType = new TypeWithState(node.Type, NullableFlowState.NotNull); resultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
} }
TrackNullableStateForAssignment(node, leftLValueType, MakeSlot(node.Left), resultType); TrackNullableStateForAssignment(node, leftLValueType, MakeSlot(node.Left), resultType);
...@@ -4968,7 +4972,7 @@ private void VisitMemberAccess(BoundExpression node, BoundExpression receiverOpt ...@@ -4968,7 +4972,7 @@ private void VisitMemberAccess(BoundExpression node, BoundExpression receiverOpt
if (slot > 0 && slot < this.State.Capacity) if (slot > 0 && slot < this.State.Capacity)
{ {
var state = this.State[slot]; var state = this.State[slot];
resultType = new TypeWithState(resultType.Type, state); resultType = TypeWithState.Create(resultType.Type, state);
} }
} }
...@@ -5147,7 +5151,7 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) ...@@ -5147,7 +5151,7 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
} }
else else
{ {
resultType = new TypeWithState(node.Type, node.OperatorKind.IsLifted() ? argumentResult.State : NullableFlowState.NotNull); resultType = TypeWithState.Create(node.Type, node.OperatorKind.IsLifted() ? argumentResult.State : NullableFlowState.NotNull);
} }
ResultType = resultType; ResultType = resultType;
...@@ -5198,7 +5202,7 @@ private TypeWithState InferResultNullability(BoundUserDefinedConditionalLogicalO ...@@ -5198,7 +5202,7 @@ private TypeWithState InferResultNullability(BoundUserDefinedConditionalLogicalO
{ {
// https://github.com/dotnet/roslyn/issues/33879 Conversions: Lifted operator // https://github.com/dotnet/roslyn/issues/33879 Conversions: Lifted operator
// Should this use the updated flow type and state? How should it compute nullability? // Should this use the updated flow type and state? How should it compute nullability?
return new TypeWithState(node.Type, NullableFlowState.NotNull); return TypeWithState.Create(node.Type, NullableFlowState.NotNull);
} }
// Update method based on inferred operand types: see https://github.com/dotnet/roslyn/issues/29605. // Update method based on inferred operand types: see https://github.com/dotnet/roslyn/issues/29605.
...@@ -5302,7 +5306,7 @@ public override BoundNode VisitAwaitExpression(BoundAwaitExpression node) ...@@ -5302,7 +5306,7 @@ public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
public override BoundNode VisitTypeOfOperator(BoundTypeOfOperator node) public override BoundNode VisitTypeOfOperator(BoundTypeOfOperator node)
{ {
var result = base.VisitTypeOfOperator(node); var result = base.VisitTypeOfOperator(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result; return result;
} }
...@@ -5402,7 +5406,7 @@ public override BoundNode VisitAsOperator(BoundAsOperator node) ...@@ -5402,7 +5406,7 @@ public override BoundNode VisitAsOperator(BoundAsOperator node)
} }
} }
ResultType = new TypeWithState(type, resultState); ResultType = TypeWithState.Create(type, resultState);
return null; return null;
} }
...@@ -5434,7 +5438,7 @@ public override BoundNode VisitLiteral(BoundLiteral node) ...@@ -5434,7 +5438,7 @@ public override BoundNode VisitLiteral(BoundLiteral node)
var result = base.VisitLiteral(node); var result = base.VisitLiteral(node);
Debug.Assert(!IsConditionalState); Debug.Assert(!IsConditionalState);
ResultType = new TypeWithState(node.Type, node.Type?.CanContainNull() != false && node.ConstantValue?.IsNull == true ? NullableFlowState.MaybeNull : NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, node.Type?.CanContainNull() != false && node.ConstantValue?.IsNull == true ? NullableFlowState.MaybeNull : NullableFlowState.NotNull);
return result; return result;
} }
...@@ -5570,7 +5574,7 @@ public override BoundNode VisitAnonymousPropertyDeclaration(BoundAnonymousProper ...@@ -5570,7 +5574,7 @@ public override BoundNode VisitAnonymousPropertyDeclaration(BoundAnonymousProper
public override BoundNode VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node) public override BoundNode VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node)
{ {
var result = base.VisitNoPiaObjectCreationExpression(node); var result = base.VisitNoPiaObjectCreationExpression(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result; return result;
} }
...@@ -5679,7 +5683,7 @@ public override BoundNode VisitQueryClause(BoundQueryClause node) ...@@ -5679,7 +5683,7 @@ public override BoundNode VisitQueryClause(BoundQueryClause node)
public override BoundNode VisitNameOfOperator(BoundNameOfOperator node) public override BoundNode VisitNameOfOperator(BoundNameOfOperator node)
{ {
var result = base.VisitNameOfOperator(node); var result = base.VisitNameOfOperator(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result; return result;
} }
...@@ -5693,7 +5697,7 @@ public override BoundNode VisitNamespaceExpression(BoundNamespaceExpression node ...@@ -5693,7 +5697,7 @@ public override BoundNode VisitNamespaceExpression(BoundNamespaceExpression node
public override BoundNode VisitInterpolatedString(BoundInterpolatedString node) public override BoundNode VisitInterpolatedString(BoundInterpolatedString node)
{ {
var result = base.VisitInterpolatedString(node); var result = base.VisitInterpolatedString(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull); ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result; return result;
} }
...@@ -5714,7 +5718,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack ...@@ -5714,7 +5718,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack
public override BoundNode VisitDiscardExpression(BoundDiscardExpression node) public override BoundNode VisitDiscardExpression(BoundDiscardExpression node)
{ {
var result = TypeWithAnnotations.Create(node.Type); var result = TypeWithAnnotations.Create(node.Type);
var rValueType = new TypeWithState(node.Type, NullableFlowState.MaybeNull); var rValueType = TypeWithState.ForType(node.Type);
SetResult(rValueType, result); SetResult(rValueType, result);
return null; return null;
} }
......
...@@ -211,7 +211,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement ...@@ -211,7 +211,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement
break; break;
} }
State[outputSlot] = NullableFlowState.NotNull; State[outputSlot] = NullableFlowState.NotNull;
var outputType = new TypeWithState(e.Type, inputState); var outputType = TypeWithState.Create(e.Type, inputState);
addToTempMap(output, outputSlot, outputType.Type); addToTempMap(output, outputSlot, outputType.Type);
break; break;
} }
...@@ -323,7 +323,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement ...@@ -323,7 +323,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement
var tempState = this.State[tempSlot]; var tempState = this.State[tempSlot];
if (variableAccess is BoundLocal { LocalSymbol: SourceLocalSymbol { IsVar: true } local }) if (variableAccess is BoundLocal { LocalSymbol: SourceLocalSymbol { IsVar: true } local })
{ {
var inferredType = new TypeWithState(tempType, tempState).ToTypeWithAnnotations(); var inferredType = TypeWithState.Create(tempType, tempState).ToTypeWithAnnotations();
if (_variableTypes.TryGetValue(local, out var existingType)) if (_variableTypes.TryGetValue(local, out var existingType))
{ {
// merge inferred nullable annotation from different branches of the decision tree // merge inferred nullable annotation from different branches of the decision tree
......
...@@ -711,7 +711,7 @@ internal TypeWithState ToTypeWithState() ...@@ -711,7 +711,7 @@ internal TypeWithState ToTypeWithState()
// Reading from a variable of a type parameter (that could be substituted with a nullable type), but which // Reading from a variable of a type parameter (that could be substituted with a nullable type), but which
// cannot itself be annotated (because it isn't known to be a reference type), may yield a null value // cannot itself be annotated (because it isn't known to be a reference type), may yield a null value
// even though the type parameter isn't annotated. // even though the type parameter isn't annotated.
return new TypeWithState( return TypeWithState.Create(
Type, Type,
IsPossiblyNullableTypeTypeParameter() || NullableAnnotation.IsAnnotated() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull); IsPossiblyNullableTypeTypeParameter() || NullableAnnotation.IsAnnotated() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull);
} }
......
...@@ -15,12 +15,39 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols ...@@ -15,12 +15,39 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
public bool HasNullType => Type is null; public bool HasNullType => Type is null;
public bool MayBeNull => State == NullableFlowState.MaybeNull; public bool MayBeNull => State == NullableFlowState.MaybeNull;
public bool IsNotNull => State == NullableFlowState.NotNull; public bool IsNotNull => State == NullableFlowState.NotNull;
public static TypeWithState ForType(TypeSymbol type) => new TypeWithState(type, type?.CanContainNull() == true ? NullableFlowState.MaybeNull : NullableFlowState.NotNull);
public TypeWithState(TypeSymbol type, NullableFlowState state) => (Type, State) = (type, state); private static bool CanContainNull(TypeSymbol type)
{
return type is null || !type.IsValueType || type.IsNullableTypeOrTypeParameter();
}
public static TypeWithState ForType(TypeSymbol type)
{
var state = CanContainNull(type) ? NullableFlowState.MaybeNull : NullableFlowState.NotNull;
return new TypeWithState(type, state);
}
public static TypeWithState Create(TypeSymbol type, NullableFlowState defaultState)
{
var state = defaultState == NullableFlowState.MaybeNull && CanContainNull(type) ? NullableFlowState.MaybeNull : NullableFlowState.NotNull;
return new TypeWithState(type, state);
}
private TypeWithState(TypeSymbol type, NullableFlowState state)
{
Debug.Assert(state == NullableFlowState.NotNull || CanContainNull(type));
Type = type;
State = state;
}
public void Deconstruct(out TypeSymbol type, out NullableFlowState state) => (type, state) = (Type, State); public void Deconstruct(out TypeSymbol type, out NullableFlowState state) => (type, state) = (Type, State);
public string GetDebuggerDisplay() => $"{{Type:{Type?.GetDebuggerDisplay()}, State:{State}{"}"}"; public string GetDebuggerDisplay() => $"{{Type:{Type?.GetDebuggerDisplay()}, State:{State}{"}"}";
public override string ToString() => GetDebuggerDisplay(); public override string ToString() => GetDebuggerDisplay();
public TypeWithState WithNotNullState() => new TypeWithState(Type, NullableFlowState.NotNull); public TypeWithState WithNotNullState() => new TypeWithState(Type, NullableFlowState.NotNull);
public TypeWithAnnotations ToTypeWithAnnotations() public TypeWithAnnotations ToTypeWithAnnotations()
{ {
NullableAnnotation annotation = this.State.IsNotNull() || Type?.CanContainNull() == false || Type?.IsTypeParameterDisallowingAnnotation() == true NullableAnnotation annotation = this.State.IsNotNull() || Type?.CanContainNull() == false || Type?.IsTypeParameterDisallowingAnnotation() == true
......
...@@ -79998,7 +79998,7 @@ static void F3(int? ni) ...@@ -79998,7 +79998,7 @@ static void F3(int? ni)
} }
else else
{ {
_ = (S)ni; // 1 _ = (S)ni; // 3
} }
} }
}"; }";
...@@ -80011,7 +80011,7 @@ static void F3(int? ni) ...@@ -80011,7 +80011,7 @@ static void F3(int? ni)
// _ = s4.Value; // 2 // _ = s4.Value; // 2
Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s4").WithLocation(33, 17), Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s4").WithLocation(33, 17),
// (45,20): warning CS8629: Nullable value type may be null. // (45,20): warning CS8629: Nullable value type may be null.
// _ = (S)ni; // 1 // _ = (S)ni; // 3
Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "ni").WithLocation(45, 20) Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "ni").WithLocation(45, 20)
); );
} }
...@@ -81721,9 +81721,8 @@ internal override void F<U>(int? t) ...@@ -81721,9 +81721,8 @@ internal override void F<U>(int? t)
// o.ToString(); // 1 // o.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(11, 9), Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(11, 9),
// (21,9): warning CS8602: Dereference of a possibly null reference. // (21,9): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // o.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(21, 9) Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(21, 9));
);
} }
[Fact] [Fact]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册