未验证 提交 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,
}
case SyntaxKind.SingleVariableDesignation:
{
var declType = new TypeWithState(inputType, NullableFlowState.MaybeNull).ToTypeWithAnnotations();
var declType = TypeWithState.ForType(inputType).ToTypeWithAnnotations();
BindPatternDesignation(
designation: node, declType: declType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors,
variableSymbol: out Symbol variableSymbol, variableAccess: out BoundExpression variableAccess);
......
......@@ -141,7 +141,7 @@ public VisitArgumentResult(VisitResult visitResult, Optional<LocalState> stateFo
/// Invalid type, used only to catch Visit methods that do not set
/// _result.Type. See VisitExpressionWithoutStackGuard.
/// </summary>
private static readonly TypeWithState _invalidType = new TypeWithState(ErrorTypeSymbol.UnknownResultType, NullableFlowState.NotNull);
private static readonly TypeWithState _invalidType = TypeWithState.Create(ErrorTypeSymbol.UnknownResultType, NullableFlowState.NotNull);
/// <summary>
/// The result and l-value type of the last visited expression.
......@@ -1409,7 +1409,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
VisitObjectCreationInitializer(null, slot, initializerOpt);
}
ResultType = new TypeWithState(type, resultState);
ResultType = TypeWithState.Create(type, resultState);
}
private void VisitObjectCreationInitializer(Symbol containingSymbol, int containingSlot, BoundExpression node)
......@@ -1502,7 +1502,7 @@ private new void VisitCollectionElementInitializer(BoundCollectionElementInitial
private void SetNotNullResult(BoundExpression node)
{
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
}
private int GetOrCreatePlaceholderSlot(BoundExpression node)
......@@ -1552,7 +1552,7 @@ public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousO
}
}
ResultType = new TypeWithState(anonymousType, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(anonymousType, NullableFlowState.NotNull);
return null;
}
......@@ -1563,7 +1563,7 @@ public override BoundNode VisitArrayCreation(BoundArrayCreation node)
VisitRvalue(expr);
}
TypeSymbol resultType = (node.InitializerOpt == null) ? node.Type : VisitArrayInitializer(node);
ResultType = new TypeWithState(resultType, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(resultType, NullableFlowState.NotNull);
return null;
}
......@@ -1797,12 +1797,12 @@ private TypeWithState InferResultNullability(BinaryOperatorKind operatorKind, Me
}
}
if (operatorKind.IsLifted())
if (operatorKind.IsLifted() && !operatorKind.IsComparison())
{
resultState = leftType.State.Join(rightType.State);
}
return new TypeWithState(resultType, resultState);
return TypeWithState.Create(resultType, resultState);
}
protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
......@@ -2104,7 +2104,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
rightResult = VisitRvalueWithState(rightOperand);
// 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.
ResultType = new TypeWithState(node.Type, rightResult.State);
ResultType = TypeWithState.Create(node.Type, rightResult.State);
return null;
}
......@@ -2202,7 +2202,7 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr)
private static TypeWithState GetNullCoalescingResultType(TypeWithState rightResult, TypeSymbol resultType)
{
NullableFlowState resultState = rightResult.State;
return new TypeWithState(resultType, resultState);
return TypeWithState.Create(resultType, resultState);
}
public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
......@@ -2230,6 +2230,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
var accessExpressionType = VisitRvalueWithState(node.AccessExpression);
Join(ref this.State, ref receiverState);
// 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.
NullableFlowState resultState = NullableFlowState.MaybeNull;
......@@ -2247,7 +2248,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
_currentConditionalReceiverVisitResult = default;
_lastConditionalAccessSlot = previousConditionalAccessSlot;
ResultType = new TypeWithState(type, resultState);
ResultType = TypeWithState.Create(type, resultState);
return null;
}
......@@ -2284,7 +2285,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
var lValueAnnotation = consequenceLValue.NullableAnnotation.EnsureCompatible(alternativeLValue.NullableAnnotation);
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;
}
......@@ -2379,7 +2380,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
resultState = convertedConsequenceResult.State.Join(convertedAlternativeResult.State);
}
ResultType = new TypeWithState(resultType, resultState);
ResultType = TypeWithState.Create(resultType, resultState);
return null;
(BoundExpression, Conversion, TypeWithState) visitConditionalOperand(LocalState state, BoundExpression operand)
......@@ -2444,7 +2445,7 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node
{
rvalueType = rvalueType.GetNullableUnderlyingType();
}
ResultType = new TypeWithState(rvalueType, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(rvalueType, NullableFlowState.NotNull);
return null;
}
......@@ -3373,7 +3374,7 @@ private TypeWithState GetAdjustedResult(TypeWithState type, int slot)
if (slot > 0 && slot < this.State.Capacity)
{
NullableFlowState state = this.State[slot];
return new TypeWithState(type.Type, state);
return TypeWithState.Create(type.Type, state);
}
return type;
......@@ -3608,7 +3609,7 @@ private void VisitTupleExpression(BoundTupleExpression node)
tupleOpt = tupleOpt.WithElementTypes(elementTypesWithAnnotations);
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);
ResultType = new TypeWithState(tupleOpt, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(tupleOpt, NullableFlowState.NotNull);
}
}
......@@ -3939,7 +3940,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
ReportNullabilityMismatchWithTargetDelegate(node.Syntax, delegateType, unboundLambda);
}
return new TypeWithState(targetType, NullableFlowState.NotNull);
return TypeWithState.Create(targetType, NullableFlowState.NotNull);
}
break;
......@@ -3962,6 +3963,9 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
break;
case ConversionKind.NoConversion:
resultState = operandType.State;
break;
case ConversionKind.DefaultOrNullLiteral:
checkConversion = false;
goto case ConversionKind.Identity;
......@@ -4117,7 +4121,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
resultState = NullableFlowState.MaybeNull;
}
var resultType = new TypeWithState(targetType, resultState);
var resultType = TypeWithState.Create(targetType, resultState);
if (operandType.Type?.IsErrorType() != true && !targetType.IsErrorType())
{
......@@ -4175,7 +4179,7 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi
// cf. Binder.CreateUserDefinedConversion
if (!conversion.IsValid)
{
return new TypeWithState(targetType, NullableFlowState.NotNull);
return TypeWithState.Create(targetType, NullableFlowState.NotNull);
}
// operand -> conversion "from" type
......@@ -4254,7 +4258,7 @@ private TypeWithState LiftedReturnType(TypeWithAnnotations returnType, NullableF
? compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(returnType))
: returnType.Type;
NullableFlowState state = returnType.ToTypeWithState().State.Join(operandState);
return new TypeWithState(type, state);
return TypeWithState.Create(type, state);
}
private TypeWithState ClassifyAndApplyConversion(
......@@ -4374,7 +4378,7 @@ public override BoundNode VisitThisReference(BoundThisReference 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);
SetResult(rvalueResult, lvalueResult);
}
......@@ -4418,7 +4422,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
}
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;
......@@ -4578,7 +4582,7 @@ private void VisitDeconstructionArguments(ArrayBuilder<DeconstructionVariable> v
valueSlot = MakeSlot(rightPart);
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);
}
}
......@@ -4823,7 +4827,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen
}
else
{
resultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
resultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
}
TrackNullableStateForAssignment(node, leftLValueType, MakeSlot(node.Left), resultType);
......@@ -4968,7 +4972,7 @@ private void VisitMemberAccess(BoundExpression node, BoundExpression receiverOpt
if (slot > 0 && slot < this.State.Capacity)
{
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)
}
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;
......@@ -5198,7 +5202,7 @@ private TypeWithState InferResultNullability(BoundUserDefinedConditionalLogicalO
{
// https://github.com/dotnet/roslyn/issues/33879 Conversions: Lifted operator
// 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.
......@@ -5302,7 +5306,7 @@ public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
public override BoundNode VisitTypeOfOperator(BoundTypeOfOperator node)
{
var result = base.VisitTypeOfOperator(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result;
}
......@@ -5402,7 +5406,7 @@ public override BoundNode VisitAsOperator(BoundAsOperator node)
}
}
ResultType = new TypeWithState(type, resultState);
ResultType = TypeWithState.Create(type, resultState);
return null;
}
......@@ -5434,7 +5438,7 @@ public override BoundNode VisitLiteral(BoundLiteral node)
var result = base.VisitLiteral(node);
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;
}
......@@ -5570,7 +5574,7 @@ public override BoundNode VisitAnonymousPropertyDeclaration(BoundAnonymousProper
public override BoundNode VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node)
{
var result = base.VisitNoPiaObjectCreationExpression(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result;
}
......@@ -5679,7 +5683,7 @@ public override BoundNode VisitQueryClause(BoundQueryClause node)
public override BoundNode VisitNameOfOperator(BoundNameOfOperator node)
{
var result = base.VisitNameOfOperator(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result;
}
......@@ -5693,7 +5697,7 @@ public override BoundNode VisitNamespaceExpression(BoundNamespaceExpression node
public override BoundNode VisitInterpolatedString(BoundInterpolatedString node)
{
var result = base.VisitInterpolatedString(node);
ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
ResultType = TypeWithState.Create(node.Type, NullableFlowState.NotNull);
return result;
}
......@@ -5714,7 +5718,7 @@ public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStack
public override BoundNode VisitDiscardExpression(BoundDiscardExpression node)
{
var result = TypeWithAnnotations.Create(node.Type);
var rValueType = new TypeWithState(node.Type, NullableFlowState.MaybeNull);
var rValueType = TypeWithState.ForType(node.Type);
SetResult(rValueType, result);
return null;
}
......
......@@ -211,7 +211,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement
break;
}
State[outputSlot] = NullableFlowState.NotNull;
var outputType = new TypeWithState(e.Type, inputState);
var outputType = TypeWithState.Create(e.Type, inputState);
addToTempMap(output, outputSlot, outputType.Type);
break;
}
......@@ -323,7 +323,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement
var tempState = this.State[tempSlot];
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))
{
// merge inferred nullable annotation from different branches of the decision tree
......
......@@ -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
// 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.
return new TypeWithState(
return TypeWithState.Create(
Type,
IsPossiblyNullableTypeTypeParameter() || NullableAnnotation.IsAnnotated() ? NullableFlowState.MaybeNull : NullableFlowState.NotNull);
}
......
......@@ -15,12 +15,39 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
public bool HasNullType => Type is null;
public bool MayBeNull => State == NullableFlowState.MaybeNull;
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 string GetDebuggerDisplay() => $"{{Type:{Type?.GetDebuggerDisplay()}, State:{State}{"}"}";
public override string ToString() => GetDebuggerDisplay();
public TypeWithState WithNotNullState() => new TypeWithState(Type, NullableFlowState.NotNull);
public TypeWithAnnotations ToTypeWithAnnotations()
{
NullableAnnotation annotation = this.State.IsNotNull() || Type?.CanContainNull() == false || Type?.IsTypeParameterDisallowingAnnotation() == true
......
......@@ -79998,7 +79998,7 @@ static void F3(int? ni)
}
else
{
_ = (S)ni; // 1
_ = (S)ni; // 3
}
}
}";
......@@ -80011,7 +80011,7 @@ static void F3(int? ni)
// _ = s4.Value; // 2
Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s4").WithLocation(33, 17),
// (45,20): warning CS8629: Nullable value type may be null.
// _ = (S)ni; // 1
// _ = (S)ni; // 3
Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "ni").WithLocation(45, 20)
);
}
......@@ -81721,9 +81721,8 @@ internal override void F<U>(int? t)
// o.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(11, 9),
// (21,9): warning CS8602: Dereference of a possibly null reference.
// o.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(21, 9)
);
// o.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(21, 9));
}
[Fact]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册