[GHC] #15725: Core Lint error: Trans coercion mis-match

GHC ghc-devs at haskell.org
Tue Oct 9 17:49:21 UTC 2018


#15725: Core Lint error: Trans coercion mis-match
-------------------------------------+-------------------------------------
        Reporter:  RyanGlScott       |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.8.1
       Component:  Compiler          |              Version:  8.6.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Compile-time      |  Unknown/Multiple
  crash or panic                     |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #15703            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by RyanGlScott):

 After much digging this morning, I've finally found my way out of this
 rabbit hole. It turns out that the culprit is the
 [http://git.haskell.org/ghc.git/blob/d728c3c578cc9e9205def2c1e96934487b364b7b:/compiler/types/OptCoercion.hs#l375
 InstCo] case of `opt_co4`:

 {{{#!hs
 -- See Note [Optimising InstCo]
 opt_co4 env sym rep r (InstCo co1 arg)
     -- forall over type...
   | Just (tv, kind_co, co_body) <- splitForAllCo_ty_maybe co1
   = opt_co4_wrap (extendLiftingContext env tv
                     (mkCoherenceRightCo Nominal t2 (mkSymCo kind_co)
 arg'))
                    -- kind_co :: k1 ~ k2
                    -- arg' :: (t1 :: k1) ~ (t2 :: k2)
                    -- tv |-> (t1 :: k1) ~ (((t2 :: k2) |> (sym kind_co))
 :: k1)
                  sym rep r co_body
 }}}

 In particular, the bug lies within an optimization where `co1` is of the
 form `forall (tv :: kind_co). co_body`, as explained in `Note [Optimising
 InstCo]`. As explained in the comment, we need to extend the
 `LiftingContext` such that `tv` maps to `(t1 :: k1) ~ (((t2 :: k2) |> (sym
 kind_co)) :: k1)`, which we accomplish by way of `mkCoherenceRightCo`.

 The
 [http://git.haskell.org/ghc.git/blob/4eeeb51d5f51083d0ae393009a7fd246223e9791:/compiler/types/Coercion.hs#l1087
 Haddocks] state that given `mkCoherenceRightCo r ty co co2`, the following
 invariants must hold:

 {{{
 ty  :: k1
 co  :: k1 ~ k2
 co2 :: ty' ~ ty
 }}}

 That is, it must be the case that `typeKind ty ~ fst (coercionKind co)`
 and `ty ~ snd (coercionKind co2)`.

 Through some `pprTrace` sleuthing, I discovered that these were the things
 being used to instantiate `ty`, `co`, and `co2`, respectively:

 {{{
 ty  = t2              = (From1 Identity a x |> D:R:Rep1Identity[0] <a>_N)
 :: Par1 a
 co  = mkSymCo kind_co = Sym (Sym (D:R:Rep1Identity[0]) <a>_N)
 :: Rep1 Identity a ~ Par1 a
 co2 = arg'            = GRefl nominal (From1 Identity a x)
 (D:R:Rep1Identity[0] <a>_N) :: From1 Identity a x ~ (From1 Identity a x |>
 D:R:Rep1Identity[0] <a>_N)
 }}}

 This does uphold the invariant that `ty ~ snd (coercionKind co2)`, but it
 does //not// uphold the invariant that `typeKind ty ~ fst (coercionKind
 co)`, since:

 * `typeKind ty           ~ Par1 a`
 * `fst (coercionKind co) ~ Rep1 Identity a`

 My best guess as to why this happens is that `arg'` is computed
 [http://git.haskell.org/ghc.git/blob/d728c3c578cc9e9205def2c1e96934487b364b7b:/compiler/types/OptCoercion.hs#l414
 like so]:

 {{{#!hs
     arg' = opt_co4_wrap env sym False Nominal arg
 }}}

 In particular, we pass `opt_co4_wrap` the `sym` flag which, in the program
 above, happens to be `True`, so an outer `Sym` is applied to the result of
 the whole optimized coercion. `mkSymCo kind_co`, on the other hand, was
 not the result of calling `opt_co4_wrap env sym` (since it comes from
 `co1`, not `co1'`), which means that it does //not// have the same outer
 `Sym` that `arg'` has. This causes a "polarity mismatch" between the two,
 leading to disaster.

 Here is one way to fix this issue:

 {{{#!diff
 diff --git a/compiler/types/OptCoercion.hs b/compiler/types/OptCoercion.hs
 index 8a44b86..c52e11e 100644
 --- a/compiler/types/OptCoercion.hs
 +++ b/compiler/types/OptCoercion.hs
 @@ -377,7 +377,7 @@ opt_co4 env sym rep r (InstCo co1 arg)
      -- forall over type...
    | Just (tv, kind_co, co_body) <- splitForAllCo_ty_maybe co1
    = opt_co4_wrap (extendLiftingContext env tv
 -                    (mkCoherenceRightCo Nominal t2 (mkSymCo kind_co)
 arg'))
 +                    (mkCoherenceRightCo Nominal t2 (mkSymCo kind_co)
 sym_arg'))
                     -- kind_co :: k1 ~ k2
                     -- arg' :: (t1 :: k1) ~ (t2 :: k2)
                     -- tv |-> (t1 :: k1) ~ (((t2 :: k2) |> (sym kind_co))
 :: k1)
 @@ -396,14 +396,14 @@ opt_co4 env sym rep r (InstCo co1 arg)
      -- forall over type...
    | Just (tv', kind_co', co_body') <- splitForAllCo_ty_maybe co1'
    = opt_co4_wrap (extendLiftingContext (zapLiftingContext env) tv'
 -                    (mkCoherenceRightCo Nominal t2 (mkSymCo kind_co')
 arg'))
 +                    (mkCoherenceRightCo Nominal t2' (mkSymCo kind_co')
 arg'))
              False False r' co_body'

      -- forall over coercion...
    | Just (cv', kind_co', co_body') <- splitForAllCo_co_maybe co1'
 -  , CoercionTy h1 <- t1
 -  , CoercionTy h2 <- t2
 -  = let new_co = mk_new_co cv' kind_co' h1 h2
 +  , CoercionTy h1' <- t1'
 +  , CoercionTy h2' <- t2'
 +  = let new_co = mk_new_co cv' kind_co' h1' h2'
      in opt_co4_wrap (extendLiftingContext (zapLiftingContext env) cv'
 new_co)
                      False False r' co_body'

 @@ -412,7 +412,9 @@ opt_co4 env sym rep r (InstCo co1 arg)
      co1' = opt_co4_wrap env sym rep r co1
      r'   = chooseRole rep r
      arg' = opt_co4_wrap env sym False Nominal arg
 -    Pair t1 t2 = coercionKind arg'
 +    sym_arg'     = wrapSym sym arg'
 +    Pair t1  t2  = coercionKind sym_arg'
 +    Pair t1' t2' = coercionKind arg'

      mk_new_co cv kind_co h1 h2
        = let -- h1 :: (t1 ~ t2)
 }}}

 Essentially, we wrap `arg'` with another `Sym` to cancel out an extra
 `Sym` that `opt_co4_wrap env sym` might provide. Of course, this should
 only apply to the two cases where we inspect `co1` (which did not come
 from `opt_co4_wrap`); for the two cases where we instead inspect `co1'`,
 we continue to use plain old `arg'`.

 Patch incoming.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15725#comment:3>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list