Hey, first off I'm psyched that this project is being worked on! I had a question (or comment) about how this project decided to report diagnostics. If my understanding is correct, it looks like this project uses a library version fork of the Elm compiler and uses that to type check the user's code. This is pretty cool, but I'm not sure that it's the best way to do this. My reasons for thinking this are
-
It seems like a lot of work to maintain a fork of of the Elm compiler. This is especially true if there ends up being something like an 0.19.1
to address a bug that is being discussed here. Additionally, it seems hard to eventually support both 0.19 and 0.20 down the line if this project uses a compiler fork.
-
Elm includes a flag to get these syntax and type errors. If one runs elm make src/Main.elm
, and the error something like
-- UNBOUND TYPE VARIABLE ----------------------------------------- src/Field.elm
The `Field` type uses an unbound type variable `error` in its definition:
44| type Field value
45| = Field value Metadata (Status error)
^^^^^
You probably need to change the declaration to something like this:
type Field value error = ...
Why? Well, imagine one `Field` where `error` is an Int and another where it is a
Bool. When we explicitly list the type variables, the type checker can see that
they are actually different types.
then one can run elm make src/Main.elm --report=json
and the output will be
{
"type": "compile-errors",
"errors": [{
"path": "src/Field.elm",
"name": "Field",
"problems": [{
"title": "UNBOUND TYPE VARIABLE",
"region": {
"start": {
"line": 44,
"column": 1
},
"end": {
"line": 45,
"column": 42
}
},
"message": ["The `Field` type uses an unbound type variable ", {
"bold": false,
"underline": false,
"color": "yellow",
"string": "`error`"
}, " in its definition:\n\n44| type Field value\n45| = Field value Metadata (Status error)\n ", {
"bold": false,
"underline": false,
"color": "red",
"string": "^^^^^"
}, "\nYou probably need to change the declaration to something like this:\n\n type Field value ", {
"bold": false,
"underline": false,
"color": "GREEN",
"string": "error"
}, " = ...\n\nWhy? Well, imagine one `Field` where `error` is an Int and another where it is a\nBool. When we explicitly list the type variables, the type checker can see that\nthey are actually different types."]
}]
}]
}
Then, one only has to parse the json to get the error and report it back to the user.
Because of the challenges of maintaining a fork and the fact the you can get compile errors from elm make
, it seems to me that attempting to find the user installed version of Elm and getting diagnostics from that would be more effective. Other benefits of this approach are
-
The language server could prefer local installations. If a user used 0.19 in one project and 0.20 installed in another (both installed in maybenode_modules
), then the language server could report errors seamlessly in both. Additionally, it can always fallback to looking at a global installation.
-
This project only has to maintain a fork of the elm parser, which is simpler than maintaining a fork of the compiler. I think it's fair to say that generally speaking the elm syntax doesn't change drastically between releases, so maintain a fork of just the compiler may end up being more straightforward.
I would also like to point out that this seems to be the approach taken by [elm-format] (https://github.com/avh4/elm-format), though their goal/use case is somewhat different.
And lastly, I have been working on my own implementation of an elm language server, and the approach I've outlined in this issue has worked well so far. It seems that collaborating on one project is more beneficial to the community though, which is why I'm writing this issue. If interested, this project can use that as a basis for the implementation.
Please let me know your thoughts on this, it's super possible that there are reasons for keeping a fork of the compiler that I haven't thought of! And I'm super down to work on this refactor if it's decided that this is the way to go.