-
Notifications
You must be signed in to change notification settings - Fork 272
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
Improve error LSP ranges on type mismatches #5284
base: trunk
Are you sure you want to change the base?
Conversation
ec6988d
to
7b8ca46
Compare
936a77c
to
29fd7e3
Compare
Had fun getting ormolu to work properly here... turns out there's a non-determinism bug, if you have a Fixed it by just rewriting the comments. |
@aryairani would be good to test this out on trunk for at least a little bit before it goes out. Shouldn't be outright harmful, but might require a little tweaking for unexpected edge-cases. TBH though I think it's likely to be a universal improvement over the current version 👍🏼 |
Before and after looks good!
Maybe? For |
@@ -368,7 +368,7 @@ renderTypeError e env src = case e of | |||
Mismatch {..} -> | |||
mconcat | |||
[ Pr.lines | |||
[ "I found a value of type: " <> style Type1 (renderType' env foundLeaf), |
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.
I think this extra space may have been intentional to allow the types and the :
s to line up. I would move the space after the :
to preserve that the types line up, or just revert this line altogether.
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.
I think this has caught me like 3 times now, I admit I don't find it very intuitive 🙃
I'll move it to after the :
so I don't do this again in 3 weeks haha.
Seems obviously good in the We could 1) smart match on the Or we could 2) change this PR apply to only Or we could 3) merge it as-is, possibly making @pchiusano Any thoughts? I guess my preference is 2, 1 (but time-boxed), 3 in that order; unless there's an obvious easy theoretical answer. |
Yeah I think it'd be good to detect a TBH I'm not sure we actually avoid the issue if we only do it on
Then this will show the error on the |
Oops, good point. Well... side note, I kind of thought our type provenance algorithm was already supposed to do this, do we just need the ability to drill down into the type automatically? Do we not have that. Sorry I don't have a laptop this week but maybe there's a tweak or bug in the annotations that's causing this to happen like if we have Anyway it would definitely be good to get this working. Sorry I'm rambling. |
b53fdca
to
108ed55
Compare
845c4e8
to
1a59338
Compare
|
||
-- | Checks if the mismatch between two types is due to a missing delay, if so returns a tag for which type is | ||
-- missing the delay | ||
isMismatchMissingDelay :: (Var v) => Type v loc -> Type v loc -> Maybe (Either (Type v loc) (Type v loc)) |
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.
@pchiusano is this a reasonable way to do this? I suppose ideally this would be done inside the typechecker itself, but it seems like a pretty simple type to check against 🤔
It works in simple cases; but unsurprisingly doesn't seem to work with polymorphic types; e.g. this doesn't trip the hint:
y : '(e -> Nat)
y =
_ = 1
_ = "one two three"
(_a -> 2)
If adding it correctly to the typechecker is difficult it's still beneficial to get the hint sometimes rather than not at all; but would be nice if it worked in all cases :)
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.
cc @dolio
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.
So, here's a possible idea for how to make the typechecker facilitate some of this. Up to you if you want to try out implementing it.
So, we can detect do
in the typechecker because it turns into Lam body
where Var.typeOf (ABT.variable body) = Delay
. We can try to detect 't
in the typechecker by looking for a check against () -> t
. So, you can try to partition the checking problem into three cases:
- Checking
λDelay -> ...
against() -> t
: this looks fine, so just continue as normal - Checking
λDelay -> ...
against something else: this might be a baddo
, so put something in the error scope that indicates this. - Checking something else against
() -> t
: this might be a missingdo
, so again put something in the error scope.
Then you can try to parse the improved error information in some situations. Like, if you got a leaf mismatch with an arrow vs. something else, you could look to see if one of these do
indicators is upstream, and report something about that instead.
I think with this approach, you might be able to identify the example you mentioned above. I'm not 100% sure that it wouldn't cause some other weird corner cases, though.
So, my understanding of the reasons behind these two poor behaviors is as follows. For the
However, In some sense, this is caused by desugaring The other case could be improved in the type checker, though, I think. What is happening right now is that
eventually directly calls:
The reported errors rely on scoping information that is supposed to be pushed/popped during type checking, but the Possibly with this change you wouldn't need to crawl to the leaf of the let for some errors. But, you'd need a different strategy for reporting your whole block You probably need a couple cases in |
Overview
When you get a type mismatch on the type of a
do
orlet
block the range reported for the error is the ENTIRE block, which lights up the editor like a Christmas tree, which is annoying and less-than-helpful for finding where the error actually is.This changes the range to be just the "leaf expressions" of the returned value of a block which results in a much more reasonable error highlight.
One time where you may not want this is if the type of the block itself is wrong; e.g.
'Nat
vsNat
; I've special cased that situation and will highlight the whole block and print a hint suggesting adding/removing ado
.Old: Highlights the whole humongous block 😢
New: Highlights only the relevant final line.
Hint for superfluous delay:
Hint for missing delay:
Implementation notes
It simply crawls down the expression that's causing the type error, if it's a Let/Do block it crawls inside and finds the terminal expressions within the block and returns those annotations instead.
Test coverage
Loose ends
Might we want to alter UCM's type-mismatch message to include the more accurate ranges too?