Error retrieving interface file for ghc-prim type
Summary
I'm working on lift-type
, which provides a function liftType :: Typeable a => TemplateHaskell.Type
, as part of working on discover-instances
. I ran into a bug in discover-instances
where polykinded classes (ie class TypeScript (a :: k) where ...
break the library. I determined that I can't discover all kinds of instances, but I can pick a single kind. $$(discoverInstances @(TypeScript :: Type -> Constraint))
works fine, for example.
In chasing it down, I determined that I needed to use lift-type
to turn the provided kind into a Type
so I can pass it to discoverInstances
. Instead of providing [VarT (mkName "a")]
, I need to provide reifyInstances cls [SigT (VarT (mkName "a")) (liftType @Data.Kind.Type)]
.
When I do that, however, I get a GHC error:
/home/matt/Projects/lift-type/test/Spec.hs:12:34: error:
• Can't find interface-file declaration for data constructor ghc-prim-0.6.1:GHC.Prim.LiftedRep
Probable cause: bug in .hi-boot file, or inconsistent .hi file
Use -ddump-if-trace to get an idea of which file caused the error
• In the first argument of ‘TYPE’, namely
‘'ghc-prim-0.6.1:GHC.Prim.LiftedRep’
In the first argument of ‘Proxy’, namely
‘(TYPE 'ghc-prim-0.6.1:GHC.Prim.LiftedRep)’
In an expression type signature:
Proxy (TYPE 'ghc-prim-0.6.1:GHC.Prim.LiftedRep)
|
12 | type_ = Proxy :: Proxy $(liftTypeQ @Type)
| ^^^^^^^^^^^^^^^
With -ddump-splices
, I get this:
/home/matt/Projects/lift-type/test/Spec.hs:14:34-48: Splicing type
liftTypeQ @Type ======> TYPE 'ghc-prim-0.6.1:GHC.Prim.LiftedRep
The code that produces it is here:
mk :: TyCon -> Type
mk tyCon =
let
tcName =
tyConName tyCon
trySymbol =
case tcName of
'"' : cs ->
Just $ LitT (StrTyLit (zipWith const cs (drop 1 cs)))
_ ->
Nothing
tryTicked =
case tcName of
'\'' : dcName ->
let nameBase =
mkOccName dcName
flavor =
NameG
DataName
(mkPkgName $ tyConPackage tyCon)
(mkModName $ tyConModule tyCon)
name =
Name
nameBase
flavor
in
Just (PromotedT name)
_ ->
Nothing
tryNat =
LitT . NumTyLit <$> readMaybe tcName
plainType =
let
nameBase =
mkOccName tcName
flavor =
NameG
TcClsName
(mkPkgName $ tyConPackage tyCon)
(mkModName $ tyConModule tyCon)
name =
Name
nameBase
flavor
in
ConT name
in fromMaybe plainType $ asum [tryTicked, trySymbol, tryNat]
It's taking the tryTicked
path, which constructs the NameG DataName pkgName modName
for TemplateHaskell
to work with non-imported terms.
I've worked around this by introducing this case:
go :: forall k (a :: k). TypeRep a -> Type
go tr
| Just HRefl <- eqTypeRep (typeRep @Kind.Type) tr
= ConT ''Kind.Type
| otherwise =
However, that's brittle, and won't work for other kinds than just Type
, and it introduces a performance impact.
Steps to reproduce
git clone git@github.com:parsonsmatt/lift-type
cd lift-type
git checkout mattp/demonstrate-interface-bug
cabal test
Expected behavior
I would expect the built-in types to work as well as the regular ones.
For what it's worth, liftType @Word#
works fine, so it's not only an issue wiht built-in types
Environment
- GHC version used: 8.10 and 9.4 (but CI shows it break in many ghcs: https://github.com/parsonsmatt/lift-type/pull/10)
Optional:
- Operating System: Ubuntu
- System Architecture: x86-64