-
-
Notifications
You must be signed in to change notification settings - Fork 378
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
Import suggestion for missing newtype constructor, all types constructor and indirect overloadedrecorddot fields #4516
base: master
Are you sure you want to change the base?
Conversation
In a context where we want to `coerce` to a type for which constructor is not in scope, GHC fails with (e.g., for `Sum Int`): ``` • Couldn't match representation of type ‘Int’ with that of ‘Sum Int’ arising from a use of ‘coerce’ The data constructor ‘base-4.18.2.1:Data.Semigroup.Internal.Sum’ of newtype ‘Sum’ is not in scope ``` This code action detects the missing `newtype` and suggests to add the required import. This is convenient because otherwise the user need to interpret the error message and most of the time manually find which module and type to import. Note that a better implementation could try to decet that the type is already imported (if that's the case) and just suggest to add the constructor (e.g. `(..)`) in the import list, but this is too much complexity to implement. It could lead to duplicated import lines which will be "cleaned" by formatter or other extensions.
For example, `deriving instance Generic (Sum Int)`, but it should work for other deriving which indirectly requires a complete access to the type constructor. ``` Can't make a derived instance of ‘Generic (Sum Int)’: The data constructors of ‘Sum’ are not all in scope so you cannot derive an instance for it ```
For example, the following code `foo.titi` when the type of `foo` (e.g. `Bar` here is not in scope and not from an already imported module (e.g. the type exists indirectly because here `foo :: Bar` comes from another module). If the module which contains `Bar` is already imported, GHC already gives an hint to add `titi` to the `import Bar` line and this is already correctly handled by HLS. ``` No instance for ‘HasField "titi" Bar.Bar String’ arising from selecting the field ‘titi’ ```
This correct previous commit by handling ghc 9.4 parethensis instead of "tick".
bddf4b5
to
f1eb36a
Compare
Rebased and fixed test for GHC 9.4. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the change ~
I think we just need more test on the regex.
Otherwise it is good to go.
-- "foo" (Bar Int)...`, e.g. see the parenthesis | ||
| Just [_module, name] <- matchRegexUnifySpaces x "No instance for [‘(].*HasField \"[^\"]+\" ([^ (.]+\\.)*([^ (.]+).*[’)]" | ||
= Just $ NotInScopeThing name | ||
| Just [_module, name] <- matchRegexUnifySpaces x "No instance for [‘(].*HasField \"[^\"]+\" \\(([^ .]+\\.)*([^ .]+)[^)]*\\).*[’)]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems complex.
perhapes more unit test on these patterns. Thanks
I mean just plain unit test for matchRegexUnifySpaces x "No instance for [‘(].*HasField \"[^\"]+\" ([^ (.]+\\.)*([^ (.]+).*[’)]"
and matchRegexUnifySpaces x "No instance for [‘(].*HasField \"[^\"]+\" \\(([^ .]+\\.)*([^ .]+)[^)]*\\).*[’)]"
This MR contains 3 commits which improves the import suggestion code actions:
newtype
constructor is not in scope. This usually happen whencoerce
ingnewtype
.deriving instance Generic Bar
whenBar
(the type) may be in scope, but not the construtors (e.g. requiringBar(..)
).OverloadedRecordDot
context, such asfoo.bar
wherefoo :: Foo
andFoo(bar)
is not in scope. Note that this is already partially handled by HLS in the case where the module containingFoo
is already imported, but not the fields. In this context, GHC is kind enough to give us an hint (something like "maybe add fieldbar
to import line...") and this is already handled by HLS. However, if the module containingFoo
is not already imported, it does not work.All of these case usually happen when types are "indirectly" in scope. For example, consider the followings:
In the module
Usage
, the typeFoo
is not explicitly imported, it exists just indirectly becausefoo
is imported fromValue
.Discussion
I tried to take care of multiples patterns in the regex used to match the error messages, such as qualified or not qualified types or class, as well as polymorphic or not. If you see a case not taken into account, please tell me.
Tests
I've added simple tests for the
coerce
andinstance Generic
"cases" and a more involved test for the overloaded record dot cases.I've developed this using GHC 9.10. I'll test on other version of GHC asap, perhaps some adaptations of the regex need to be introduced.