summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2022-02-14 09:23:24 +0000
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-02-26 02:06:51 -0500
commit61a203ba2e942b39c5f26a7ad01017841937fd0a (patch)
treee1300c3fc87bdd2d6e24fc2a04fc94cdb07f21ab /compiler/GHC/Tc
parent75e4e09040862dd12e6960d366868ca8ec434035 (diff)
downloadhaskell-61a203ba2e942b39c5f26a7ad01017841937fd0a.tar.gz
Make typechecking unfoldings from interfaces lazier
The old logic was unecessarily strict in loading unfoldings because when reading the unfolding we would case on the result of attempting to load the template before commiting to which type of unfolding we were producing. Hence trying to inspect any of the information about an unfolding would force the template to be loaded. This also removes a potentially hard to discover bug where if the template failed to be typechecked for some reason then we would just not return an unfolding. Instead we now panic so these bad situations which should never arise can be identified.
Diffstat (limited to 'compiler/GHC/Tc')
-rw-r--r--compiler/GHC/Tc/Utils/Monad.hs30
1 files changed, 10 insertions, 20 deletions
diff --git a/compiler/GHC/Tc/Utils/Monad.hs b/compiler/GHC/Tc/Utils/Monad.hs
index a2720bc4e1..75d6491bad 100644
--- a/compiler/GHC/Tc/Utils/Monad.hs
+++ b/compiler/GHC/Tc/Utils/Monad.hs
@@ -136,7 +136,6 @@ module GHC.Tc.Utils.Monad(
initIfaceLoadModule,
getIfModule,
failIfM,
- forkM_maybe,
forkM,
setImplicitEnvM,
@@ -2197,14 +2196,14 @@ failIfM msg = do
-- | Run thing_inside in an interleaved thread.
-- It shares everything with the parent thread, so this is DANGEROUS.
--
--- It returns Nothing if the computation fails
+-- It throws an error if the computation fails
--
-- It's used for lazily type-checking interface
-- signatures, which is pretty benign.
--
--- See Note [Masking exceptions in forkM_maybe]
-forkM_maybe :: SDoc -> IfL a -> IfL (Maybe a)
-forkM_maybe doc thing_inside
+-- See Note [Masking exceptions in forkM]
+forkM :: SDoc -> IfL a -> IfL a
+forkM doc thing_inside
= unsafeInterleaveM $ uninterruptibleMaskM_ $
do { traceIf (text "Starting fork {" <+> doc)
; mb_res <- tryM $
@@ -2212,11 +2211,11 @@ forkM_maybe doc thing_inside
thing_inside
; case mb_res of
Right r -> do { traceIf (text "} ending fork" <+> doc)
- ; return (Just r) }
+ ; return r }
Left exn -> do {
-- Bleat about errors in the forked thread, if -ddump-if-trace is on
-- Otherwise we silently discard errors. Errors can legitimately
- -- happen when compiling interface signatures (see tcInterfaceSigs)
+ -- happen when compiling interface signatures.
whenDOptM Opt_D_dump_if_trace $ do
logger <- getLogger
let msg = hang (text "forkM failed:" <+> doc)
@@ -2225,33 +2224,24 @@ forkM_maybe doc thing_inside
MCFatal
noSrcSpan
$ withPprStyle defaultErrStyle msg
-
; traceIf (text "} ending fork (badly)" <+> doc)
- ; return Nothing }
+ ; pgmError "Cannot continue after interface file error" }
}
-forkM :: SDoc -> IfL a -> IfL a
-forkM doc thing_inside
- = do { mb_res <- forkM_maybe doc thing_inside
- ; return (case mb_res of
- Nothing -> pgmError "Cannot continue after interface file error"
- -- pprPanic "forkM" doc
- Just r -> r) }
-
setImplicitEnvM :: TypeEnv -> IfL a -> IfL a
setImplicitEnvM tenv m = updLclEnv (\lcl -> lcl
{ if_implicits_env = Just tenv }) m
{-
-Note [Masking exceptions in forkM_maybe]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Masking exceptions in forkM]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using GHC-as-API it must be possible to interrupt snippets of code
executed using runStmt (#1381). Since commit 02c4ab04 this is almost possible
by throwing an asynchronous interrupt to the GHC thread. However, there is a
subtle problem: runStmt first typechecks the code before running it, and the
exception might interrupt the type checker rather than the code. Moreover, the
-typechecker might be inside an unsafeInterleaveIO (through forkM_maybe), and
+typechecker might be inside an unsafeInterleaveIO (through forkM), and
more importantly might be inside an exception handler inside that
unsafeInterleaveIO. If that is the case, the exception handler will rethrow the
asynchronous exception as a synchronous exception, and the exception will end