diff options
author | Matthew Pickering <matthewtpickering@gmail.com> | 2022-02-14 09:23:24 +0000 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-02-26 02:06:51 -0500 |
commit | 61a203ba2e942b39c5f26a7ad01017841937fd0a (patch) | |
tree | e1300c3fc87bdd2d6e24fc2a04fc94cdb07f21ab /compiler/GHC/Tc | |
parent | 75e4e09040862dd12e6960d366868ca8ec434035 (diff) | |
download | haskell-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.hs | 30 |
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 |