-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Track nullability across reference and nullable conversions of tuple elements #34303
Conversation
nit: Please mark your PRs with Compilers label at a minimum, so it shows up in the "to review" query Jared had shared. Thanks |
@dotnet/roslyn-compiler please review. |
Related to #32599 |
@@ -1521,6 +1454,8 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre | |||
} | |||
} | |||
} | |||
|
|||
this.State[slot] = resultState; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.State[slot] = resultState; [](start = 20, length = 31)
Should this be pushed two lines lower even (outside the if ((object)type != null)
)?
Never mind, we would not have a slot #Closed
@@ -1769,6 +1704,7 @@ private ArrayTypeSymbol VisitArrayInitializer(BoundArrayCreation node) | |||
} | |||
} | |||
|
|||
conversions.Free(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
conversions.Free(); [](start = 12, length = 19)
Thanks #Closed
@@ -3942,8 +3932,10 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi | |||
ParameterSymbol target = null, | |||
bool reportTopLevelWarnings = true, | |||
bool reportRemainingWarnings = true, | |||
bool extensionMethodThisArgument = false) | |||
bool extensionMethodThisArgument = false, | |||
bool trackNullability = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trackNullability [](start = 17, length = 16)
nit: consider trackState
instead (here and elsewhere). Otherwise, please add an xml doc comment.
A comment is probably good anyways, as this flag seems to just be an optimization (don't assign some slots in return
or other scenarios where we don't care about creating slots) #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -2190,7 +2126,7 @@ public override BoundNode VisitNullCoalescingAssignmentOperator(BoundNullCoalesc | |||
var leftState = this.State.Clone(); | |||
LearnFromNonNullTest(leftOperand, ref leftState); | |||
LearnFromNullTest(leftOperand, ref this.State); | |||
TypeWithState rightResult = VisitOptionalImplicitConversion(rightOperand, targetType, UseLegacyWarnings(leftOperand), AssignmentKind.Assignment); | |||
TypeWithState rightResult = VisitOptionalImplicitConversion(rightOperand, targetType, useLegacyWarnings: UseLegacyWarnings(leftOperand), trackNullability: false, AssignmentKind.Assignment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trackNullability: false, [](start = 149, length = 24)
I'm unsure whether this should be be trackNullability: true
(I assume we'd remove the call to TrackNullableStateForAssignment
on the next line)
From our discussion, we'll probably move in this direction, but for now ApplyConversion only invokes Track methods when it needs to create new slots (ie. for Nullable and tuples). #Closed
trackConvertedValue(targetElements[i], conversions[i], valueElements[i]); | ||
} | ||
|
||
void trackConvertedValue(FieldSymbol targetField, Conversion conversion, FieldSymbol valueField) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trackConvertedValue [](start = 17, length = 19)
How does this function relate to ApplyConversion(..., trackNullability: true)
? Could we just leverage ApplyConversion
? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function should probably be merged with ApplyConversion
. I'm attempting to do that with the next PR.
In reply to: 267979386 [](ancestors = 267979386)
@@ -893,7 +827,7 @@ private void ReportNullabilityMismatchInAssignment(SyntaxNode syntaxNode, object | |||
// https://github.com/dotnet/roslyn/issues/31395: We should copy all tracked state from `value` regardless of | |||
// BoundNode type but we'll need to handle cycles (see NullableReferenceTypesTests.Members_FieldCycle_07). | |||
// For now, we copy a limited set of BoundNode types that shouldn't contain cycles. | |||
if (((targetType.Type.IsReferenceType || targetType.TypeKind == TypeKind.TypeParameter) && (isSupportedReferenceTypeValue(value) || targetType.Type.IsAnonymousType)) || | |||
if (((targetType.Type.IsReferenceType || targetType.TypeKind == TypeKind.TypeParameter) && (valueOpt is null || isSupportedReferenceTypeValue(valueOpt) || targetType.Type.IsAnonymousType)) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
((targetType.Type.IsReferenceType || targetType.TypeKind == TypeKind.TypeParameter) && (valueOpt is null || isSupportedReferenceTypeValue(valueOpt) || targetType.Type.IsAnonymousType)) || [](start = 24, length = 187)
This is getting gnarly, but I don't see a good way to simplify :-( #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks (iteration 1)
@@ -518,6 +518,11 @@ protected override int MakeSlot(BoundExpression node) | |||
} | |||
case BoundKind.Conversion: | |||
{ | |||
int slot = getPlaceholderSlot(node); | |||
if (slot > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be >= 0
? (I'm not sure if it's possible to observe) #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The slot is never 0
. This matches other tests in this class that are either > 0
or < 0
.
In reply to: 267981582 [](ancestors = 267981582)
@dotnet/roslyn-compiler for a second review, thanks. |
@dotnet/roslyn-compiler please review. |
} | ||
}"; | ||
var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); | ||
// https://github.com/dotnet/roslyn/issues/32599: Track state across tuple element conversions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// #32599: Track state across tuple element conversions. [](start = 8, length = 99)
Comment could be removed? #Pending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should report warnings marked above. I have a fix for this case in the next PR.
In reply to: 268849176 [](ancestors = 268849176)
}"; | ||
var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); | ||
// https://github.com/dotnet/roslyn/issues/32599: Track state across tuple element conversions. | ||
comp.VerifyDiagnostics(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} [](start = 8, length = 1)
not related to this PR: it may be good to add a test showing the user-defined conversions on tuples are ignored for analysis (we don't expect users to define their own ValueTuple types) #Pending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm including tests for user-defined conversions between tuples and custom types in the next PR.
In reply to: 268850928 [](ancestors = 268850928)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks (iteration 4)
Debug.Assert(valueSlot > 0); | ||
|
||
var valueTuple = operandType as TupleTypeSymbol; | ||
if (valueTuple is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using pattern matching if (operandType is TupleTypeSymbol valueTuple)
#Pending
@@ -4164,6 +4171,19 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi | |||
break; | |||
|
|||
case ConversionKind.ImplicitNullable: | |||
if (trackMembers && node.Kind == BoundKind.Conversion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using an is
check instead of the kind and conversion. #Pending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case ConversionKind.ExplicitTupleLiteral: | ||
case ConversionKind.ExplicitTuple: | ||
if (trackMembers && node.Kind == BoundKind.Conversion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment. #Pending
@@ -4164,6 +4171,19 @@ private bool HasTopLevelNullabilityConversion(TypeWithAnnotations source, TypeWi | |||
break; | |||
|
|||
case ConversionKind.ImplicitNullable: | |||
if (trackMembers && node.Kind == BoundKind.Conversion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this whole check be broken out into a local function? Seems to be duplicated here and for tuple conversions. #Pending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check will be simplified in the next PR and removed later.
In reply to: 269237714 [](ancestors = 269237714)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (commit 4). Couple of minor refactoring suggestions that can be addressed as a followup.
Moves tracking of nullability across conversions into
ApplyConversion
and adds support for reference and nullable conversions of tuple elements.There are a couple of cases that will be handled next (nested tuple conversions, and conversion groups where the top-most conversion is not the interesting conversion), but those are likely to involve more significant changes.