Skip to content

Commit

Permalink
Don't read the same property twice in pattern matching (#35669)
Browse files Browse the repository at this point in the history
Don't read the same property twice in pattern matching when accessed through the same underlying object, but references of different types.
Fixes #34933
  • Loading branch information
YairHalberstadt authored and Neal Gafter committed Jun 3, 2019
1 parent 075fcfc commit 59b717d
Show file tree
Hide file tree
Showing 3 changed files with 936 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
return other != (object)null && this.Kind == other.Kind && this.Input.Equals(other.Input) && this.Symbol == other.Symbol;
return other != (object)null && this.Kind == other.Kind && this.GetOriginalInput().Equals(other.GetOriginalInput()) && this.Symbol == other.Symbol;
}
private Symbol Symbol
{
Expand All @@ -28,8 +28,25 @@ private Symbol Symbol
}
public override int GetHashCode()
{
return Hash.Combine(this.Input.GetHashCode(), this.Symbol?.GetHashCode() ?? 0);
return Hash.Combine(GetOriginalInput().GetHashCode(), this.Symbol?.GetHashCode() ?? 0);
}

/// <summary>
/// Returns the original input for this evaluation, stripped of all Type Evaluations.
///
/// A BoundDagTypeEvaluation doesn't change the underlying object being pointed to
/// So two evaluations act on the same input so long as they have the same original input.
/// </summary>
private BoundDagTemp GetOriginalInput()
{
var input = this.Input;
while (input.Source is BoundDagTypeEvaluation source)
{
input = source.Input;
}
return input;
}

public static bool operator ==(BoundDagEvaluation left, BoundDagEvaluation right)
{
return (left is null) ? right is null : left.Equals(right);
Expand Down
9 changes: 9 additions & 0 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3673,6 +3673,15 @@ private TypeWithState GetAdjustedResult(TypeWithState type, int slot)
return type;
}

/// <summary>
/// Gets the corresponding member for a symbol from initial binding to match an updated receiver type in NullableWalker.
/// For instance, this will map from List&lt;string~&gt;.Add(string~) to List&lt;string?&gt;.Add(string?) in the following example:
/// <example>
/// string s = null;
/// var list = new[] { s }.ToList();
/// list.Add(null);
/// </example>
/// </summary>
private static Symbol AsMemberOfType(TypeSymbol type, Symbol symbol)
{
Debug.Assert((object)symbol != null);
Expand Down
Loading

0 comments on commit 59b717d

Please sign in to comment.