summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2022-12-13 12:30:36 +0000
committerMatthew Pickering <matthewtpickering@gmail.com>2022-12-23 11:22:25 +0000
commit40c9da19decb68e1bf4be6fef7b0592c19a8cacd (patch)
treeda86ac3d580f161cb971bfba6edae205f11a9d7c /compiler/GHC/Tc
parent16a1bcd1d72c7a4567671f6a7f610df3fc477519 (diff)
downloadhaskell-wip/22188.tar.gz
Add flag to control whether self-recompilation information is written to interfacewip/22188
This patch adds the flag -fwrite-self-recomp-info which controls whether interface files contain the information necessary to answer the question: Do I need to recompile myself or is this current interface file suitable? Why? Most packages are only built once either by a distribution or cabal and then placed into an immutable store, after which we will never ask this question. Therefore we can derive two benefits from omitting this information. * Primary motivation: It vastly reduces the surface area for creating non-deterministic interface files. See issue #10424 which motivated a proper fix to that issue. Distributions have long contained versions of GHC which just have broken self-recompilation checking (in order to get deterministic interface files). * Secondary motivation: This reduces the size of interface files slightly.. the `mi_usages` field can be quite big but probably this isn't such a great benefit. * Third motivation: Conceptually clarity about which parts of an interface file are used in order to **communicate** with subsequent packages about the **interface** for a module. And which parts are used to self-communicate during recompilation checking. In addition to this, the change alerted me to the incorrect implemenation of the reifyModule function. See #8489 for more discussion about how to fix this if anyone was so inclined. For now I just added a warning `-Wreify-module-missing-info` which triggers if the module you are trying to reify doesn't have a suitable interface. Interfaces which are unsuitable include: * The GHC.Prim interface, which is a fake interface * Interfaces compiled with -fno-write-self-recomp-info The main tracking issue is #22188 but fixes issues such as #10424 in a proper way.
Diffstat (limited to 'compiler/GHC/Tc')
-rw-r--r--compiler/GHC/Tc/Errors/Ppr.hs6
-rw-r--r--compiler/GHC/Tc/Errors/Types.hs6
-rw-r--r--compiler/GHC/Tc/Gen/Splice.hs21
3 files changed, 30 insertions, 3 deletions
diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs
index 33b75e3eb1..014ffe33c2 100644
--- a/compiler/GHC/Tc/Errors/Ppr.hs
+++ b/compiler/GHC/Tc/Errors/Ppr.hs
@@ -1223,6 +1223,9 @@ instance Diagnostic TcRnMessage where
TcRnSectionWithoutParentheses expr -> mkSimpleDecorated $
hang (text "A section must be enclosed in parentheses")
2 (text "thus:" <+> (parens (ppr expr)))
+ TcRnReifyModuleMissingInfo m -> mkSimpleDecorated $
+ vcat [ (ppr m) <+> text "can't be reified due to missing information in its interface file."
+ , text "Possible cause:" <+> ppr m <+> text "was compiled with -fno-write-self-recomp-info" ]
diagnosticReason = \case
@@ -1628,6 +1631,8 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnIllegalTupleSection{}
-> ErrorWithoutFlag
+ TcRnReifyModuleMissingInfo {} ->
+ WarningWithFlag Opt_WarnReifyModuleMissingInfo
diagnosticHints = \case
TcRnUnknownMessage m
@@ -2037,6 +2042,7 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnIllegalTupleSection{}
-> [suggestExtension LangExt.TupleSections]
+ TcRnReifyModuleMissingInfo {} -> noHints
diagnosticCode = constructorCode
diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs
index 335e7c4965..b7b1a32b87 100644
--- a/compiler/GHC/Tc/Errors/Types.hs
+++ b/compiler/GHC/Tc/Errors/Types.hs
@@ -2762,6 +2762,12 @@ data TcRnMessage where
-}
TcRnSectionWithoutParentheses :: HsExpr GhcPs -> TcRnMessage
+ {-| TcRnReifyModuleMissingInfo is a warning triggered by attempting to
+ call reifyModule on a module whose interface file lacks the necessary information
+ to satisfy the query. This normally occurs when the module is compiled with `-fno-write-self-recomp-info`.
+ -}
+ TcRnReifyModuleMissingInfo:: Module -> TcRnMessage
+
deriving Generic
-- | Things forbidden in @type data@ declarations.
diff --git a/compiler/GHC/Tc/Gen/Splice.hs b/compiler/GHC/Tc/Gen/Splice.hs
index 6ba304be16..3bbe9a9af7 100644
--- a/compiler/GHC/Tc/Gen/Splice.hs
+++ b/compiler/GHC/Tc/Gen/Splice.hs
@@ -2808,6 +2808,10 @@ modToTHMod :: Module -> TH.Module
modToTHMod m = TH.Module (TH.PkgName $ unitString $ moduleUnit m)
(TH.ModName $ moduleNameString $ moduleName m)
+-- | Note that reifyModule will not work if the module is compiled with `-fno-write-self-recomp-info`
+-- because the implementation works by consulting the `mi_usages` field which is intended to be only
+-- used for recompilation checking. See #8489 for a ticket which tracks improvement
+-- of this function.
reifyModule :: TH.Module -> TcM TH.ModuleInfo
reifyModule (TH.Module (TH.PkgName pkgString) (TH.ModName mString)) = do
this_mod <- getModule
@@ -2820,9 +2824,20 @@ reifyModule (TH.Module (TH.PkgName pkgString) (TH.ModName mString)) = do
reifyFromIface reifMod = do
iface <- loadInterfaceForModule (text "reifying module from TH for" <+> ppr reifMod) reifMod
- let usages = [modToTHMod m | usage <- mi_usages iface,
- Just m <- [usageToModule (moduleUnit reifMod) usage] ]
- return $ TH.ModuleInfo usages
+ case mi_self_recomp_info iface of
+ NoSelfRecomp -> do
+ -- Arguably this should fail here but GHC.Prim always has NoSelfRecomp, so
+ -- any existing traversals would just stop working. Now they will start warning
+ -- and a user is expected to add a special case to avoid GHC.Prim in their traversal.
+
+ -- An alternative would be to add that special case for GHC.Prim here and make it a hard
+ -- error if reifyModule was attempted to be used with these partial interface files.
+ addDiagnosticTc (TcRnReifyModuleMissingInfo reifMod)
+ return (TH.ModuleInfo [])
+ ModIfaceSelfRecomp{ mi_sr_usages } -> do
+ let usages = [modToTHMod m | usage <- mi_sr_usages
+ , Just m <- [usageToModule (moduleUnit reifMod) usage] ]
+ return $ TH.ModuleInfo usages
usageToModule :: Unit -> Usage -> Maybe Module
usageToModule _ (UsageFile {}) = Nothing