Silent failure with `reifyInstances` in a TH block if class not in scope
Summary
This is a bit tricky. The code in question uses the discover-instances
library.
Consider the following code:
module Class where
import DiscoverInstances
import Language.Haskell.TH
class C a where
c :: proxy a -> Int
blah :: [SomeDict C] -> IO ()
blah dicts = putStrLn "hello world"
In "real code", the blah
function will do something real and useful with the [SomeDict C]
parameter. But in this example, we're just using it to drive type inference.
module Foo where
import Class
data Foo = Foo
instance Class Foo where c _ = 1
{-# LANGUAGE TemplateHaskell #-}
module Lib where
import Foo
import Class (blah)
import DiscoverInstances
import Language.Haskell.TH
$(do
runIO $ blah $$discoverInstances
pure []
)
When compiling these modules, GHC dies without any warning at all. I've tested this on GHC 8.10 and GHC 9.0, but constraints
fails to build on GHC 9.2 so I don't have an easy reproduction on that.
This is the output when the offending code is run in TemplateHaskell
:
λ ~/Projects/disc-inst-bug/ cabal build
Build profile: -w ghc-9.0.1 -O1
In order, the following will be built (use -v for more details):
- disc-inst-bug-0.1.0.0 (lib) (first run)
- disc-inst-bug-0.1.0.0 (exe:disc-inst-bug-exe) (first run)
Preprocessing library for disc-inst-bug-0.1.0.0..
Building library for disc-inst-bug-0.1.0.0..
[3 of 4] Compiling Lib ( src/Lib.hs, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.o, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.dyn_o )
cabal: Failed to build disc-inst-bug-0.1.0.0 (which is required by
exe:disc-inst-bug-exe from disc-inst-bug-0.1.0.0).
Compiling with --verbose
doesn't provide more useful information.
λ ~/Projects/disc-inst-bug/ master* cabal build --verbose
this build was affected by the following (project) config files:
Build profile: -w ghc-9.0.1 -O1
In order, the following will be built:
- disc-inst-bug-0.1.0.0 (lib) (first run)
- disc-inst-bug-0.1.0.0 (exe:disc-inst-bug-exe) (first run)
creating /home/matt/Projects/disc-inst-bug/dist-newstyle/build
creating /home/matt/Projects/disc-inst-bug/dist-newstyle/tmp
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/cache
Using self-exec internal setup method with build-type Simple and args:
["act-as-setup","--build-type=Simple","--","build","--verbose=2","--builddir=/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0"]
/home/matt/.ghcup/bin/cabal-3.0.0.0 act-as-setup --build-type=Simple -- build
--verbose=2
--builddir=/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0
Component build order: library
/home/matt/.ghcup/bin/ghc-pkg init /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/package.conf.inplace
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/autogen
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/autogen
Preprocessing library for disc-inst-bug-0.1.0.0..
Building library for disc-inst-bug-0.1.0.0..
creating
/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build
/home/matt/.ghcup/bin/ghc --make -fbuilding-cabal-package -O -static -dynamic-too -dynosuf dyn_o -dynhisuf dyn_hi -outputdir /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -odir /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -hidir /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -stubdir /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -i -i/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -isrc -i/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/autogen -i/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/global-autogen -I/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/autogen -I/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/global-autogen -I/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build -optP-include -optP/home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/autogen/cabal_macros.h -this-unit-id disc-inst-bug-0.1.0.0-inplace -hide-all-packages -Wmissing-home-modules -no-user-package-db -package-db /home/matt/.cabal/store/ghc-9.0.1/package.db -package-db /home/matt/Projects/disc-inst-bug/dist-newstyle/packagedb/ghc-9.0.1 -package-db /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/package.conf.inplace -package-id base-4.15.0.0 -package-id discover-instances-0.1.0.0-4126b33401c84f8b3e0134b159298025056eca1769e16abd71aa53048325d16d -package-id template-haskell-2.17.0.0 -XHaskell2010 Class Instance Lib Paths_disc_inst_bug -hide-all-packages
[3 of 4] Compiling Lib ( src/Lib.hs, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.o, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.dyn_o )
CallStack (from HasCallStack):
die', called at ./Distribution/Client/ProjectOrchestration.hs:1035:55 in main:Distribution.Client.ProjectOrchestration
cabal: Failed to build disc-inst-bug-0.1.0.0-inplace.
Failed to build disc-inst-bug-0.1.0.0 because it depends on
disc-inst-bug-0.1.0.0 which itself failed to build.
If you write blah $$discoverInstances
outside of a TemplateHaskell
splice, then you get an error message.
{-# LANGUAGE TemplateHaskell #-}
module Lib where
import Foo
import Class (blah)
import DiscoverInstances
import Language.Haskell.TH
someFunc :: IO ()
someFunc =
blah $$discoverInstances
This fails with:
[3 of 4] Compiling Lib ( src/Lib.hs, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.o, /home/matt/Projects/disc-inst-bug/dist-newstyle/build/x86_64-linux/ghc-9.0.1/disc-inst-bug-0.1.0.0/build/Lib.dyn_o )
src/Lib.hs:12:22: error:
• Not in scope: type constructor or class ‘C’
Perhaps you want to add ‘C’ to the import list in the import of
‘Class’ (src/Lib.hs:7:1-29).
• In the argument of reifyInstances: C a
In the Template Haskell splice $$discoverInstances
In the first argument of ‘printInstances’, namely
‘$$discoverInstances’
|
12 | printInstances $$discoverInstances
| ^^^^^^^^^^^^^^^^^
cabal: Failed to build disc-inst-bug-0.1.0.0 (which is required by
exe:disc-inst-bug-exe from disc-inst-bug-0.1.0.0).
So, what appears to be happening here:
- I have
discoverInstances :: forall (c :: _ -> Constraint). Q (TExp [SomeDict c])
- I have
blah :: [SomeDict C] -> IO ()
- So GHC can infer that
blah $$discoverInstances
is supposed to selectc ~ C
, and then$$(discoverInstances :: Q (TExp [SomeDict C]))
. - But then GHC complains that
C
is not in scope at the call toreifyInstances
- And somehow this error is swallowed by
TemplateHaskell
.
Steps to reproduce
This repository contains everything you need to reproduce the issue.
Expected behavior
I expect the error message to be present even when the code snippet is used in Template Haskell.
Environment
- GHC version used: 8.10, 9.0
Optional:
- Operating System: Ubuntu
- System Architecture: x86