Skip to content

feat: update type signature during add argument action #3321

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

Merged
merged 5 commits into from
Nov 14, 2022

Conversation

santiweight
Copy link
Collaborator

@santiweight santiweight commented Nov 6, 2022

@michaelpj @pepeiborra This one resolves a lot of the issues you had with the previous MR

It's also hopefully much clearer now, since I spent some time cleaning up also...

Some notes:

  • A future MR will split the logic into a separate file (I am delaying due to merge conflicts that I want to avoid)
  • There is still one uncompleted feature that is noted in documentation (we do not use GHC's suggested type when updating the type signature)

@santiweight santiweight requested a review from wz1000 November 6, 2022 23:41
@santiweight
Copy link
Collaborator Author

One point of annoyance I had during implementation: you can't run golden tests without setting -j1. Running golden tests multi-threaded would have bizarre behavior around the current working directory and creating golden files in odd places.

It took me a while to realize... is there a way to fix runSessionWithServer' so that future contributors are not burned by this?

Copy link
Collaborator

@michaelpj michaelpj left a comment

Choose a reason for hiding this comment

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

Somewhat superficial review, but looks generally good! Not sure about the tests.

a ->
TransformT m a
TransformT m (a, Maybe r)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does this do now? Should the Haddock change to explain the new behaviour?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Revised

pure $ MG xMg (L locMatches matches') originMg
modifyMgMatchesT mg f = fst <$> modifyMgMatchesT' mg (fmap (, ()) . f) () ((.) pure . const)

-- | Modify the each LMatch in a MatchGroup
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- | Modify the each LMatch in a MatchGroup
-- | Modify each LMatch in a MatchGroup

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Revised

@@ -972,31 +982,97 @@ suggestAddArgument parsedModule Diagnostic {_message, _range}
where
message = unifySpaces _message

-- TODO use typ to modify type signature
-- Given a name for the new binding, add a new pattern to the match in the last position,
-- returning how many patterns are in this match:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- returning how many patterns are in this match:
-- returning how many patterns there were in this match before the modification:

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should it be before or after?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Before. Revised

in (L locMatch (Match xMatch ctxMatch (pats <> [newPat]) rhs), length pats)

-- Attempt to insert a binding pattern into each match for the given LHsDecl. Also return the declaration's name, and
-- the number of bound patterns in the declaration's matches, if the HsDecl is a fun bind
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- the number of bound patterns in the declaration's matches, if the HsDecl is a fun bind
-- the number of bound patterns in the declaration's matches before the transformation, if the HsDecl is a fun bind

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Revised

appendFinalPatToMatches :: T.Text -> LHsDecl GhcPs -> TransformT (Either ResponseError) (LHsDecl GhcPs, Maybe (GenLocated SrcSpanAnnN RdrName, Int))
appendFinalPatToMatches name = \case
(L locDecl (ValD xVal (FunBind xFunBind idFunBind mg coreFunBind))) -> do
(mg', numPatsMay) <- modifyMgMatchesT' mg (pure . second Just . addArgToMatch name) Nothing combineMatchNumPats
Copy link
Collaborator

Choose a reason for hiding this comment

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

This all feels a bit roundabout. You've taught two functions to pass up the number of matches, and then changed modifyMgMatches to pass a result thorough... but it seems like you could just look for the number of matches independently of the modification, either before or afterwards. Sure, you have to write another function, but I imagine funBindArgCount is quite straightforward code and simplifies all the rest.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The unfortunate thing is that we don't know which declaration is going to be altered.

Note that we use modifySmallestDeclWithM with this function in addArgumentAction.

An alternative would be to do two calls to modifySmallestDeclWithM (perhaps a variant called viewSmallestDeclWithM that just returns some information on the matching decl). The first would do the modification, the second would extract the information (and then the two maybes would be <|> together).

I don't personally find that clearer... While I do agree that this code is a little odd, I think it's part and parcel of these sorts of transformations :/

I'm happy to switch it up if you still think it'd be clearer.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Okay, so you do quite a bit of finding this decl. You have to go in and find it here to modify it, then you have to go in again to find the matching signature?

Continuing possibly dumb questions: could we not do something like:

do
   decl <- findSmallestDecl
   sig <- findSigFor decl
   -- return the modified version in case we want to look at them
   decl' <- modifyDecl decl
   sig' <- modifySig sig

Anyway, I won't nitpick more: I'm happy to go with what you think makes sense as a structure here. It just feels like we've got some pieces of work that are currently entangled and I wonder if they could be disentangled.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah I see your thought. We certainly could do something like this.

However, this not generally how I've seen other AST refactors done with ghc-exactprint. Normally I see modifications done in a lens style Lens ast Decl, and I think it makes some sense to continue to do so.

The API you suggest is actually something I've been considering myself for a while, but the exactprint API is far from stable enough to have such niceties (there would probably be a fair amount of CPP involved in the near future...).

@michaelpj
Copy link
Collaborator

What happens if you run this on a local def in a let or where? does it work? Can we have some tests to show whatever happens? And what happens if there's an intervening local def like the lambda case?

@santiweight
Copy link
Collaborator Author

@michaelpj

There were already tests for where bindings in the tests that existed before support for updating type signatures. However, I've added golden tests because the old tests were crap (I will be refactoring them in a follow up).

This plugin currently only looks for top-level bindings.

foo = bar
  where bar = new_def
-- Hover over new_def...

-- current behavior (only for top levels): 
+ add as argument

-- future behavior:
+ add as argument to foo
+ add as argument to bar

@santiweight santiweight merged commit 68d353f into haskell:master Nov 14, 2022
@santiweight santiweight deleted the add-arg-type-sig branch November 15, 2022 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants