Skip to content

Introduce 'use recursive patterns' refactoring feature #53553

Merged
CyrusNajmabadi merged 24 commits intodotnet:mainfrom
alrz:use-recursive-pattern-refactoring
Jul 31, 2021
Merged

Introduce 'use recursive patterns' refactoring feature #53553
CyrusNajmabadi merged 24 commits intodotnet:mainfrom
alrz:use-recursive-pattern-refactoring

Conversation

@alrz
Copy link
Member

@alrz alrz commented May 20, 2021

No description provided.

@alrz alrz requested review from a team as code owners May 20, 2021 20:21
@ghost ghost added the Area-IDE label May 20, 2021
@CyrusNajmabadi
Copy link
Contributor

strongly love this. just need a story told through the code to explain what's going on plz. thanks!

@jinujoseph jinujoseph added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label May 20, 2021
@alrz alrz requested a review from CyrusNajmabadi May 21, 2021 20:01
@alrz
Copy link
Member Author

alrz commented May 21, 2021

@CyrusNajmabadi Ready for review.


context.RegisterRefactoring(
new MyCodeAction(
"Use recursive patterns",
Copy link
Member

Choose a reason for hiding this comment

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

Move to resx for localization?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup. I will get there eventually.

Copy link
Contributor

Choose a reason for hiding this comment

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

plzdo :)

@alrz alrz force-pushed the use-recursive-pattern-refactoring branch from 31a6411 to 09f9638 Compare May 27, 2021 18:16
@alrz
Copy link
Member Author

alrz commented May 27, 2021

@CyrusNajmabadi I think I've addressed all your feedback. PTAL.

@CyrusNajmabadi
Copy link
Contributor

On vacation now. Will do so next week!

@alrz
Copy link
Member Author

alrz commented May 29, 2021

A couple of things are intentionally left out for a follow-up:

  • Support || as the entry point
    • e.p == 1 || e.p == 2 => e is { p: 1 or 2 }
    • e is not C c || !c.p => e is not C { p: false }
  • Remove unused variables after applying the fix
    • case C v when v.p => case C { p: true }
  • Cover more pattern combinations before falling back to and
    • Should also include simplifying the resulting pattern

I think the last two should be done as a reducer to be applied for any simplification run.

@alrz
Copy link
Member Author

alrz commented Jun 3, 2021

tagging @CyrusNajmabadi for review.

};
}

if (TryGetCommonReceiver(leftReceiver, rightReceiver, model) is var (commonReceiverOpt, leftNames, rightNames))
Copy link
Contributor

Choose a reason for hiding this comment

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

so it feels odd that hhis says: TryGetCommonReceiver... but it can return a null common receiver (i.e. commonReceiverOpt), but this is still considered success. can you doc what's going on here?

{
var leftSubpattern = CreateSubpattern(leftNames, CreatePattern(leftReceiver, leftTarget, leftFlipped));
var rightSubpattern = CreateSubpattern(rightNames, CreatePattern(rightReceiver, rightTarget, rightFlipped));
// If the common receiver is null, it's an implicit `this` reference in source.
Copy link
Contributor

Choose a reason for hiding this comment

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

does some code validate that? i.e. that these are actually instance members, and not static members?

// For instance, `expr && a.b == 1 && a.c == 2` is converted to `expr && a is { b: 1, c: 2 }`
if (logicalAnd.Left is BinaryExpressionSyntax(LogicalAndExpression) leftExpression)
replacement = leftExpression.WithRight(replacement);
return replacement.ConvertToSingleLine().WithAdditionalAnnotations(Formatter.Annotation);
Copy link
Contributor

Choose a reason for hiding this comment

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

this drops trivia... which seems not good.

private static Func<SyntaxNode, SyntaxNode>? CombineWhenClauseCondition(PatternSyntax switchPattern, ExpressionSyntax condition, SemanticModel model)
{
if (TryDetermineReceiver(condition, model, inWhenClause: true) is not var (receiver, target, flipped) ||
TryFindVariableDesignation(switchPattern, receiver, model) is not var (containingPattern, namesOpt))
Copy link
Contributor

Choose a reason for hiding this comment

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

can you comment these if clauses to state what forms you're looking to match?

@CyrusNajmabadi
Copy link
Contributor

So my general feedback follows some thigns i've mentione din the past. Namely that the code ends up reading far too cryptically and too cutely. i feel like there's an overemphasis on trying to express thigns in the most compact pattern+tree-tranform form as possible. And i feel like that works because in your head you have a model of the exact tree forms and what you're extracting/combining/reforming. However, it makes the code feel far too dense and unclear as to waht's going on. I'd far prefer a simpler step-by-step recipe-like form where we state what we're looking for, and what we have extracted out, and what we are transforming into.

THis is esp. critical to me as it's very hard to otherwise know what's going on, which is important so that reviewer can gauge what might have been missed or what might need work.

@CyrusNajmabadi
Copy link
Contributor

@alrz what do you think your next steps will be here?

@alrz
Copy link
Member Author

alrz commented Jul 29, 2021

So my general feedback follows some thigns i've mentione din the past. Namely that the code ends up reading far too cryptically and too cutely. i feel like there's an overemphasis on trying to express thigns in the most compact pattern+tree-tranform form as possible. And i feel like that works because in your head you have a model of the exact tree forms and what you're extracting/combining/reforming. However, it makes the code feel far too dense and unclear as to waht's going on. I'd far prefer a simpler step-by-step recipe-like form where we state what we're looking for, and what we have extracted out, and what we are transforming into.

I'm not sure exactly what is the request here. I did actually write this in "step-by-step recipe-like form" with a few refactoring to reuse code whenever possible. I have no idea what could be cryptic about that.

@CyrusNajmabadi CyrusNajmabadi enabled auto-merge July 30, 2021 21:36
@CyrusNajmabadi
Copy link
Contributor

I have no idea what could be cryptic about that.

I think part of it is the returning of lambdas that then do the work later. so it's a bit unclear how to distinguish the matching portion from the transform portion. this is not a complaint. it's more an observation that this feels very different from how we generally have shipped refactorigns in the past.

I did actually write this in "step-by-step recipe-like form

Yes. but not always. For example, if i see:

            if (TryGetCommonReceiver(leftReceiver, rightReceiver, model) is var (commonReceiver, leftNames, rightNames))
            {
                return root =>
                {
                    var leftSubpattern = CreateSubpattern(leftNames, CreatePattern(leftReceiver, leftTarget, leftFlipped));
                    var rightSubpattern = CreateSubpattern(rightNames, CreatePattern(rightReceiver, rightTarget, rightFlipped));

It would be nice to have a general example of what's going on there.

--

That said, i think this is fine and i'm going to merge it in :) There were a couple of pieces of feedback not responded to. However, we can see based on if users run into issues with that if we need to do anything here.

Thanks much for the awesome contribution :)

@CyrusNajmabadi CyrusNajmabadi merged commit 32003cd into dotnet:main Jul 31, 2021
@ghost ghost added this to the Next milestone Jul 31, 2021
@alrz alrz deleted the use-recursive-pattern-refactoring branch July 31, 2021 06:20
@dibarbet dibarbet modified the milestones: Next, 17.0.P4 Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants