ucsd-progsys / liquidhaskell

Liquid Types For Haskell

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Build LH with GHC 9.4.7

facundominguez opened this issue · comments

Continuing the epic #2184, I'm trying now to build LH with GHC 9.4.7. I have some work in progress in this branch.

liquidhaskell builds, but then trying to build liquid-prelude fails. See the details in a follow up comment. I expect a few more issues that are yet undiscovered to come.

Building a few modules from liquid-prelude fails with the following panic:

$ cabal build -fdevel liquid-prelude
...
<no location info>: error:
    panic! (the 'impossible' happened)
  GHC version 9.4.7:
	lookupIdSubst
  empty
  InScope {k_a1sK $dOrd_a1sL ds_d2f6
           lq_anf$##7205759403792802262_d2fI fromList}
  Call stack:
      CallStack (from HasCallStack):
        callStackDoc, called at compiler/GHC/Utils/Panic.hs:182:37 in ghc:GHC.Utils.Panic
        pprPanic, called at compiler/GHC/Core/Subst.hs:260:17 in ghc:GHC.Core.Subst

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

The complete trace is as follows:
Plugin.hs calls to liquidQuery, which calls to updTargetInfoTermVars, which calls to terminationVars, which calls to failingBinds, which calls to checkBind, which calls to deShadowBind, which calls to deShadowBinds, which calls to substBind, which calls to substExpr, which calls to lookupIdSubst, which panics.

Maybe LH is calling deShadowBinds to rename local variables. But I don't understand exactly why yet. Maybe someone on the LH side can fill in this context.

On the other hand, deShadowBinds is an internal function in GHC that is currently dead code in GHC. So I have no explicit advice on how to call it. Though I would conjecture that the bindings that the assertion reports as missing need to be provided all in one single call to deShadowBinds. This might not have been a problem before because lookupIdSubst didn't use to panic in ghc-9.2, the panic call is new in ghc-9.4.

In the absence of other insights, I'm eliminating the call to deShadowBinds and will see what fails.

Almost there. I have only one testsuite failing: benchmark-vector-algorithms

So far, I haven't encountered any consequences of removing the call to deShadowBinds.

This error seems to be due to the introduction of coercions in the desugaring of

{-@ countLoop :: (v (PrimState m) e) 
              -> count:(PV.MVector (PrimState m) Int) 
              -> (e -> (OkIdx count)) ->  m ()
  @-}
countLoop :: (PrimMonad m, MVector v e)
          => (v (PrimState m) e) -> (PV.MVector (PrimState m) Int) 
          -> (e -> Int) ->  m ()
countLoop src count rdx = set count 0 >> go len 0
 where
 len = length src
 go (m :: Int) i
   | i < len   = let lenSrc = length src 
                 in (unsafeRead src i) >>= inc count . rdx >> go (m-1) (i+1)
   | otherwise = return ()

The error says:

tests/benchmarks/vector-algorithms-0.5.4.2/Data/Vector/Algorithms/Common.hs:80:36: error:
    Liquid Type Mismatch
    .
    The inferred type
      VV : {v : GHC.Types.Int | v == i
                                && v + ?b == vsize src
                                && v >= 0
                                && 0 <= v
                                && v <= vsize src}
    .
    is not a subtype of the required type
      VV : {VV : GHC.Types.Int | VV <= vsize (coerce (v##a1sH s##a1sJ e##a1sI) ~ (v##a1sH (Control.Monad.Primitive.PrimState m##a1tq) e##a1sI) in src) - (0 + 1)}
    .
    in the context
      src : a b c
       
      i : {i : GHC.Types.Int | i + ?b == vsize src
                               && i >= 0
                               && 0 <= i
                               && i <= vsize src}
       
      ?b : {?b : GHC.Types.Int | ?b >= 0
                                 && 0 <= ?b
                                 && ?b <= vsize src}
    Constraint id 44
   |
80 |                  in unsafeRead src i >>= inc count . rdx >> go (m-1) (i+1)
   |                                    ^

And examining the Core does indeed show that ghc-9.4 introduces a cast around the first argument of unsafeRead:

unsafeRead
  @m_a1sY
  @v_a1sd
  @e_a1se
  $dPrimMonad_a1u5
  $dMVector_a1sg
  ((src<tests/benchmarks/vector-algorithms-0.5.4.2/Data/Vector/Algorithms/Common.hs:80:33-35>
      src_a1qn)
    `cast` (<v_a1sd>_R (Sym co_a1uL) <e_a1se>_N
            :: v_a1sd (PrimState m_a1sc) e_a1se
               ~R# v_a1sd (PrimState m_a1sY) e_a1se))
  (src<tests/benchmarks/vector-algorithms-0.5.4.2/Data/Vector/Algorithms/Common.hs:80:37>
     i_a1qt))

I don't know how to fix this yet.

Apparently the coercion in ghc-9.4 is necessary because go doesn't have a type signature, and ghc is generalizing the type of go. Thus, a coercion is needed to say that the m type variable of countLoop is instantiated the same as the universally quantified m type variable of go.

Disabling let generalization with {-# LANGUAGE MonoLocalBinds #-} has the module pass verification.

Another fix is to pass src and count as parameters of go, which also prevents the variable m from being generalized.

I think taming the desugared Core and the inferred type for go with MonoLocalBinds is worth the trouble. However, then we need the user to be aware of the problem for her to be able to use LH.

Maybe you have a different plan to ignore the cast that I’m not following?

Not really. I discarded the idea after writing my suggestion. :)

All tests are passing for me now.

Btw just to be clear we could also just add a type signature for go, Yes?

Indeed. A type signature together with ScopedTypeVariables does also avoid the coercion.