#14933 closed bug (fixed)

DeriveAnyClass can cause "No skolem info" GHC panic

Reported by: RyanGlScott Owned by:
Priority: normal Milestone: 8.4.2
Component: Compiler (Type checker) Version: 8.2.2
Keywords: deriving Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Compile-time crash or panic Test Case: deriving/should_compile/T14933
Blocked By: Blocking:
Related Tickets: #14932 Differential Rev(s): Phab:D4507
Wiki Page:


This program panics:

{-# LANGUAGE DefaultSignatures          #-}
{-# LANGUAGE DeriveAnyClass             #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DerivingStrategies         #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes                 #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeFamilies               #-}
module Bug where

import Control.Concurrent (ThreadId)
import Control.Monad.Reader

class Wrapped s where
  type Unwrapped s :: *
  _Wrapped' :: Iso' s (Unwrapped s)

type Iso' s a = forall f. Functor f => (a -> f a) -> s -> f s

class Fork m where
    fork :: x -> m () -> m ThreadId

    default fork :: ( Wrapped (m ())
                    , Unwrapped (m ()) ~ t ()
                    , Fork t
                    , Wrapped (m ThreadId)
                    , Unwrapped (m ThreadId) ~ t ThreadId
                    ) => x -> m () -> m ThreadId
    fork = undefined -- view _Unwrapped' . fork . view _Wrapped'

instance Fork m => Fork (ReaderT e m) where
    fork x action = ReaderT $ \env -> fork x (runReaderT action env)

data Env

newtype MyThing m a = MyThing { unMyThing :: ReaderT Env m a }
    deriving newtype  (Functor, Applicative, Monad)
    deriving anyclass (Fork)

instance Wrapped (MyThing m a) where
    type Unwrapped (MyThing m a) = ReaderT Env m a
    _Wrapped' = undefined -- iso unMyThing MyThing
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )

Bug.hs:39:24: error:ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
        No skolem info:
  Call stack:
      CallStack (from HasCallStack):
        prettyCurrentCallStack, called at compiler/utils/Outputable.hs:1133:58 in ghc:Outputable
        callStackDoc, called at compiler/utils/Outputable.hs:1137:37 in ghc:Outputable
        pprPanic, called at compiler/typecheck/TcErrors.hs:2653:5 in ghc:TcErrors

(Program adapted from here.)

Change History (6)

comment:1 Changed 18 months ago by monoidal

Smaller version:

{-# LANGUAGE DefaultSignatures          #-}
{-# LANGUAGE DeriveAnyClass             #-}
{-# LANGUAGE TypeFamilies               #-}
module Bug where

class Wrapped s where 
  type Unwrapped s :: *

class Fork m where
    fork :: (x, m)

    default fork :: ( Wrapped m 
                    , Unwrapped m ~ t
                    , Fork t
                    ) => (x, m)
    fork = undefined 

newtype MyThing m = MyThing m
    deriving (Fork)

instance Wrapped (MyThing m) where
    type Unwrapped (MyThing m) = m
Last edited 18 months ago by monoidal (previous) (diff)

comment:2 Changed 18 months ago by RyanGlScott

Differential Rev(s): Phab:D4507
Status: newpatch

Ack, it turns out that we are re-using the same unification variables across multiple iterations of simplifyDeriv, which results in utter disaster. (Honestly, I'm not sure how anything was working before.)

Phab:D4507 fixes this issue (and #14932) by generating new unification variables across each iteration of simplifyDeriv.

comment:3 Changed 18 months ago by Simon Peyton Jones <simonpj@…>

In 2a3702d8/ghc:

Comments and tiny refactor

Related to Ryan's upcoming patch for Trac #14933

comment:4 Changed 18 months ago by Ben Gamari <ben@…>

In 9893042/ghc:

Fix two pernicious bugs in DeriveAnyClass

The way GHC was handling `DeriveAnyClass` was subtly wrong
in two notable ways:

* In `inferConstraintsDAC`, we were //always// bumping the `TcLevel`
  of newly created unification variables, under the assumption that
  we would always place those unification variables inside an
  implication constraint. But #14932 showed precisely the scenario
  where we had `DeriveAnyClass` //without// any of the generated
  constraints being used inside an implication, which made GHC
  incorrectly believe the unification variables were untouchable.
* Even worse, we were using the generated unification variables from
  `inferConstraintsDAC` in every single iteration of `simplifyDeriv`.
  In #14933, however, we have a scenario where we fill in a
  unification variable with a skolem in one iteration, discard it,
  proceed on to another iteration, use the same unification variable
  (still filled in with the old skolem), and try to unify it with
  a //new// skolem! This results in an utter disaster.

The root of both these problems is `inferConstraintsDAC`. This patch
fixes the issue by no longer generating unification variables
directly in `inferConstraintsDAC`. Instead, we store the original
variables from a generic default type signature in `to_metas`, a new
field of `ThetaOrigin`, and in each iteration of `simplifyDeriv`, we
generate fresh meta tyvars (avoiding the second issue). Moreover,
this allows us to more carefully fine-tune the `TcLevel` under which
we create these meta tyvars, fixing the first issue.

Test Plan: make test TEST="T14932 T14933"

Reviewers: simonpj, bgamari

Reviewed By: simonpj

Subscribers: rwbarton, thomie, carter

GHC Trac Issues: #14932, #14933

Differential Revision: https://phabricator.haskell.org/D4507

comment:5 Changed 18 months ago by RyanGlScott

Milestone: 8.4.2
Status: patchmerge
Test Case: deriving/should_compile/T14933

comment:6 Changed 18 months ago by bgamari

Resolution: fixed
Status: mergeclosed
Note: See TracTickets for help on using tickets.