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

Learn from binary operators on non-null constant values #33929

Merged
merged 3 commits into from
Mar 8, 2019

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Mar 7, 2019

Two changes in this PR:

  • a comparison (except !=) to a non-null constant is a non-null test
  • a comparison with null (x == null, x != null, (Type)x == null, ...) is a pure null test and therefore affects both branches

Related issues:

@jcouv jcouv added this to the 16.1.P1 milestone Mar 7, 2019
@jcouv jcouv self-assigned this Mar 7, 2019
@jcouv jcouv force-pushed the learn-comparisons branch 3 times, most recently from 3a11af2 to b748e6b Compare March 7, 2019 15:45
@jcouv jcouv marked this pull request as ready for review March 7, 2019 17:12
@jcouv jcouv requested a review from a team as a code owner March 7, 2019 17:12
@jcouv
Copy link
Member Author

jcouv commented Mar 7, 2019

@dotnet/roslyn-compiler FYI, I just rebased to resolve conflicts. This PR is ready for review. Thanks #Resolved

operandComparedToNonNull = SkipReferenceConversions(operandComparedToNonNull);
splitAndLearnFromNonNullTest(operandComparedToNonNull, caseToLearn: true);
return;
default:
Copy link
Member

@gafter gafter Mar 8, 2019

Choose a reason for hiding this comment

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

We should learn from a != test as well. In if (o != 1) we know o is not null in the else branch. #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

Please either make a change or file an issue (your choice)


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

}

static BoundExpression skipImplicitNullableConversions(BoundExpression possiblyConversion)
{
Copy link
Member

@gafter gafter Mar 8, 2019

Choose a reason for hiding this comment

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

while (possiblyConversion.Kind == BoundKind.Conversion && possiblyConversion is BoundConversion { ConversionKind: ConversionKind.ImplicitNullable, Operand: var operand })
{
possiblyConversion = operand;
}
return possiblyConversion;
#Resolved

Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

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

:shipit:

gafter added a commit to gafter/roslyn that referenced this pull request Mar 8, 2019
operandComparedToNonNull = binary.Left;
}

if (operandComparedToNonNull != null)
Copy link
Member

Choose a reason for hiding this comment

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

What happens in the case if (null == null)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nothing will happen because there is no slot to update for either null.
There is however a scenario that is a bit weird:

const string? nullable = null;
const string? nonNullable = "";
if (nullable == nonNullable)

We could say that we don't update constants, or maybe we need to distinguish null from other null-valued constants...

Copy link
Member

@jaredpar jaredpar left a comment

Choose a reason for hiding this comment

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

:shipit:

return possiblyConversion;
}

// If caseToLearn is true, we'll learn in the when-true branch, otherwise in the when-false branch.
Copy link
Member

@cston cston Mar 8, 2019

Choose a reason for hiding this comment

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

caseToLearn [](start = 18, length = 11)

Perhaps name whenTrue. #Resolved


// learn from non-null constant
BoundExpression operandComparedToNonNull = null;
if (skipImplicitNullableConversions(binary.Left).ConstantValue?.IsNull == false)
Copy link
Member

@cston cston Mar 8, 2019

Choose a reason for hiding this comment

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

skipImplicitNullableConversions(binary.Left).ConstantValue?.IsNull == false [](start = 16, length = 75)

Consider extracting an isNullConstant() local function. #Resolved

@@ -63105,25 +63424,16 @@ class Program
static void F1(object[]? x1, object[]? y1)
{
foreach (var x in x1) { } // 1
}
static void F2(object[]? x1, object[]? y1)
{
foreach (var x in x1) { }
}
static void F3(object[]? x1, object[]? y1)
Copy link
Member

@cston cston Mar 8, 2019

Choose a reason for hiding this comment

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

F3 [](start = 16, length = 2)

Consider renumbering these methods. #Resolved

@jcouv jcouv merged commit 6e9bb3f into dotnet:master Mar 8, 2019
@jcouv jcouv deleted the learn-comparisons branch March 8, 2019 18:18
gafter pushed a commit to gafter/roslyn that referenced this pull request Mar 13, 2019
* Track inferred state changes in a finally block
Fixes dotnet#33446

* Add a test so we don't regress when merging with dotnet#33929

* Add some comments and tests

* Use `LearnFromNullTest` in recently integrated code in `NullableWalker`

* Remove Unused Parameter
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