[GHC] #13264: GHC panic with (->) generalization branch while compiling lens

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- While testing characterizing the performance impact of the Typeable branch (`wip/ttypeable`) against Hackage packages I have found that `lens` manages to break the `(->)` kind-generalization patch. Specifically, `TcCanonical.can_eq_nc` induces a panic by `tcRepSplitTyApp_maybe` during compilation of `Control.Lens.Traversal.holesOf`, {{{ ghc-stage2: panic! (the 'impossible' happened) (GHC version 8.1.20170207 for x86_64-unknown-linux): tcRepSplitTyConApp_maybe ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] c_alzb[tau:5] Call stack: CallStack (from HasCallStack): prettyCurrentCallStack, called at compiler/utils/Outputable.hs:1188:58 in ghc:Outputable callStackDoc, called at compiler/utils/Outputable.hs:1192:37 in ghc:Outputable pprPanic, called at compiler/typecheck/TcType.hs:1456:5 in ghc:TcType tcRepSplitTyConApp_maybe, called at compiler/typecheck/TcCanonical.hs:617:25 in ghc:TcCanonical }}} The last thing emitted by tc-trace is, {{{ can_eq_nc False [WD] hole{alyP} {0}:: (p_alyn[tau:5] :: TYPE p_alym[tau:5]) GHC.Prim.~# (cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] :: *) nominal equality ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] -> c_alzb[tau:5] p_alyn[tau:5] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] }}} While I haven't yet fully reduced the reproducer to a standalone module, replacing `Control.Lens.Traversal` in a `lens` working tree is sufficient, {{{#!hs {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} module Control.Lens.Traversal where import Control.Category import Control.Lens.Internal.Bazaar import Control.Lens.Internal.Context import Control.Lens.Internal.Indexed import Data.Tagged import Prelude hiding ((.),id) type Over p f s t a b = p a (f b) -> s -> f t holesOf :: forall p s t a. Conjoined p => Over p (Bazaar p a a) s t a a -> s -> [Pretext p a a t] holesOf l s = unTagged ( conjoined (Tagged $ let f [] _ = [] f (x:xs) g = Pretext (\xfy -> g . (:xs) <$> xfy x) : f xs (g . (x:)) in f (ins b) (unsafeOuts b)) (Tagged $ let f [] _ = [] f (wx:xs) g = Pretext (\wxfy -> g . (:Prelude.map extract xs) <$> cosieve wxfy wx) : f xs (g . (extract wx:)) in f (pins b) (unsafeOuts b)) :: Tagged (p a b) [Pretext p a a t] ) where b = l sell s }}} More specifically, {{{ $ git clone git://github.com/bgamari/hashable $ git clone git://github.com/ekmett/comonad $ git clone git://github.com/ekmett/semigroupoids $ git clone git://github.com/ekmett/lens $ cabal install ./comonad ./lens ./semigroupoids ./hashable --with- ghc=`pwd`/inplace/bin/ghc-stage2 --allow-newer=base,template- haskell,primitive,ghc-prim --disable-library-profiling -j1 --ghc- options='-v -ddump-to-file -ddump-tc-trace' }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Here is a standalone reproducer, {{{#!hs {-# LANGUAGE Rank2Types #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} module Control.Lens.Traversal where import Control.Category import Prelude hiding ((.),id) type Over p f s t a b = p a (f b) -> s -> f t newtype Bazaar p a b t = Bazaar { runBazaar :: forall f. Applicative f => p a (f b) -> f t } newtype Pretext p a b t = Pretext { runPretext :: forall f. Functor f => p a (f b) -> f t } newtype Tagged s b = Tagged { unTagged :: b } class Conjoined p where holesOf :: forall p s t a. Conjoined p => Over p (Bazaar p a a) s t a a -> s -> [Pretext p a a t] holesOf l s = unTagged ( conjoined (Tagged $ let f [] _ = [] f (x:xs) g = Pretext (\xfy -> g . (:xs) <$> xfy x) : f xs (g . (x:)) in f (ins b) (unsafeOuts b)) (Tagged $ let f [] _ = [] f (wx:xs) g = Pretext (\wxfy -> g . (:Prelude.map extract xs) <$> cosieve wxfy wx) : f xs (g . (extract wx:)) in f (pins b) (unsafeOuts b)) :: Tagged (p a b) [Pretext p a a t] ) where b = l sell s }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * Attachment "Traversal.hs" added. Standalone reproducer -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * Attachment "Traversal.dump-tc-trace.xz" added. tc-trace output from compilation -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Description changed by bgamari: @@ -40,49 +40,0 @@ - - While I haven't yet fully reduced the reproducer to a standalone module, - replacing `Control.Lens.Traversal` in a `lens` working tree is sufficient, - {{{#!hs - {-# LANGUAGE Rank2Types #-} - {-# LANGUAGE FlexibleContexts #-} - {-# LANGUAGE FlexibleInstances #-} - {-# LANGUAGE ScopedTypeVariables #-} - - module Control.Lens.Traversal where - - import Control.Category - import Control.Lens.Internal.Bazaar - import Control.Lens.Internal.Context - import Control.Lens.Internal.Indexed - import Data.Tagged - import Prelude hiding ((.),id) - - type Over p f s t a b = p a (f b) -> s -> f t - - holesOf :: forall p s t a. Conjoined p => Over p (Bazaar p a a) s t a a -> - s -> [Pretext p a a t] - holesOf l s = unTagged - ( conjoined - (Tagged $ let - f [] _ = [] - f (x:xs) g = Pretext (\xfy -> g . (:xs) <$> xfy x) : f xs (g . - (x:)) - in f (ins b) (unsafeOuts b)) - (Tagged $ let - f [] _ = [] - f (wx:xs) g = Pretext (\wxfy -> g . (:Prelude.map extract xs) <$> - cosieve wxfy wx) : f xs (g . (extract wx:)) - in f (pins b) (unsafeOuts b)) - :: Tagged (p a b) [Pretext p a a t] - ) where b = l sell s - }}} - - More specifically, - {{{ - $ git clone git://github.com/bgamari/hashable - $ git clone git://github.com/ekmett/comonad - $ git clone git://github.com/ekmett/semigroupoids - $ git clone git://github.com/ekmett/lens - $ cabal install ./comonad ./lens ./semigroupoids ./hashable --with- - ghc=`pwd`/inplace/bin/ghc-stage2 --allow-newer=base,template- - haskell,primitive,ghc-prim --disable-library-profiling -j1 --ghc- - options='-v -ddump-to-file -ddump-tc-trace' - }}} New description: While testing characterizing the performance impact of the Typeable branch (`wip/ttypeable`) against Hackage packages I have found that `lens` manages to break the `(->)` kind-generalization patch. Specifically, `TcCanonical.can_eq_nc` induces a panic by `tcRepSplitTyApp_maybe` during compilation of `Control.Lens.Traversal.holesOf`, {{{ ghc-stage2: panic! (the 'impossible' happened) (GHC version 8.1.20170207 for x86_64-unknown-linux): tcRepSplitTyConApp_maybe ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] c_alzb[tau:5] Call stack: CallStack (from HasCallStack): prettyCurrentCallStack, called at compiler/utils/Outputable.hs:1188:58 in ghc:Outputable callStackDoc, called at compiler/utils/Outputable.hs:1192:37 in ghc:Outputable pprPanic, called at compiler/typecheck/TcType.hs:1456:5 in ghc:TcType tcRepSplitTyConApp_maybe, called at compiler/typecheck/TcCanonical.hs:617:25 in ghc:TcCanonical }}} The last thing emitted by tc-trace is, {{{ can_eq_nc False [WD] hole{alyP} {0}:: (p_alyn[tau:5] :: TYPE p_alym[tau:5]) GHC.Prim.~# (cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] :: *) nominal equality ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] -> c_alzb[tau:5] p_alyn[tau:5] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] }}} -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Description changed by bgamari: @@ -1,1 +1,1 @@ - While testing characterizing the performance impact of the Typeable + While characterizing the performance impact of the Typeable New description: While characterizing the performance impact of the Typeable branch (`wip/ttypeable`) against Hackage packages I have found that `lens` manages to break the `(->)` kind-generalization patch. Specifically, `TcCanonical.can_eq_nc` induces a panic by `tcRepSplitTyApp_maybe` during compilation of `Control.Lens.Traversal.holesOf`, {{{ ghc-stage2: panic! (the 'impossible' happened) (GHC version 8.1.20170207 for x86_64-unknown-linux): tcRepSplitTyConApp_maybe ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] c_alzb[tau:5] Call stack: CallStack (from HasCallStack): prettyCurrentCallStack, called at compiler/utils/Outputable.hs:1188:58 in ghc:Outputable callStackDoc, called at compiler/utils/Outputable.hs:1192:37 in ghc:Outputable pprPanic, called at compiler/typecheck/TcType.hs:1456:5 in ghc:TcType tcRepSplitTyConApp_maybe, called at compiler/typecheck/TcCanonical.hs:617:25 in ghc:TcCanonical }}} The last thing emitted by tc-trace is, {{{ can_eq_nc False [WD] hole{alyP} {0}:: (p_alyn[tau:5] :: TYPE p_alym[tau:5]) GHC.Prim.~# (cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] :: *) nominal equality ([] |> <*>_N ->_N Sym {alzj}) a_alzd[tau:5] -> c_alzb[tau:5] p_alyn[tau:5] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] cat_alyK[tau:6] b_alyM[tau:6] c_alyN[tau:6] }}} -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * cc: simonpj, goldfire (added) Comment: It appears that replacing the `tcRepSplitTyApp_maybe` callsite in `can_eq_nc'` with a variant which returns `Nothing` instead of panicking allows compilation to proceed, {{{#!hs -- Try to decompose type constructor applications -- Including FunTy (s -> t) can_eq_nc' _flat _rdr_env _envs ev eq_rel ty1 _ ty2 _ | Just (tc1, tys1) <- tcRepSplitTyConApp_maybe' ty1 , Just (tc2, tys2) <- tcRepSplitTyConApp_maybe' ty2 , not (isTypeFamilyTyCon tc1) , not (isTypeFamilyTyCon tc2) = canTyConApp ev eq_rel tc1 tys1 tc2 tys2 }}} Where `tcRepSplitTyConApp_maybe'` is the variant described above. While I'm far from convinced that this is the right, it does seem plausible. Afterall, the failing invocation involves a `FunTy` and an `AppTy`, so the guards really should just fail. It would be nice to hear Simon or Richard's opinion on this. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by goldfire): I see what's going on here. `tcRepSplitTyConApp_maybe` rightly needs to know the `RuntimeRep` of the argument type `([] |> <*>_N ->_N Sym {alzj}) a_alzd`. This `RuntimeRep` is buried in the from-type of the coercion hole `{alzj}`. We can see in the trace that `{alzj}` has from-type `k_agxC`. Except this has already been filled in with `*`. So the problem is that we haven't zonked yet -- and that's it. `can_eq_nc'` works over non-flat (that is, unzonked) types and also over flat (zonked) types. See `Note [Canonicalising equalities]` immediately above. Your decomposition will work on the zonked types. So returning `Nothing`, as you propose, works, as it forces `can_eq_nc'` to zonk and then try again, succeeding. Is `tcRepSplitTyConApp_maybe` used anywhere else? If so, returning `Nothing` in this case may be wrong.... except that returning `Nothing` in this case makes `tcRepSplitTyConApp_maybe` strictly more well-defined, so I suppose nothing can actually go wrong with this change. A detailed `Note` about the choice for `tcRepSplitTyConApp_maybe` not to panic is called for. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): goldfire, my previous statement claiming that there were only two callsites of `tcRepSplitTyConApp_maybe` was actually blatantly wrong. I neglected to consider the callsite in `tcSplitTyConApp_maybe`, which itself has dozens of sites. It seems like we really will need to have two variants of `tcRepSplitTyConApp_maybe`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by goldfire): Maybe, but not necessarily. After all, the change we're proposing replaces a panic with a `Nothing`. In theory, no code (except the case we've identified in `can_eq_nc'`) should evaluate to the panic, so changing behavior there should have no effect beyond `can_eq_nc'`. However, practice does not always equate to theory, and this choice might change a helpful panic into very obscure behavior. So if the function ''is'' widely used, then I learn more toward the new-ADT approach: define something like {{{#!hs data SplitResult a b = Split a b | NotSplittable | NoRuntimeRep }}} where `NotSplittable` means that the type is a `FunTy` that would ordinarily be splittable, but retrieving the `RuntimeRep` failed. This failure should happen only when a) something is ill-kinded, or b) something needs a good zonk. This new ADT could be used in both `splitTyConApp` and `splitAppTy`. Or here's another approach: you're calling `tcRepSplitTyConApp_maybe`. Note the `tc`. How would we fare if this function were put into the `TcM` monad? Then, if the `RuntimeRep` were unavailable, we could zonk on the fly and succeed. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: bug | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by goldfire): I have a terrible idea. Consider a unification variable (`MetaTv`) `alpha`. After `alpha` is filled in, say with `Int`, GHC should consider `alpha` and `Int` to be the same in all contexts. To achieve this, GHC must be very careful to zonk in just the right places. What if, instead, we use `unsafePerformIO` to zonk on the fly, whenever `coreView` is used? `coreView` looks through type synonyms, so it is currently put wherever we need to know about the "real" type -- in equality checks, splitting, etc. These places seem precisely the places where zonking is important. So we teach `coreView` how to zonk! Or, perhaps, we resurrect `tcView` (which was removed because it was just the same as `coreView`) so that this zonk-on-the-fly behavior happens only in the typechecker. Now, this idea (because it requires `unsafePerformIO`) goes against my grain. But what's actually wrong with it? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13264: GHC panic with (->) generalization branch while compiling lens -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 8.1 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * status: new => closed * resolution: => fixed Comment: This is fixed in the version of my patch which was merged (b207b536ded40156f9adb168565ca78e1eef2c74). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13264#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC