Skip to content
This repository has been archived by the owner on Jan 2, 2021. It is now read-only.

Fix code action for adding missing constraints to type signatures #839

Merged
merged 5 commits into from
Oct 4, 2020
Merged

Fix code action for adding missing constraints to type signatures #839

merged 5 commits into from
Oct 4, 2020

Conversation

jhrcek
Copy link
Contributor

@jhrcek jhrcek commented Sep 28, 2020

I'm trying to fix this issue, which is quite relevant for our codebase at work: we have many type signatures like this, for which the code action "Add CONSTRAINT to the context of the type signature for FUNCTION" doesn't work.

someFunction
    :: ( WithDb env m
       , WithError m
       , Has PieceOfConfig env
       )
    => Id User
    -> Id ProjectInfo
    -> m ProjectInfo
someFunction userId projectId = do
...

I added 2 failing tests illustrating both issues. The current implementation seems quite brittle (based on parsing stuff with regexes), I'm trying to figure out how to make it more robust..

@jhrcek jhrcek changed the title Add failing tests Fix code action for adding missing constraints to type signatures Sep 28, 2020
@alanz
Copy link
Collaborator

alanz commented Sep 28, 2020

I'm trying to figure out how to make it more robust..

Use the AST :)

@jhrcek
Copy link
Contributor Author

jhrcek commented Sep 28, 2020

Ok, I tried to use the AST and made the tests pass. It'll still need some work and I'll have to clean this up a lot.
I'll get back to this.

@jhrcek jhrcek marked this pull request as draft September 28, 2020 17:08
@jhrcek jhrcek marked this pull request as ready for review October 1, 2020 18:44
@jhrcek jhrcek requested a review from wz1000 October 2, 2020 11:14
test/exe/Main.hs Show resolved Hide resolved
Copy link
Collaborator

@pepeiborra pepeiborra left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution!
Apologies for the long delay in reviewing this, change looks fine to me with a minor change request.

src/Development/IDE/Plugin/CodeAction.hs Show resolved Hide resolved
]
srcSpanToRange $ case locatedType of
-- The type signature has explicit Context
L _ (HsQualTy _ (L contextSrcSpan _ ) _) -> contextSrcSpan
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not every type with a context is rooted in an HsQualTy constructor. Did you consider using splitLHsQualTy instead ?

Copy link
Contributor Author

@jhrcek jhrcek Oct 4, 2020

Choose a reason for hiding this comment

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

Good point, I wasn't aware a function like that existed.
I just tried it but it makes the test case where there's no initial context to start with fail.

Looking at how splitLHsQualTy is implemented it's clear why: It uses noLHsContext = noLoc [] in the case where I use SrcSpan of the start of the type signature. So in that respect my "manual" pattern match seems better.

On the other hand splitLHsQualTy has an additional case HsParTy which I have no idea what kind of syntax it represents. I'll try to find out and tweak my implementation based on that (Ideally adding a test case which triggers that case).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't find an example syntax which would trigger that HsParTy case, but I reimplemented my attempt like this, which made the tests pass

          srcSpanToRange $ case splitLHsQualTy locatedType of
            (L contextSrcSpan _ , _) ->
              if isGoodSrcSpan contextSrcSpan
                then contextSrcSpan -- The type signature has explicit context
                else -- No explicit context, return SrcSpan at the start of type sig where we can write context
                     let start = srcSpanStart $ getLoc locatedType in mkSrcSpan start start

BUT it seems to be noticably slower:

Screenshot from 2020-10-04 16-14-14

compared to my previous impl:

Screenshot from 2020-10-04 16-14-01

Which implementation would you suggest using?

Copy link
Contributor Author

@jhrcek jhrcek Oct 4, 2020

Choose a reason for hiding this comment

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

Nevermind, the speed difference seems to have been fluke. On repeated reruns both versions seems to have comparable performance. So I'm going with your suggestion of using the ghc helper function.

src/Development/IDE/Plugin/CodeAction.hs Show resolved Hide resolved
@jhrcek jhrcek requested a review from pepeiborra October 4, 2020 14:34
@pepeiborra pepeiborra merged commit d6fc31e into haskell:master Oct 4, 2020
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…skell/ghcide#839)

* Add failing tests

* Ugly fix, make tests pass

* Clean it up

* Make the tests more readable

* Use splitLHsQualTy
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…skell/ghcide#839)

* Add failing tests

* Ugly fix, make tests pass

* Clean it up

* Make the tests more readable

* Use splitLHsQualTy
pepeiborra pushed a commit to pepeiborra/ide that referenced this pull request Dec 29, 2020
…skell/ghcide#839)

* Add failing tests

* Ugly fix, make tests pass

* Clean it up

* Make the tests more readable

* Use splitLHsQualTy
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Type class constraint inserted as last line in source file
4 participants