Skip to content
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

Merged
merged 4 commits into from
Mar 26, 2019

Conversation

cston
Copy link
Member

@cston cston commented Mar 20, 2019

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.

@cston cston requested a review from a team as a code owner March 20, 2019 22:18
@jcouv jcouv modified the milestones: 16.2, 16.1.P1 Mar 20, 2019
@jcouv
Copy link
Member

jcouv commented Mar 20, 2019

nit: Please mark your PRs with Compilers label at a minimum, so it shows up in the "to review" query Jared had shared. Thanks

@cston
Copy link
Member Author

cston commented Mar 21, 2019

@dotnet/roslyn-compiler please review.

@RikkiGibson
Copy link
Contributor

Related to #32599

@@ -1521,6 +1454,8 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
}
}
}

this.State[slot] = resultState;
Copy link
Member

@jcouv jcouv Mar 21, 2019

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();
Copy link
Member

@jcouv jcouv Mar 21, 2019

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)
Copy link
Member

@jcouv jcouv Mar 21, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to trackMembers and added comment.


In reply to: 267962369 [](ancestors = 267962369)

@@ -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);
Copy link
Member

@jcouv jcouv Mar 21, 2019

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)
Copy link
Member

@jcouv jcouv Mar 21, 2019

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

Copy link
Member Author

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)) ||
Copy link
Member

@jcouv jcouv Mar 21, 2019

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

Copy link
Member

@jcouv jcouv left a 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)
Copy link
Member

@jcouv jcouv Mar 21, 2019

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

Copy link
Member Author

@cston cston Mar 21, 2019

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)

@cston
Copy link
Member Author

cston commented Mar 22, 2019

@dotnet/roslyn-compiler for a second review, thanks.

@cston
Copy link
Member Author

cston commented Mar 25, 2019

@dotnet/roslyn-compiler please review.

}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
// https://github.com/dotnet/roslyn/issues/32599: Track state across tuple element conversions.
Copy link
Member

@jcouv jcouv Mar 25, 2019

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

Copy link
Member Author

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();
}
Copy link
Member

@jcouv jcouv Mar 25, 2019

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

Copy link
Member Author

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)

Copy link
Member

@jcouv jcouv left a 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)
Copy link
Member

@333fred 333fred Mar 26, 2019

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)
Copy link
Member

@333fred 333fred Mar 26, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks should be removed soon.


In reply to: 269237234 [](ancestors = 269237234)

case ConversionKind.ExplicitTupleLiteral:
case ConversionKind.ExplicitTuple:
if (trackMembers && node.Kind == BoundKind.Conversion)
Copy link
Member

@333fred 333fred Mar 26, 2019

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)
Copy link
Member

@333fred 333fred Mar 26, 2019

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

Copy link
Member Author

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)

Copy link
Member

@333fred 333fred left a 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.

@cston cston merged commit 7aac2e3 into dotnet:master Mar 26, 2019
@cston cston deleted the 32599 branch March 26, 2019 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants