Opened 20 months ago

Last modified 7 months ago

#14828 new bug

panic! when using :print on some functions with class constraints?

Reported by: jol Owned by:
Priority: normal Milestone:
Component: GHCi Version: 8.2.2
Keywords: debugger Cc:
Operating System: Linux Architecture: x86_64 (amd64)
Type of failure: Compile-time crash or panic Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

These are the problematic ones I've found:

> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
> :print foldl
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a1H7[rt] :: TYPE t_a1H6[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug
> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :print fmap
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a1Hu[rt] :: TYPE t_a1Ht[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

> :t return
return :: Monad m => a -> m a
> :print return
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a1Wt[rt] :: TYPE t_a1Ws[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

> :t pure
pure :: Applicative f => a -> f a
> :print pure
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a1WP[rt] :: TYPE t_a1WO[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

These that don't have constraints are fine:

> :print id
id = (_t1::a -> a)
> :print map
map = (_t2::(a1 -> b) -> [a1] -> [b])
> :print const
const = (_t3::a2 -> b1 -> a2)

This value and function created in the session are fine:

> let x :: Monad m => m (); x = return ()
Prelude| 
> :p x
x = (_t5::Monad m1 => m1 ())
> let f :: Monad m => Int -> m Int; f n = return (n + 1)
Prelude| 
> :p f
f = (_t6::Monad m2 => Int -> m2 Int)

mempty and mappend imported from Data.Monoid are fine:

> :m + Data.Monoid
> :p mempty
mempty = (_t7::Monoid a4 => a4)
> :p mappend
mappend = (_t8::Monoid a4 => a4 -> a4 -> a4)

foldl' and foldr imported from Data.List are not fine:

> :m + Data.List
> :p foldl'
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a6Qy[rt] :: TYPE t_a6Qx[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

> :p Data.List.foldr
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
	isUnliftedType
  t2_a6RG[rt] :: TYPE t1_a6RF[rt]
  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/types/Type.hs:1952:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

but all and init from that same module are fine:

> :p Data.List.all
all = (_t13::Foldable t1 => (a22 -> Bool) -> t1 a22 -> Bool)
> :p Data.List.init
init = (_t14::[a29] -> [a29])

So, in a given module, among functions with class constraints, some have the error and others don't. I haven't found a value that's not a function with the error, and I haven't found a function with no class constraints exhibit the error.

Change History (7)

comment:1 Changed 20 months ago by RyanGlScott

Keywords: debugger added

comment:2 Changed 10 months ago by olligobber

Note this is still an issue in 8.6.2

GHCi, version 8.6.2: http://www.haskell.org/ghc/  :? for help
Prelude> :print fmap
ghc: panic! (the 'impossible' happened)
  (GHC version 8.6.2 for x86_64-unknown-linux):
	isUnliftedType
  t1_a1x6[rt] :: TYPE t_a1x5[rt]
  Call stack:
      CallStack (from HasCallStack):
        callStackDoc, called at compiler/utils/Outputable.hs:1160:37 in ghc:Outputable
        pprPanic, called at compiler/types/Type.hs:2021:10 in ghc:Type

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

comment:3 Changed 9 months ago by bgamari

Adding test in !192.

comment:4 Changed 8 months ago by RyanGlScott

I spent some time today digging into why exactly this panic happens. The immediate issue appears to be a hiccup in how the interactive debugger handles higher-rank types, which is surprising, considering that none of the types in the original description appear to be higher-rank. For the time being, just take my word for it that this is true—I'll return to this point later.

Here is an example showing that :print chokes on a term with a higher-rank type:

GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
λ> f :: (forall a. a -> a) -> b -> b; f g x = g x
λ> :print f
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
        isUnliftedType
  t1_a1tY[rt] :: TYPE t_a1tX[rt]
  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/types/Type.hs:1952:10 in ghc:Type

The fact that the panic mentions t1_a1tY is a bit curious... I wonder what happens if we try an older version of GHC?

GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
λ> f :: (forall a. a -> a) -> b -> b; f g x = g x
λ> :print f
f = (_t1::t1)

Ah, this doesn't panic on GHC 8.0, so this must be a regression introduced between 8.0 and 8.2. Moreover, note that even in 8.0, :print f's behavior is strange: it prints out a thunk of type t1 instead of, say, (forall a. a -> a) -> b -> b. This must explain where the t1_a1tY in the 8.2 panic comes from, since that is the type of _t1 (with its unique explicitly printed).

What changed between GHC 8.0 and 8.2 that would trigger this panic? As it turns out, it's commit e7985ed23ddc68b6a2e4af753578dc1d9e8ab4c9 (Update levity polymorphism). Specifically, this change:

  • compiler/ghci/Debugger.hs

    diff --git a/compiler/ghci/Debugger.hs b/compiler/ghci/Debugger.hs
    index 64ac1540aa..4d7f8e3ef0 100644
    a b import Var hiding ( varName ) 
    2828import VarSet
    2929import UniqFM
    3030import Type
    31 import Kind
    3231import GHC
    3332import Outputable
    3433import PprTyThing
    pprintClosureCommand bindThings force str = do 
    7877       term_    <- GHC.obtainTermFromId maxBound force id'
    7978       term     <- tidyTermTyVars term_
    8079       term'    <- if bindThings &&
    81                       False == isUnliftedTypeKind (termType term)
     80                      (not (isUnliftedType (termType term)))
    8281                     then bindSuspensions term
    8382                     else return term
    8483     -- Before leaving, we compare the type obtained to see if it's more specific

I'm not sure if this was Richard's intention, but this patch actually changes the behavior of :print. Unlike isUnlifedTypeKind, isUnliftedType is a partial function. If isUnliftedType cannot ascertain with 100% confidence that a type is unlifted, then it throws the isUnliftedType panic we saw above. Evidently, GHC isn't 100% confident that t1_a1tY is unlifted.

This proposes one possible patch. Instead of checking if not (isUnliftedType (termType term)) returns True, we could check is isLiftedType_maybe (termType term) returns Just True. This "inverts" the check by querying if GHC is 100% certain that termType term is lifted, and moreover, isLiftedType_maybe won't panic if that isn't the case.


So why are functions like fmap, which appear not to be higher-rank, triggering this panic? -ddump-rtti reveals the answer:

GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
λ> :set -ddump-rtti 
λ> :print fmap
Term reconstruction started with initial type forall (f :: * -> *).
                                              GHC.Base.Functor f =>
                                              forall a b. (a -> b) -> f a -> f b
Unknown closure: Fun
check2 passed
add constraint: t1_a1sK[tau:1] =
                GHC.Base.Functor f0_a1sI[tau:1] =>
                forall a b. (a -> b) -> f0_a1sI[tau:1] a -> f0_a1sI[tau:1] b
Term reconstruction completed.
Term obtained: _
Type obtained: t1_a1sK[rt]
ghc: panic! (the 'impossible' happened)
  (GHC version 8.2.2 for x86_64-unknown-linux):
        isUnliftedType
  t1_a1sK[rt] :: TYPE t_a1sJ[rt]
  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/types/Type.hs:1952:10 in ghc:Type

In particular, take special notice of these parts:

Term reconstruction started with initial type forall (f :: * -> *).
                                              GHC.Base.Functor f =>
                                              forall a b. (a -> b) -> f a -> f b
add constraint: t1_a1sK[tau:1] =
                GHC.Base.Functor f0_a1sI[tau:1] =>
                forall a b. (a -> b) -> f0_a1sI[tau:1] a -> f0_a1sI[tau:1] b

:print starts with the type forall f. Functor f => forall a b. (a -> b) -> f a -> f b which, strictly speaking, is higher-rank, as there is a nested use of forall a b. Normally, we don't think of foralls to the right of => as higher-rank, since we can "float" them out to the front of the type, but :print doesn't appear to be doing this, since the add constraint logging message says that t1_a1sK is equal to Functor f0 => forall a b. (a -> b) -> f0 a -> f0 b, where f0 is a metavariable. Note that :print seems to have instantiated f with a metavariable, but not a or b! If :print had done that, then t1_a1sK would not be higher-rank at all, avoiding this panic in the first place.

Of course, even if we did this smarter metavariable instantiation, the problem of higher-rank types crashing :print would still linger. This suggests that we should fix the isUnliftedType panic first, and then we can worry about future steps like making the type of fmap render correctly with :print.

Last edited 8 months ago by RyanGlScott (previous) (diff)

comment:5 Changed 8 months ago by Ben Gamari <ben@…>

In 5b970d8/ghc:

testsuite: Add test for #14828

comment:6 Changed 7 months ago by Marge Bot <ben+marge-bot@…>

In 8162eab2/ghc:

Remove the GHCi debugger's panicking isUnliftedType check

The GHCi debugger has never been that robust in the face of
higher-rank types, or even types that are _interally_ higher-rank,
such as the types of many class methods (e.g., `fmap`). In GHC 8.2,
however, things became even worse, as the debugger would start to
_panic_ when a user tries passing the name of a higher-rank thing
to `:print`. This all ties back to a strange `isUnliftedType` check
in `Debugger` that was mysteriously added 11 years ago
(in commit 4d71f5ee6dbbfedb4a55767e4375f4c0aadf70bb) with no
explanation whatsoever.

After some experimentation, no one is quite sure what this
`isUnliftedType` check is actually accomplishing. The test suite
still passes if it's removed, and I am unable to observe any
differences in debugger before even with data types that _do_ have
fields of unlifted types (e.g., `data T = MkT Int#`). Given that
this is actively causing problems (see #14828), the prudent thing
to do seems to be just removing this `isUnliftedType` check, and
waiting to see if anyone shouts about it. This patch accomplishes
just that.

Note that this patch fix the underlying issues behind #14828, as the
debugger will still print unhelpful info if you try this:

```
λ> f :: (forall a. a -> a) -> b -> b; f g x = g x
λ> :print f
f = (_t1::t1)
```

But fixing this will require much more work, so let's start with the
simple stuff for now.

comment:7 Changed 7 months ago by Marge Bot <ben+marge-bot@…>

In 8d18a873/ghc:

Reject nested predicates in impredicativity checking

When GHC attempts to unify a metavariable with a type containing
foralls, it will be rejected as an occurrence of impredicativity.
GHC was /not/ extending the same treatment to predicate types, such
as in the following (erroneous) example from #11514:

```haskell
foo :: forall a. (Show a => a -> a) -> ()
foo = undefined
```

This will attempt to instantiate `undefined` at
`(Show a => a -> a) -> ()`, which is impredicative. This patch
catches impredicativity arising from predicates in this fashion.

Since GHC is pickier about impredicative instantiations, some test
cases needed to be updated to be updated so as not to fall afoul of
the new validity check. (There were a surprising number of
impredicative uses of `undefined`!) Moreover, the `T14828` test case
now has slightly less informative types shown with `:print`. This is
due to a a much deeper issue with the GHCi debugger (see #14828).

Fixes #11514.
Note: See TracTickets for help on using tickets.