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
Misleading Type Error #3788
Comments
Here's a simplified example: foo :: Effect Unit
foo = do
log "hello" -- Misleading compiler error here
y <- Just "World" -- This line should be flagged instead
logShow y https://try.purescript.org/?gist=1059a81d0a851f59bf6f3f641d5e0364 |
I think that having good errors for do-notation would probably require us to type-check the original do-syntax. I think it's likely that poor errors arise in do notation due to type-checking the desugared syntax, where conflicts in the tail propagate up the block. I'm not completely positive this is the case, but it's always been an issue even after we added correct source positions for this syntax. |
I'd also like to note that using the monomorphized versions of foo :: Effect Unit
foo = do
log "hello"
y <- Just "World" -- This line should be flagged instead
logShow y -- Misleading compiler error here https://try.purescript.org/?gist=733fdfcc03328d2960d507200613d4e0 I do think type-check-then-desugar would definitely help produce better errors here, though. |
That's what GHC does: type check, then desugar. |
Why wouldn't we change the order of operations in the type checker instead of type-checking sugared do blocks? Even with the manually desugared foo :: Effect Unit
foo = log "hello" >>= \_ -> Just "World" >>= \y -> logShow y we would want the I could be completely wrong about this but I would imagine that the type checker has some freedom when checking function applications to decide whether to unify instantiated result types with the expected type first or check arguments against the instantiated parameter types first, and I think that's the determining factor in where the squigglies end up, isn't it? |
Isn't it more like a synthesis rule? With |
Yeah, I don't pretend to understand why the type checker is written the way it is, but it does seem to behave like—and this lines up with what I understand from the implementation—the algorithm when checking a function application is to first infer the function type, then check the argument against that type, and then check that the result of that type matches the expected type. I think that's basically Algorithm W's inference rule, with a unification step at the end for the final check. I'm asking if, when checking as opposed to inferring/synthesizing, it would make sense to reverse those steps: first, check the function against |
I also can't say I understand bidirectional type checking thoroughly enough to diverge from the typing rules (which is currently 1-to-1 with the papers for the most part). I'm still leaning more towards adding more meta-information to the type checker by deferring the desugaring of do-blocks; we could always add special cases in the type checker, but that's not really maintainable 😄 |
I don't think this is an issue specific to do blocks, though. See my earlier example; currently, the Edit: I should qualify that last statement, because it's not literally what I want. What I want is something more like, the type checker should present unification errors as if it were traversing an expression in normal order, building up a human-level understanding of the types involved, and presenting an error on the first inconsistency thus encountered. In particular, with data Trio a = Trio a a a
x = Trio false 0 "" I would expect y :: Trio Unit
y = Trio false 0 "" I would expect The current algorithm highlights |
Ah, thanks for the clarification; that's a more intuitive way to look at it. I think more meta information when typing applications is the way to go then. As in, treating applications as a whole in order to figure out which argument position fails, while (edit: mostly) keeping the typing rule for function applications. Edit: I see that this has to do with the type checker switching to inference while checking the type application, right? With your example, what happens is: check (Trio false 0 "") (Trio Unit)
infer (Trio false 0) -> checkApp ""
infer (Trio false) -> checkApp 0
infer Trio -> checkApp false
-- at this point, `a` should be `Boolean` |
The compiler gives a misleading type error where it assumes the type should be
Effect
even though the top type declaration isAff
(line 19) then reports that anAff
line (line 24) is in error instead of theEffect
line (line 22). I was having trouble simplifying this so I put the whole file, sorry.The text was updated successfully, but these errors were encountered: