Don't read the same property twice in pattern matching #35669
Don't read the same property twice in pattern matching #35669gafter merged 6 commits intodotnet:masterfrom
Conversation
…through the same underlying object, but references of different types.
| @@ -9,7 +9,7 @@ partial class BoundDagEvaluation | |||
| public override bool Equals(object obj) => obj is BoundDagEvaluation other && this.Equals(other); | |||
| public virtual bool Equals(BoundDagEvaluation other) | |||
| { | |||
There was a problem hiding this comment.
Because we're overriding object.Equals, it's impossible to know statically everywhere this is called.
Instead I've set a breakpoint here, and on GetHashCode, and I've seen where it's been called from in the tests I added.
Namely:
DecisionDagBuilder.SimplifyTestsAndBindings(ArrayBuilder<BoundDagTest> testsBuilder, ArrayBuilder<BoundPatternBinding> bindingsBuilder)
usedValues
DecisionDagBuilder.RemoveEvaluation(RemainingTestsForCase c, BoundDagEvaluation e)
RemainingTests: c.RemainingTests.WhereAsArray(d => !(d is BoundDagEvaluation e2) || e2 != e),
NullableWalker.LearnFromDecisionDag()
tempMap
LocalRewriter.PatternLocalRewriter
_mapI was not able to understand what was happening in NullableWalker.LearnFromDecisionDag, so I've simply added tests to verify that my changes do not affect nullability analysis. I imagine @gafter would be able to help here.
In all other cases my changes to Equals seemed correct.
#Resolved
There was a problem hiding this comment.
Thanks to @jcouv for giving me an overview of how the nullable walker works. It seems to me that this behaviour is correct - since we assume property evaluations are non-mutating, the nullability state of any evaluations of the same property through different types should be the same, so it's ok to use the same slot for them. #Resolved
| /// So two evaluations act on the same input so long as they have the same original input. | ||
| /// </summary> | ||
| /// <returns></returns> | ||
| private BoundDagTemp GetOriginalInput() |
There was a problem hiding this comment.
Please remove the empty <returns> section. #Resolved
|
|
||
| public class Student : Person { | ||
| public override string Name { get => Name; } | ||
| } |
There was a problem hiding this comment.
This looks like infinite recursion. Did you mean base.Name? #Resolved
|
@agocke Could you look at this please? @YairHalberstadt You may have to pull the latest from the master branch to fix the build error in the CI tests. #Resolved |
|
This might cause another issue in It doesn't look like As an aside, I think that there is limited documentation of the Nullable Walker. @jcouv gave me a high level overview a couple of days ago. I would be happy to add that information to the Nullable Walker, and will also try and add any information @cston gives. @jcouv's overview was:
|
|
@YairHalberstadt, For instance, string s = null;
var list = new[] { s }.ToList();
list.Add(null);
|
|
@cston Could you please review this? I'd be happy to walk through it with you if it helps. #Resolved |
| @@ -9,7 +9,7 @@ partial class BoundDagEvaluation | |||
| public override bool Equals(object obj) => obj is BoundDagEvaluation other && this.Equals(other); | |||
| public virtual bool Equals(BoundDagEvaluation other) | |||
There was a problem hiding this comment.
Equals [](start = 28, length = 6)
Logged #36102 to consider renaming the Equals method to something more specific. (That shouldn't block this PR.) #Resolved
| [Fact, WorkItem(34933, "https://github.com/dotnet/roslyn/issues/34933")] | ||
| public void NoRedundantPropertyRead04() | ||
| { | ||
| // Cannot combine the evalations of name here, since we first check if p is Teacher, |
There was a problem hiding this comment.
evalations [](start = 34, length = 10)
Typo, here and other tests. #Resolved
| var source = @"using System; | ||
|
|
||
| public class Person { | ||
| public string Name { get; set; } |
There was a problem hiding this comment.
public string Name { get; set; } [](start = 4, length = 32)
Consider testing with abstract or virtual property with no override in derived type. #Resolved
|
@cston |
|
@YairHalberstadt Thank you for your contribution! |
when accessed through the same underlying object, but references of different types.
Fix to #34933
Namely:
will now only evaluate Person.Name once.
There are a number of limitations to this - the tests describe the details in comments.