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

Share pattern-matching temps when they are the same type. #19378

Merged
merged 6 commits into from
May 11, 2017

Conversation

gafter
Copy link
Member

@gafter gafter commented May 9, 2017

Customer scenario

Use edit-and-continue in a method that contains a pattern-switch statement. It doesn't work today, but we'd like to enable it. This work is a first step in making that happen.

Bugs this fixes:

Fixes #19280

Workarounds, if any

None.

Risk

Quite low. We simply reuse temporary variables when they are used in non-overlapping ranges.

Performance impact

No compiler perf change expected. Slight improvement to code quality.

Is this a regression from a previous update?

N/A

Root cause analysis:

N/A

How was the bug found?

N/A

@dotnet/roslyn-compiler @tmat Please review this compiler fix. It is a prerequisite to E&C work we hope to get into 15.3.

@gafter gafter added 4 - In Review A fix for the issue is submitted for review. Area-Compilers Interactive-EnC Feature - Pattern Matching Pattern Matching labels May 9, 2017
@gafter gafter added this to the 15.3 milestone May 9, 2017
@gafter gafter self-assigned this May 9, 2017
@gafter gafter requested review from tmat, agocke and AlekseyTs May 9, 2017 23:31
LocalSymbol temp;
if (!localByType.TryGetValue(type, out temp))
{
temp = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax);
Copy link
Member

Choose a reason for hiding this comment

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

_enclosingSymbol as MethodSymbol [](start = 44, length = 32)

Can this be null? If not use explicit cast.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, the parameter is "optional" in the constructor.

While it would be possible to change this to a cast now, that would be an error when we introduce a match expression, because in that case the enclosing symbol could be a field (for a field initializer). I'd rather leave this as is so it is future-proof.

@tmat
Copy link
Member

tmat commented May 9, 2017

:shipit:

@@ -101,6 +101,7 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel
/// the decision tree.
/// </summary>
private ImmutableArray<BoundPatternSwitchSection> BindPatternSwitchSections(
SyntaxNode syntax,
Copy link
Contributor

@AlekseyTs AlekseyTs May 10, 2017

Choose a reason for hiding this comment

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

SyntaxNode syntax [](start = 12, length = 17)

It looks like there is only one call-site. Consider making this a SwitchStatementSyntax and removing the two next parameters (boundSwitchExpression is coming from a property, sections are available from SwitchStatementSyntax). #Closed

Copy link
Member Author

@gafter gafter May 10, 2017

Choose a reason for hiding this comment

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

Yes; even this syntax parameter is unneeded (it is available in the property SwitchSyntax).

@@ -26,17 +26,63 @@ internal abstract class DecisionTreeBuilder
protected readonly Symbol _enclosingSymbol;
protected readonly Conversions _conversions;
protected HashSet<DiagnosticInfo> _useSiteDiagnostics = new HashSet<DiagnosticInfo>();
private Dictionary<TypeSymbol, LocalSymbol> localByType = new Dictionary<TypeSymbol, LocalSymbol>();
Copy link
Contributor

Choose a reason for hiding this comment

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

new Dictionary<TypeSymbol, LocalSymbol>(); [](start = 66, length = 42)

Should this dictionary be sensitive to dynamic/object, tuple names and custom modifier differences?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it definitely should not.

Copy link
Contributor

Choose a reason for hiding this comment

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

No, it definitely should not.

Please add a test targeting this scenario.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added TestIgnoreDynamicVsObjectAndTupleElementNames_03.

Copy link
Member Author

Choose a reason for hiding this comment

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

My "No" above should be "Yes".

@@ -59,15 +59,9 @@ private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node)
var expression = _localRewriter.VisitExpression(node.Expression);
var result = ArrayBuilder<BoundStatement>.GetInstance();

// if the expression is "too complex", we copy it to a temp.
Copy link
Contributor

Choose a reason for hiding this comment

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

// if the expression is "too complex", we copy it to a temp. [](start = 16, length = 60)

Could you please explain why this is no longer needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Lowering starts by lowering to a decision tree, which starts by calling CreateEmptyDecisionTree, which contains code equivalent to this deleted code. The existing generated code always contained two temps instead of one.

        /// <summary>
        /// Create a fresh decision tree for the given input expression of the given type.
        /// </summary>
        protected DecisionTree CreateEmptyDecisionTree(BoundExpression expression)
        {
            var type = expression.Type;

            LocalSymbol temp = null;
            if (expression.ConstantValue == null)
            {
                // Unless it is a constant, the decision tree acts on a copy of the input expression.
                // We create a temp to represent that copy. Lowering will assign into this temp.
                temp = PatternMatchingTemp(type);
                expression = new BoundLocal(expression.Syntax, temp, null, type);
            }

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation.

@AlekseyTs
Copy link
Contributor

Done with review pass.

@gafter
Copy link
Member Author

gafter commented May 10, 2017

@AlekseyTs The PR has been modified to respond to your comments.

@@ -115,11 +113,11 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel

// Bind match sections
var boundPatternSwitchSectionsBuilder = ArrayBuilder<BoundPatternSwitchSection>.GetInstance();
SubsumptionDiagnosticBuilder subsumption = new SubsumptionDiagnosticBuilder(ContainingMemberOrLambda, this.Conversions, boundSwitchExpression);
foreach (var sectionSyntax in sections)
SubsumptionDiagnosticBuilder subsumption = new SubsumptionDiagnosticBuilder(base.ContainingMemberOrLambda, SwitchSyntax, this.Conversions, SwitchGoverningExpression);
Copy link
Contributor

Choose a reason for hiding this comment

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

base. [](start = 88, length = 5)

Does the base. make a difference?

Copy link
Member Author

Choose a reason for hiding this comment

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

No.

}

[Fact, WorkItem(19280, "https://github.com/dotnet/roslyn/issues/19280")]
public void TestIgnoreDynamicVsObjectAndTupleElementNames_03()
Copy link
Contributor

Choose a reason for hiding this comment

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

TestIgnoreDynamicVsObjectAndTupleElementNames_03 [](start = 20, length = 48)

I am confused, the name of the test says "Ignore", but it looks like the differences aren't ignored.

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'll rename it TestSignificanceOfDynamicVersusObjectAndTupleNamesInUniquenessOfPatternMatchingTemps

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM

@gafter
Copy link
Member Author

gafter commented May 10, 2017

@dotnet/roslyn-compiler May I please have a second review from the compiler team?

Copy link
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

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

LGTM

@gafter
Copy link
Member Author

gafter commented May 11, 2017

/CC @MeiChin-Tsai for ask mode approval, please

@MeiChin-Tsai
Copy link

Approved. thx.

@gafter gafter merged commit 841044b into dotnet:master May 11, 2017
@gafter gafter added Resolution-Fixed The bug has been fixed and/or the requested behavior has been implemented and removed 4 - In Review A fix for the issue is submitted for review. labels May 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers cla-already-signed Feature - Pattern Matching Pattern Matching Interactive-EnC Resolution-Fixed The bug has been fixed and/or the requested behavior has been implemented
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Share long-lived pattern matching temps of the same type used in switch
6 participants