Expanding a particular type family in type errors

Richard Eisenberg rae at richarde.dev
Mon May 4 09:25:23 UTC 2020


I'm afraid I like none of (1)-(5). Important background: if we have type family F a where F Int = Bool, then F Int and Bool are *not* equal in Core. We cannot just change one to the other. Instead, a coercion exists between them.

1. pprType seems a very challenging place to do this, given that pprType works on IfaceTypes, which are not amenable to much of any analysis. Maybe you could do the switcho-changeo before converting to IfaceType. Are your type families closed? Then it's just barely conceivable. If they're open, you won't have the instances available in pprType. Still, this seems like far too much processing to be done in pretty-printing.

2. tidyType really cannot change one type to another unequal one. Chaos will ensue.

3. reportWanteds will have a similar problem: if we have -fdefer-type-errors, then reportWanteds may actually happen before desugaring and execution, and we can't have a type magically changed in the process. Doing so will lead to a core-lint error.

4-5. These seem the post plausible. Yes, it's true that calls to ArrowStackTup might leak through, but doing so wouldn't be strictly *wrong*, just suboptimal. So it might be that a best-effort here is good enough.

Another possibility: when these ArrowStackTup calls are born, do you already sometimes know the arguments? That is, there must be some code that produces the ArrowStackTup '[a] call -- could it just special-case an '[a] argument and produce `a` instead? Then, the ArrowStackTup family is used only when you have an abstract argument, which might be considerably rarer.

If you haven't yet come across it, see the normaliseType function, which evaluates type families as much as possible.

I hope this helps!
Richard

> On May 2, 2020, at 12:13 AM, Alexis King <lexi.lambda at gmail.com> wrote:
> 
> Answering my own question: it looks like cleaning this up in GHC.Tc.Errors is rather impractical—there are just too many types buried inside other datatypes that would have to be updated—so it has to be wired into pprType. Fortunately, I can branch on userStyle to decide whether or not to do the expansion. This still seems like a bit of a hack, but I can’t think of a better way. Do tell me if there’s a better approach!
> 
>> On May 1, 2020, at 16:36, Alexis King <lexi.lambda at gmail.com <mailto:lexi.lambda at gmail.com>> wrote:
>> 
>> Hi all,
>> 
>> As part of my ongoing rework of arrow notation <https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3191>, I have introduced two wired-in type families, which assist in the typechecking process. The details are not terribly important (you can read the proposal if you’d like for those), but the relevant detail is that equalities of the shape
>> 
>>     ArrowStackTup a ~ b
>> 
>> are produced by the typechecker in key places. ArrowStackTup is one of my wired-in type families, and it’s really an implementation detail. Unfortunately, I often end up with type errors that leak this detail, with expected/actual types like these ones:
>> 
>>     Expected type: ArrowStackTup '[Int] -> Bool
>>       Actual type: Int -> String
>> 
>> This is quite annoying, as it’s exceedingly rare that these type families actually get stuck, so they can almost always be expanded in type errors. As it happens, `ArrowStackTup '[a]` expands to simply `a`, so the type error I would like to report is this one:
>> 
>>     Expected type: Int -> Bool
>>       Actual type: Int -> String
>> 
>> Not technically challenging, but I find myself faced with the question of where this special expansion logic ought to go. It seems like it could go in any of several places:
>> 
>> It could be hard-wired into pprType, and perhaps selectively disabled with an -fprint-* flag. This is nice in that it’s universal, but it’s almost certainly a step too far: the casts for ArrowStackTup still end up in Core, and expanding the type synonyms there would be quite confusing.
>> 
>> The expansion could happen in tidyType, since it’s called before reporting an error. But this seems probably even worse than putting it in pprType, since it’s still used in too many places, and it isn’t supposed to actually change the type.
>> 
>> It could be handled as an extra, ad-hoc preprocessing step in reportWanteds. This is much closer to reasonable, though it feels like quite a hack.
>> 
>> A separate error Reporter could catch these errors before the other reporters do and perform the expansion there. But I don’t think this actually makes sense, as the above example demonstrates that ArrowStackTup might be buried inside another type and in fact might not actually be the source of the type error at all!
>> 
>> It could be done last-minute in mkEqErr. But I don’t know if this is too late, and ArrowStackTup could leak into an error through some other code path.
>> 
>> Of those options, the best one I’ve come up with seems to be option 3, an ad-hoc preprocessing step in reportWanteds. Does that seem reasonable? Or is it too much of a kludge?
>> 
>> Thanks,
>> Alexis
> 
> _______________________________________________
> ghc-devs mailing list
> ghc-devs at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20200504/841c6b0f/attachment.html>


More information about the ghc-devs mailing list