未验证 提交 1754aa4e 编写于 作者: F Fred Silberberg 提交者: GitHub

Merge pull request #32225 from 333fred/null-coalese-assignment-support

Add support for ??= to NullableWalker
......@@ -1932,12 +1932,39 @@ private static BoundExpression SkipReferenceConversions(BoundExpression possibly
return possiblyConversion;
}
// https://github.com/dotnet/roslyn/issues/30140: Track nullable state from ??=.
public override BoundNode VisitNullCoalescingAssignmentOperator(BoundNullCoalescingAssignmentOperator node)
{
var result = base.VisitNullCoalescingAssignmentOperator(node);
SetResult(node);
return result;
BoundExpression leftOperand = node.LeftOperand;
BoundExpression rightOperand = node.RightOperand;
int leftSlot = MakeSlot(leftOperand);
// The assignment to the left below needs the declared type from VisitLvalue, but the hidden
// unnecessary check diagnostic needs the current adjusted type of the slot
VisitLvalue(leftOperand);
TypeSymbolWithAnnotations targetType = _resultType;
TypeSymbolWithAnnotations currentLeftType = GetAdjustedResult(targetType, leftSlot);
if (currentLeftType.ValueCanBeNull() == false)
{
ReportNonSafetyDiagnostic(ErrorCode.HDN_ExpressionIsProbablyNeverNull, leftOperand.Syntax);
}
var leftState = this.State.Clone();
TypeSymbolWithAnnotations rightResult = VisitOptionalImplicitConversion(rightOperand, targetType, UseLegacyWarnings(leftOperand), AssignmentKind.Assignment);
TrackNullableStateForAssignment(rightOperand, targetType, leftSlot, rightResult, MakeSlot(rightOperand));
Join(ref this.State, ref leftState);
TypeSymbolWithAnnotations resultType = GetNullCoalescingResultType(leftOperand, currentLeftType, rightOperand, rightResult, targetType.TypeSymbol);
_resultType = resultType;
if (leftSlot > 0)
{
this.State[leftSlot] = resultType.NullableAnnotation;
}
return null;
}
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
......@@ -2002,20 +2029,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
throw ExceptionUtilities.UnexpectedValue(node.OperatorResultKind);
}
NullableAnnotation resultNullableAnnotation;
// We want to check if the value can be nullable based on annotations and getValueNullableAnnotation might
// adjust the value that it returns to emphasize the fact. However, we want the original annotation to flow through the system.
if (getValueNullableAnnotation(leftOperand, leftResult).IsAnyNotNullable())
{
resultNullableAnnotation = getNullableAnnotation(leftOperand, leftResult);
}
else
{
resultNullableAnnotation = getNullableAnnotation(rightOperand, rightResult);
}
_resultType = TypeSymbolWithAnnotations.Create(resultType, resultNullableAnnotation);
_resultType = GetNullCoalescingResultType(leftOperand, leftResult, rightOperand, rightResult, resultType);
return null;
NullableAnnotation getNullableAnnotation(BoundExpression e, TypeSymbolWithAnnotations t)
......@@ -2028,16 +2042,6 @@ NullableAnnotation getNullableAnnotation(BoundExpression e, TypeSymbolWithAnnota
return t.NullableAnnotation;
}
NullableAnnotation getValueNullableAnnotation(BoundExpression e, TypeSymbolWithAnnotations t)
{
if (t.IsNull)
{
return GetNullableAnnotation(e);
}
return t.GetValueNullableAnnotation();
}
TypeSymbol getLeftResultType(TypeSymbol leftType, TypeSymbol rightType)
{
// If there was an identity conversion between the two operands (in short, if there
......@@ -2098,6 +2102,41 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr)
}
}
private static TypeSymbolWithAnnotations GetNullCoalescingResultType(BoundExpression leftOperand, TypeSymbolWithAnnotations leftResult, BoundExpression rightOperand, TypeSymbolWithAnnotations rightResult, TypeSymbol resultType)
{
NullableAnnotation resultNullableAnnotation;
if (getValueNullableAnnotation(leftOperand, leftResult).IsAnyNotNullable())
{
resultNullableAnnotation = getNullableAnnotation(leftOperand, leftResult);
}
else
{
resultNullableAnnotation = getNullableAnnotation(rightOperand, rightResult);
}
return TypeSymbolWithAnnotations.Create(resultType, resultNullableAnnotation);
NullableAnnotation getNullableAnnotation(BoundExpression e, TypeSymbolWithAnnotations t)
{
if (t.IsNull)
{
return GetNullableAnnotation(e);
}
return t.NullableAnnotation;
}
NullableAnnotation getValueNullableAnnotation(BoundExpression e, TypeSymbolWithAnnotations t)
{
if (t.IsNull)
{
return GetNullableAnnotation(e);
}
return t.GetValueNullableAnnotation();
}
}
public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
{
Debug.Assert(!IsConditionalState);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册