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
singletons-2.5 regression: derived Show instances for recursive singleton types loop at compile time #371
Comments
#372 would fix this. |
I don't agree with the analysis here. Let's re-examine:
(Surely you meant it with those extra parens toward the end.) I say In contrast to the analysis above, the problem isn't from overlapping instances. That would happen only with Givens (say, when type-checking the instances), but everything here is a Wanted. No, the problem is that GHC's solver can't deal with this scenario. It would need to remember that it's really solving, e.g. I think this is squarely GHC's problem, not ours. Of course, we don't want our users to suffer just because we haughtily declare that we're right and GHC is wrong. So bring on #372, while posting this to GHC proper. |
Minimized example, about to be posted to GHC:
|
Posted #15888. |
Well, I'm glad that someone in the know thinks that this behavior of GHC is a bug. My fear was that if I posted the actual place where I discovered this bug: deriving instance (forall z. Show (Sing (z :: a)), forall z. Show (Sing (z :: [a])))
=> Show (Sing (z :: [a]))) Then it would be written off as an obvious infinite loop (due to the fact that we have |
That instance should be OK, too. After all, GHC accepts |
In that case, I'll update #372 to indicate that the whole thing is a workaround for Trac #15888, then land it and make a point release. |
Now that I've released |
Unfortunately, I inadvertently introduced a regression in the way derived
Show
instances for recursive singleton types work. To explain what I mean, consider the following code:This compiles without issue in
singletons-2.4
. Insingletons-2.5
, however, it fails to compile with the following error:To see why this happens, consider the code that gets generated for the derived
Show
instances forX
andY
:This part typechecks fine. It's when you actually try to use it, as in
print (sing :: Sing (X1 :: X Bool))
, where the typechecker loops forever. Recall thatShowSing
was changed insingletons-2.5
to be a type synonym:If you expand both occurrences of the
ShowSing
type synonym in the generated instances, you'll get:Due to the way
QuantifiedConstraints
works, GHC will always favor local, quantified constraints in the instance contexts over top-level instances. Notice that there is both a top-level instance forY a
as well as a local, quantified instance forY a
in scope in theShow
instance forX a
, so GHC will favor the local instance during instance resolution. But when resolving the local instance forY a
, we are back in the same situation: there is both a top-level and local instance forX a
, so the local instance is picked. When resolving that instance... we repeat the process and find ourselves in an infinite loop that eventually overflows the reduction stack. Eep.I think the simplest solution to make
ShowSing
a class again. That is, redefine it like this:All existing
singletons
code should continue to work with this version ofShowSing
, and since using a class ties the recursive knot, it doesn't suffer from the infinite looping issue that is described above. As an added bonus, users no longer have to enableQuantifiedConstraints
in all every module that singles a derivedShow
instance, since the use ofQuantifiedConstraints
is now localized entirely to the module that defines theShowSing
class.Does this sound reasonable, @goldfirere? If so, this might be worth releasing a
singletons-2.5.1
point release for, since this is a pretty nasty regression that prevents things likeshow (sing :: Sing '[True])
from typechecking, as I recently discovered.The text was updated successfully, but these errors were encountered: