diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2020-04-30 11:07:15 -0400 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-06-04 04:34:42 -0400 |
commit | 32a4ae90b50cc56f2955f489ad0cf8c7ff5e131a (patch) | |
tree | 274e86d49420a09eb8400bc3751c55f827ed4e56 /compiler | |
parent | cb5c31b51b021ce86890bba73276fe6f7405f5d3 (diff) | |
download | haskell-32a4ae90b50cc56f2955f489ad0cf8c7ff5e131a.tar.gz |
Clean up boot vs non-boot disambiguating types
We often have (ModuleName, Bool) or (Module, Bool) pairs for "extended"
module names (without or with a unit id) disambiguating boot and normal
modules. We think this is important enough across the compiler that it
deserves a new nominal product type. We do this with synnoyms and a
functor named with a `Gen` prefix, matching other newly created
definitions.
It was also requested that we keep custom `IsBoot` / `NotBoot` sum type.
So we have it too. This means changing many the many bools to use that
instead.
Updates `haddock` submodule.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Driver/Backpack.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Driver/Make.hs | 177 | ||||
-rw-r--r-- | compiler/GHC/Driver/MakeFile.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Driver/Types.hs | 45 | ||||
-rw-r--r-- | compiler/GHC/Hs/ImpExp.hs | 10 | ||||
-rw-r--r-- | compiler/GHC/HsToCore/Monad.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/HsToCore/Usage.hs | 7 | ||||
-rw-r--r-- | compiler/GHC/Iface/Load.hs | 26 | ||||
-rw-r--r-- | compiler/GHC/Iface/Recomp.hs | 12 | ||||
-rw-r--r-- | compiler/GHC/IfaceToCore.hs | 28 | ||||
-rw-r--r-- | compiler/GHC/Parser.y | 14 | ||||
-rw-r--r-- | compiler/GHC/Parser/Header.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Rename/Env.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Rename/Names.hs | 28 | ||||
-rw-r--r-- | compiler/GHC/Runtime/Linker.hs | 13 | ||||
-rw-r--r-- | compiler/GHC/Tc/Module.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Tc/Types.hs | 27 | ||||
-rw-r--r-- | compiler/GHC/Tc/Utils/Backpack.hs | 8 | ||||
-rw-r--r-- | compiler/GHC/Tc/Utils/Monad.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/Unit/Module.hs | 12 | ||||
-rw-r--r-- | compiler/GHC/Unit/Module/Location.hs | 9 | ||||
-rw-r--r-- | compiler/GHC/Unit/Types.hs | 70 |
23 files changed, 316 insertions, 196 deletions
diff --git a/compiler/GHC.hs b/compiler/GHC.hs index 759dda29e6..442fd0a323 100644 --- a/compiler/GHC.hs +++ b/compiler/GHC.hs @@ -936,7 +936,7 @@ getModSummary mod = do mg <- liftM hsc_mod_graph getSession let mods_by_name = [ ms | ms <- mgModSummaries mg , ms_mod_name ms == mod - , not (isBootSummary ms) ] + , isBootSummary ms == NotBoot ] case mods_by_name of [] -> do dflags <- getDynFlags liftIO $ throwIO $ mkApiErr dflags (text "Module not part of module graph") diff --git a/compiler/GHC/Driver/Backpack.hs b/compiler/GHC/Driver/Backpack.hs index 7bae489f22..5d5be6c1ff 100644 --- a/compiler/GHC/Driver/Backpack.hs +++ b/compiler/GHC/Driver/Backpack.hs @@ -772,7 +772,7 @@ hsModuleToModSummary pn hsc_src modname hie_timestamp <- liftIO $ modificationTimeIfExists (ml_hie_file location) -- Also copied from 'getImports' - let (src_idecls, ord_idecls) = partition (ideclSource.unLoc) imps + let (src_idecls, ord_idecls) = partition ((== IsBoot) . ideclSource . unLoc) imps -- GHC.Prim doesn't exist physically, so don't go looking for it. ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc . ideclName . unLoc) diff --git a/compiler/GHC/Driver/Make.hs b/compiler/GHC/Driver/Make.hs index 43c988c4c2..a3d2c0b1bb 100644 --- a/compiler/GHC/Driver/Make.hs +++ b/compiler/GHC/Driver/Make.hs @@ -21,14 +21,14 @@ module GHC.Driver.Make ( ms_home_srcimps, ms_home_imps, - IsBoot(..), summariseModule, hscSourceToIsBoot, findExtraSigImports, implicitRequirements, noModError, cyclicModuleErr, - moduleGraphNodes, SummaryNode + moduleGraphNodes, SummaryNode, + IsBootInterface(..) ) where #include "HsVersions.h" @@ -378,7 +378,7 @@ load' how_much mHscMessage mod_graph = do -- (see msDeps) let all_home_mods = mkUniqSet [ ms_mod_name s - | s <- mgModSummaries mod_graph, not (isBootSummary s)] + | s <- mgModSummaries mod_graph, isBootSummary s == NotBoot] -- TODO: Figure out what the correct form of this assert is. It's violated -- when you have HsBootMerge nodes in the graph: then you'll have hs-boot -- files without corresponding hs files. @@ -930,23 +930,26 @@ buildCompGraph (scc:sccs) = case scc of return ((ms,mvar,log_queue):rest, cycle) CyclicSCC mss -> return ([], Just mss) --- A Module and whether it is a boot module. -type BuildModule = (Module, IsBoot) - --- | 'Bool' indicating if a module is a boot module or not. We need to treat --- boot modules specially when building compilation graphs, since they break --- cycles. Regular source files and signature files are treated equivalently. -data IsBoot = NotBoot | IsBoot - deriving (Ord, Eq, Show, Read) - --- | Tests if an 'HscSource' is a boot file, primarily for constructing --- elements of 'BuildModule'. -hscSourceToIsBoot :: HscSource -> IsBoot +-- | A Module and whether it is a boot module. +-- +-- We need to treat boot modules specially when building compilation graphs, +-- since they break cycles. Regular source files and signature files are treated +-- equivalently. +type BuildModule = ModuleWithIsBoot + +-- | Tests if an 'HscSource' is a boot file, primarily for constructing elements +-- of 'BuildModule'. We conflate signatures and modules because they are bound +-- in the same namespace; only boot interfaces can be disambiguated with +-- `import {-# SOURCE #-}`. +hscSourceToIsBoot :: HscSource -> IsBootInterface hscSourceToIsBoot HsBootFile = IsBoot hscSourceToIsBoot _ = NotBoot mkBuildModule :: ModSummary -> BuildModule -mkBuildModule ms = (ms_mod ms, if isBootSummary ms then IsBoot else NotBoot) +mkBuildModule ms = GWIB + { gwib_mod = ms_mod ms + , gwib_isBoot = isBootSummary ms + } -- | The entry point to the parallel upsweep. -- @@ -1014,12 +1017,12 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do -- NB: For convenience, the last module of each loop (aka the module that -- finishes the loop) is prepended to the beginning of the loop. let graph = map fstOf3 (reverse comp_graph) - boot_modules = mkModuleSet [ms_mod ms | ms <- graph, isBootSummary ms] + boot_modules = mkModuleSet [ms_mod ms | ms <- graph, isBootSummary ms == IsBoot] comp_graph_loops = go graph boot_modules where - remove ms bm - | isBootSummary ms = delModuleSet bm (ms_mod ms) - | otherwise = bm + remove ms bm = case isBootSummary ms of + IsBoot -> delModuleSet bm (ms_mod ms) + NotBoot -> bm go [] _ = [] go mg@(ms:mss) boot_modules | Just loop <- getModLoop ms mg (`elemModuleSet` boot_modules) @@ -1193,9 +1196,13 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags mHscMessage cleanup let home_src_imps = map unLoc $ ms_home_srcimps mod -- All the textual imports of this module. - let textual_deps = Set.fromList $ mapFst (mkModule (thisPackage lcl_dflags)) $ - zip home_imps (repeat NotBoot) ++ - zip home_src_imps (repeat IsBoot) + let textual_deps = Set.fromList $ + zipWith f home_imps (repeat NotBoot) ++ + zipWith f home_src_imps (repeat IsBoot) + where f mn isBoot = GWIB + { gwib_mod = mkModule (thisPackage lcl_dflags) mn + , gwib_isBoot = isBoot + } -- Dealing with module loops -- ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1301,8 +1308,8 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags mHscMessage cleanup -- SCCs include the loop closer, so we have to filter -- it out. Just loop -> typecheckLoop lcl_dflags lcl_hsc_env' $ - filter (/= moduleName (fst this_build_mod)) $ - map (moduleName . fst) loop + filter (/= moduleName (gwib_mod this_build_mod)) $ + map (moduleName . gwib_mod) loop -- Compile the module. mod_info <- upsweep_mod lcl_hsc_env'' mHscMessage old_hpt stable_mods @@ -1315,7 +1322,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags mHscMessage cleanup let this_mod = ms_mod_name mod -- Prune the old HPT unless this is an hs-boot module. - unless (isBootSummary mod) $ + unless (isBootSummary mod == IsBoot) $ atomicModifyIORef' old_hpt_var $ \old_hpt -> (delFromHpt old_hpt this_mod, ()) @@ -1331,7 +1338,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags mHscMessage cleanup hsc_env'' <- case finish_loop of Nothing -> return hsc_env' Just loop -> typecheckLoop lcl_dflags hsc_env' $ - map (moduleName . fst) loop + map (moduleName . gwib_mod) loop return (hsc_env'', localize_hsc_env hsc_env'') -- Clean up any intermediate files. @@ -1491,8 +1498,9 @@ upsweep mHscMessage old_hpt stable_mods cleanup sccs = do -- main Haskell source file. Deleting it -- would force the real module to be recompiled -- every time. - old_hpt1 | isBootSummary mod = old_hpt - | otherwise = delFromHpt old_hpt this_mod + old_hpt1 = case isBootSummary mod of + IsBoot -> old_hpt + NotBoot -> delFromHpt old_hpt this_mod done' = extendMG done mod @@ -1596,10 +1604,10 @@ upsweep_mod hsc_env mHscMessage old_hpt (stable_obj, stable_bco) summary mod_ind mb_old_iface = case old_hmi of - Nothing -> Nothing - Just hm_info | isBootSummary summary -> Just iface - | not (mi_boot iface) -> Just iface - | otherwise -> Nothing + Nothing -> Nothing + Just hm_info | isBootSummary summary == IsBoot -> Just iface + | mi_boot iface == NotBoot -> Just iface + | otherwise -> Nothing where iface = hm_iface hm_info @@ -1823,7 +1831,7 @@ reTypecheckLoop hsc_env ms graph | Just loop <- getModLoop ms mss appearsAsBoot -- SOME hs-boot files should still -- get used, just not the loop-closer. - , let non_boot = filter (\l -> not (isBootSummary l && + , let non_boot = filter (\l -> not (isBootSummary l == IsBoot && ms_mod l == ms_mod ms)) loop = typecheckLoop (hsc_dflags hsc_env) hsc_env (map ms_mod_name non_boot) | otherwise @@ -1874,7 +1882,7 @@ getModLoop -> (Module -> Bool) -- check if a module appears as a boot module in 'graph' -> Maybe [ModSummary] getModLoop ms graph appearsAsBoot - | not (isBootSummary ms) + | isBootSummary ms == NotBoot , appearsAsBoot this_mod , let mss = reachableBackwards (ms_mod_name ms) graph = Just mss @@ -1974,14 +1982,23 @@ moduleGraphNodes drop_hs_boot_nodes summaries = numbered_summaries = zip summaries [1..] lookup_node :: HscSource -> ModuleName -> Maybe SummaryNode - lookup_node hs_src mod = Map.lookup (mod, hscSourceToIsBoot hs_src) node_map + lookup_node hs_src mod = Map.lookup + GWIB + { gwib_mod = mod + , gwib_isBoot = hscSourceToIsBoot hs_src + } + node_map lookup_key :: HscSource -> ModuleName -> Maybe Int lookup_key hs_src mod = fmap summaryNodeKey (lookup_node hs_src mod) node_map :: NodeMap SummaryNode - node_map = Map.fromList [ ((moduleName (ms_mod s), - hscSourceToIsBoot (ms_hsc_src s)), node) + node_map = Map.fromList [ ( GWIB + { gwib_mod = moduleName $ ms_mod s + , gwib_isBoot = hscSourceToIsBoot $ ms_hsc_src s + } + , node + ) | node <- nodes , let s = summaryNodeSummary node ] @@ -1990,7 +2007,7 @@ moduleGraphNodes drop_hs_boot_nodes summaries = nodes = [ DigraphNode s key out_keys | (s, key) <- numbered_summaries -- Drop the hi-boot ones if told to do so - , not (isBootSummary s && drop_hs_boot_nodes) + , not (isBootSummary s == IsBoot && drop_hs_boot_nodes) , let out_keys = out_edge_keys hs_boot_key (map unLoc (ms_home_srcimps s)) ++ out_edge_keys HsSrcFile (map unLoc (ms_home_imps s)) ++ (-- see [boot-edges] below @@ -2015,17 +2032,20 @@ moduleGraphNodes drop_hs_boot_nodes summaries = out_edge_keys :: HscSource -> [ModuleName] -> [Int] out_edge_keys hi_boot ms = mapMaybe (lookup_key hi_boot) ms -- If we want keep_hi_boot_nodes, then we do lookup_key with - -- IsBoot; else NotBoot + -- IsBoot; else False -- The nodes of the graph are keyed by (mod, is boot?) pairs -- NB: hsig files show up as *normal* nodes (not boot!), since they don't -- participate in cycles (for now) -type NodeKey = (ModuleName, IsBoot) +type NodeKey = ModuleNameWithIsBoot type NodeMap a = Map.Map NodeKey a msKey :: ModSummary -> NodeKey msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot }) - = (moduleName mod, hscSourceToIsBoot boot) + = GWIB + { gwib_mod = moduleName mod + , gwib_isBoot = hscSourceToIsBoot boot + } mkNodeMap :: [ModSummary] -> NodeMap ModSummary mkNodeMap summaries = Map.fromList [ (msKey s, s) | s <- summaries] @@ -2143,7 +2163,7 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots dup_roots :: [[ModSummary]] -- Each at least of length 2 dup_roots = filterOut isSingleton $ map rights $ nodeMapElts root_map - loop :: [(Located ModuleName,IsBoot)] + loop :: [GenWithIsBoot (Located ModuleName)] -- Work list: process these modules -> NodeMap [Either ErrorMessages ModSummary] -- Visited set; the range is a list because @@ -2152,7 +2172,7 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots -> IO (NodeMap [Either ErrorMessages ModSummary]) -- The result is the completed NodeMap loop [] done = return done - loop ((wanted_mod, is_boot) : ss) done + loop (s : ss) done | Just summs <- Map.lookup key done = if isSingleton summs then loop ss done @@ -2170,7 +2190,12 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots loop (calcDeps s) (Map.insert key [Right s] done) loop ss new_map where - key = (unLoc wanted_mod, is_boot) + GWIB { gwib_mod = L loc mod, gwib_isBoot = is_boot } = s + wanted_mod = L loc mod + key = GWIB + { gwib_mod = unLoc wanted_mod + , gwib_isBoot = is_boot + } -- | Update the every ModSummary that is depended on -- by a module that needs template haskell. We enable codegen to @@ -2206,7 +2231,7 @@ enableCodeGenForUnboxedTuplesOrSums = condition ms = unboxed_tuples_or_sums (ms_hspp_opts ms) && not (gopt Opt_ByteCode (ms_hspp_opts ms)) && - not (isBootSummary ms) + (isBootSummary ms == NotBoot) unboxed_tuples_or_sums d = xopt LangExt.UnboxedTuples d || xopt LangExt.UnboxedSums d should_modify (ModSummary { ms_hspp_opts = dflags }) = @@ -2281,10 +2306,11 @@ enableCodeGenWhen condition should_modify staticLife dynLife target nodemap = -- If a module imports a boot module, msDeps helpfully adds a -- dependency to that non-boot module in it's result. This -- means we don't have to think about boot modules here. - | (L _ mn, NotBoot) <- msDeps ms - , dep_ms <- - toList (Map.lookup (mn, NotBoot) nodemap) >>= toList >>= - toList + | dep <- msDeps ms + , NotBoot == gwib_isBoot dep + , dep_ms_0 <- toList $ Map.lookup (unLoc <$> dep) nodemap + , dep_ms_1 <- toList $ dep_ms_0 + , dep_ms <- toList $ dep_ms_1 ] new_marked_mods = Set.insert ms_mod marked_mods in foldl' go new_marked_mods deps @@ -2302,10 +2328,16 @@ mkRootMap summaries = Map.insertListWith (flip (++)) -- modules always contains B.hs if it contains B.hs-boot. -- Remember, this pass isn't doing the topological sort. It's -- just gathering the list of all relevant ModSummaries -msDeps :: ModSummary -> [(Located ModuleName, IsBoot)] -msDeps s = - concat [ [(m,IsBoot), (m,NotBoot)] | m <- ms_home_srcimps s ] - ++ [ (m,NotBoot) | m <- ms_home_imps s ] +msDeps :: ModSummary -> [GenWithIsBoot (Located ModuleName)] +msDeps s = [ d + | m <- ms_home_srcimps s + , d <- [ GWIB { gwib_mod = m, gwib_isBoot = IsBoot } + , GWIB { gwib_mod = m, gwib_isBoot = NotBoot } + ] + ] + ++ [ GWIB { gwib_mod = m, gwib_isBoot = NotBoot } + | m <- ms_home_imps s + ] ----------------------------------------------------------------------------- -- Summarising modules @@ -2392,7 +2424,7 @@ findSummaryBySourceFile summaries file (x:_) -> Just x checkSummaryTimestamp - :: HscEnv -> DynFlags -> Bool -> IsBoot + :: HscEnv -> DynFlags -> Bool -> IsBootInterface -> (UTCTime -> IO (Either e ModSummary)) -> ModSummary -> ModLocation -> UTCTime -> IO (Either e ModSummary) @@ -2433,7 +2465,7 @@ checkSummaryTimestamp summariseModule :: HscEnv -> NodeMap ModSummary -- Map of old summaries - -> IsBoot -- IsBoot <=> a {-# SOURCE #-} import + -> IsBootInterface -- True <=> a {-# SOURCE #-} import -> Located ModuleName -- Imported module to be summarised -> Bool -- object code allowed? -> Maybe (StringBuffer, UTCTime) @@ -2445,7 +2477,9 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod) | wanted_mod `elem` excl_mods = return Nothing - | Just old_summary <- Map.lookup (wanted_mod, is_boot) old_summary_map + | Just old_summary <- Map.lookup + (GWIB { gwib_mod = wanted_mod, gwib_isBoot = is_boot }) + old_summary_map = do -- Find its new timestamp; all the -- ModSummaries in the old map have valid ml_hs_files let location = ms_location old_summary @@ -2491,8 +2525,9 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod) just_found location mod = do -- Adjust location to point to the hs-boot source file, -- hi file, object file, when is_boot says so - let location' | IsBoot <- is_boot = addBootSuffixLocn location - | otherwise = location + let location' = case is_boot of + IsBoot -> addBootSuffixLocn location + NotBoot -> location src_fn = expectJust "summarise2" (ml_hs_file location') -- Check that it exists @@ -2514,10 +2549,10 @@ summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod) -- case, we know if it's a boot or not because of the {-# SOURCE #-} -- annotation, but we don't know if it's a signature or a regular -- module until we actually look it up on the filesystem. - let hsc_src = case is_boot of - IsBoot -> HsBootFile - _ | isHaskellSigFilename src_fn -> HsigFile - | otherwise -> HsSrcFile + let hsc_src + | is_boot == IsBoot = HsBootFile + | isHaskellSigFilename src_fn = HsigFile + | otherwise = HsSrcFile when (pi_mod_name /= wanted_mod) $ throwE $ unitBag $ mkPlainErrMsg pi_local_dflags pi_mod_name_loc $ @@ -2560,7 +2595,7 @@ data MakeNewModSummary = MakeNewModSummary { nms_src_fn :: FilePath , nms_src_timestamp :: UTCTime - , nms_is_boot :: IsBoot + , nms_is_boot :: IsBootInterface , nms_hsc_src :: HscSource , nms_location :: ModLocation , nms_mod :: Module @@ -2604,10 +2639,11 @@ makeNewModSummary hsc_env MakeNewModSummary{..} = do , ms_obj_date = obj_timestamp } -getObjTimestamp :: ModLocation -> IsBoot -> IO (Maybe UTCTime) +getObjTimestamp :: ModLocation -> IsBootInterface -> IO (Maybe UTCTime) getObjTimestamp location is_boot - = if is_boot == IsBoot then return Nothing - else modificationTimeIfExists (ml_obj_file location) + = case is_boot of + IsBoot -> return Nothing + NotBoot -> modificationTimeIfExists (ml_obj_file location) data PreprocessedImports = PreprocessedImports @@ -2722,8 +2758,11 @@ cyclicModuleErr mss graph = [ DigraphNode ms (msKey ms) (get_deps ms) | ms <- mss] get_deps :: ModSummary -> [NodeKey] - get_deps ms = ([ (unLoc m, IsBoot) | m <- ms_home_srcimps ms ] ++ - [ (unLoc m, NotBoot) | m <- ms_home_imps ms ]) + get_deps ms = + [ GWIB { gwib_mod = unLoc m, gwib_isBoot = IsBoot } + | m <- ms_home_srcimps ms ] ++ + [ GWIB { gwib_mod = unLoc m, gwib_isBoot = NotBoot } + | m <- ms_home_imps ms ] show_path [] = panic "show_path" show_path [m] = text "module" <+> ppr_ms m diff --git a/compiler/GHC/Driver/MakeFile.hs b/compiler/GHC/Driver/MakeFile.hs index f0de5b75c8..6a50ec483f 100644 --- a/compiler/GHC/Driver/MakeFile.hs +++ b/compiler/GHC/Driver/MakeFile.hs @@ -247,8 +247,8 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC node) | (mb_pkg, L loc mod) <- idecls, mod `notElem` excl_mods ] - ; do_imps True (ms_srcimps node) - ; do_imps False (ms_imps node) + ; do_imps IsBoot (ms_srcimps node) + ; do_imps NotBoot (ms_imps node) } diff --git a/compiler/GHC/Driver/Types.hs b/compiler/GHC/Driver/Types.hs index c93dc7649f..6903b3608f 100644 --- a/compiler/GHC/Driver/Types.hs +++ b/compiler/GHC/Driver/Types.hs @@ -114,7 +114,7 @@ module GHC.Driver.Types ( MonadThings(..), -- * Information on imports and exports - WhetherHasOrphans, IsBootInterface, Usage(..), + WhetherHasOrphans, IsBootInterface(..), Usage(..), Dependencies(..), noDependencies, updNameCache, IfaceExport, @@ -745,12 +745,12 @@ hptInstances hsc_env want_this_module in (concat insts, concat famInsts) -- | Get rules from modules "below" this one (in the dependency sense) -hptRules :: HscEnv -> [(ModuleName, IsBootInterface)] -> [CoreRule] +hptRules :: HscEnv -> [ModuleNameWithIsBoot] -> [CoreRule] hptRules = hptSomeThingsBelowUs (md_rules . hm_details) False -- | Get annotations from modules "below" this one (in the dependency sense) -hptAnns :: HscEnv -> Maybe [(ModuleName, IsBootInterface)] -> [Annotation] +hptAnns :: HscEnv -> Maybe [ModuleNameWithIsBoot] -> [Annotation] hptAnns hsc_env (Just deps) = hptSomeThingsBelowUs (md_anns . hm_details) False hsc_env deps hptAnns hsc_env Nothing = hptAllThings (md_anns . hm_details) hsc_env @@ -759,7 +759,7 @@ hptAllThings extract hsc_env = concatMap extract (eltsHpt (hsc_HPT hsc_env)) -- | Get things from modules "below" this one (in the dependency sense) -- C.f Inst.hptInstances -hptSomeThingsBelowUs :: (HomeModInfo -> [a]) -> Bool -> HscEnv -> [(ModuleName, IsBootInterface)] -> [a] +hptSomeThingsBelowUs :: (HomeModInfo -> [a]) -> Bool -> HscEnv -> [ModuleNameWithIsBoot] -> [a] hptSomeThingsBelowUs extract include_hi_boot hsc_env deps | isOneShot (ghcMode (hsc_dflags hsc_env)) = [] @@ -768,8 +768,8 @@ hptSomeThingsBelowUs extract include_hi_boot hsc_env deps in [ thing | -- Find each non-hi-boot module below me - (mod, is_boot_mod) <- deps - , include_hi_boot || not is_boot_mod + GWIB { gwib_mod = mod, gwib_isBoot = is_boot } <- deps + , include_hi_boot || (is_boot == NotBoot) -- unsavoury: when compiling the base package with --make, we -- sometimes try to look up RULES etc for GHC.Prim. GHC.Prim won't @@ -1114,8 +1114,10 @@ data ModIface_ (phase :: ModIfacePhase) -- | Old-style accessor for whether or not the ModIface came from an hs-boot -- file. -mi_boot :: ModIface -> Bool -mi_boot iface = mi_hsc_src iface == HsBootFile +mi_boot :: ModIface -> IsBootInterface +mi_boot iface = if mi_hsc_src iface == HsBootFile + then IsBoot + else NotBoot -- | Lookups up a (possibly cached) fixity from a 'ModIface'. If one cannot be -- found, 'defaultFixity' is returned instead. @@ -1141,7 +1143,7 @@ mi_free_holes iface = -> renameFreeHoles (mkUniqDSet cands) (instUnitInsts (moduleUnit indef)) _ -> emptyUniqDSet where - cands = map fst (dep_mods (mi_deps iface)) + cands = map gwib_mod $ dep_mods $ mi_deps iface -- | Given a set of free holes, and a unit identifier, rename -- the free holes according to the instantiation of the unit @@ -2494,9 +2496,6 @@ type WhetherHasOrphans = Bool -- | Does this module define family instances? type WhetherHasFamInst = Bool --- | Did this module originate from a *-boot file? -type IsBootInterface = Bool - -- | Dependency information about ALL modules and packages below this one -- in the import hierarchy. -- @@ -2504,7 +2503,7 @@ type IsBootInterface = Bool -- -- Invariant: none of the lists contain duplicates. data Dependencies - = Deps { dep_mods :: [(ModuleName, IsBootInterface)] + = Deps { dep_mods :: [ModuleNameWithIsBoot] -- ^ All home-package modules transitively below this one -- I.e. modules that this one imports, or that are in the -- dep_mods of those directly-imported modules @@ -2694,7 +2693,7 @@ type PackageCompleteMatchMap = CompleteMatchMap -- their interface files data ExternalPackageState = EPS { - eps_is_boot :: !(ModuleNameEnv (ModuleName, IsBootInterface)), + eps_is_boot :: !(ModuleNameEnv ModuleNameWithIsBoot), -- ^ In OneShot mode (only), home-package modules -- accumulate in the external package state, and are -- sucked in lazily. For these home-pkg modules @@ -2872,19 +2871,19 @@ isTemplateHaskellOrQQNonBoot :: ModSummary -> Bool isTemplateHaskellOrQQNonBoot ms = (xopt LangExt.TemplateHaskell (ms_hspp_opts ms) || xopt LangExt.QuasiQuotes (ms_hspp_opts ms)) && - not (isBootSummary ms) + (isBootSummary ms == NotBoot) -- | Add a ModSummary to ModuleGraph. Assumes that the new ModSummary is -- not an element of the ModuleGraph. extendMG :: ModuleGraph -> ModSummary -> ModuleGraph extendMG ModuleGraph{..} ms = ModuleGraph { mg_mss = ms:mg_mss - , mg_non_boot = if isBootSummary ms - then mg_non_boot - else extendModuleEnv mg_non_boot (ms_mod ms) ms - , mg_boot = if isBootSummary ms - then extendModuleSet mg_boot (ms_mod ms) - else mg_boot + , mg_non_boot = case isBootSummary ms of + IsBoot -> mg_non_boot + NotBoot -> extendModuleEnv mg_non_boot (ms_mod ms) ms + , mg_boot = case isBootSummary ms of + NotBoot -> mg_boot + IsBoot -> extendModuleSet mg_boot (ms_mod ms) , mg_needs_th_or_qq = mg_needs_th_or_qq || isTemplateHaskellOrQQNonBoot ms } @@ -2985,8 +2984,8 @@ msDynObjFilePath :: ModSummary -> DynFlags -> FilePath msDynObjFilePath ms dflags = dynamicOutputFile dflags (msObjFilePath ms) -- | Did this 'ModSummary' originate from a hs-boot file? -isBootSummary :: ModSummary -> Bool -isBootSummary ms = ms_hsc_src ms == HsBootFile +isBootSummary :: ModSummary -> IsBootInterface +isBootSummary ms = if ms_hsc_src ms == HsBootFile then IsBoot else NotBoot instance Outputable ModSummary where ppr ms diff --git a/compiler/GHC/Hs/ImpExp.hs b/compiler/GHC/Hs/ImpExp.hs index 02eb9db1ca..2257352b63 100644 --- a/compiler/GHC/Hs/ImpExp.hs +++ b/compiler/GHC/Hs/ImpExp.hs @@ -18,7 +18,7 @@ module GHC.Hs.ImpExp where import GHC.Prelude -import GHC.Unit.Module ( ModuleName ) +import GHC.Unit.Module ( ModuleName, IsBootInterface(..) ) import GHC.Hs.Doc ( HsDocString ) import GHC.Types.Name.Occurrence ( HasOccName(..), isTcOcc, isSymOcc ) import GHC.Types.Basic ( SourceText(..), StringLiteral(..), pprWithSourceText ) @@ -83,7 +83,7 @@ data ImportDecl pass -- Note [Pragma source text] in GHC.Types.Basic ideclName :: Located ModuleName, -- ^ Module name. ideclPkgQual :: Maybe StringLiteral, -- ^ Package qualifier. - ideclSource :: Bool, -- ^ True <=> {-\# SOURCE \#-} import + ideclSource :: IsBootInterface, -- ^ IsBoot <=> {-\# SOURCE \#-} import ideclSafe :: Bool, -- ^ True => safe import ideclQualified :: ImportDeclQualifiedStyle, -- ^ If/how the import is qualified. ideclImplicit :: Bool, -- ^ True => implicit import (of Prelude) @@ -118,7 +118,7 @@ simpleImportDecl mn = ImportDecl { ideclSourceSrc = NoSourceText, ideclName = noLoc mn, ideclPkgQual = Nothing, - ideclSource = False, + ideclSource = NotBoot, ideclSafe = False, ideclImplicit = False, ideclQualified = NotQualified, @@ -156,10 +156,10 @@ instance OutputableBndrId p pp_as Nothing = empty pp_as (Just a) = text "as" <+> ppr a - ppr_imp True = case mSrcText of + ppr_imp IsBoot = case mSrcText of NoSourceText -> text "{-# SOURCE #-}" SourceText src -> text src <+> text "#-}" - ppr_imp False = empty + ppr_imp NotBoot = empty pp_spec Nothing = empty pp_spec (Just (False, (L _ ies))) = ppr_ies ies diff --git a/compiler/GHC/HsToCore/Monad.hs b/compiler/GHC/HsToCore/Monad.hs index 1914498f4e..02bd5cf91e 100644 --- a/compiler/GHC/HsToCore/Monad.hs +++ b/compiler/GHC/HsToCore/Monad.hs @@ -285,7 +285,7 @@ mkDsEnvs dflags mod rdr_env type_env fam_inst_env msg_var cc_st_var = let if_genv = IfGblEnv { if_doc = text "mkDsEnvs", if_rec_types = Just (mod, return type_env) } if_lenv = mkIfLclEnv mod (text "GHC error in desugarer lookup in" <+> ppr mod) - False -- not boot! + NotBoot real_span = realSrcLocSpan (mkRealSrcLoc (moduleNameFS (moduleName mod)) 1 1) completeMatchMap = mkCompleteMatchMap complete_matches gbl_env = DsGblEnv { ds_mod = mod diff --git a/compiler/GHC/HsToCore/Usage.hs b/compiler/GHC/HsToCore/Usage.hs index fef8fb03c4..0c48b5744d 100644 --- a/compiler/GHC/HsToCore/Usage.hs +++ b/compiler/GHC/HsToCore/Usage.hs @@ -215,9 +215,10 @@ mkPluginUsage hsc_env pluginModule where dflags = hsc_dflags hsc_env platform = targetPlatform dflags - pNm = moduleName (mi_module pluginModule) - pPkg = moduleUnit (mi_module pluginModule) - deps = map fst (dep_mods (mi_deps pluginModule)) + pNm = moduleName $ mi_module pluginModule + pPkg = moduleUnit $ mi_module pluginModule + deps = map gwib_mod $ + dep_mods $ mi_deps pluginModule -- Lookup object file for a plugin dependency, -- from the same package as the plugin. diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs index 80c4505c8e..ef69e97605 100644 --- a/compiler/GHC/Iface/Load.hs +++ b/compiler/GHC/Iface/Load.hs @@ -366,7 +366,7 @@ loadSysInterface doc mod_name = loadInterfaceWithException doc mod_name ImportBy ------------------ -- | Loads a user interface and throws an exception if it fails. The first parameter indicates -- whether we should import the boot variant of the module -loadUserInterface :: Bool -> SDoc -> Module -> IfM lcl ModIface +loadUserInterface :: IsBootInterface -> SDoc -> Module -> IfM lcl ModIface loadUserInterface is_boot doc mod_name = loadInterfaceWithException doc mod_name (ImportByUser is_boot) @@ -485,7 +485,7 @@ loadInterface doc_str mod from } } - ; let bad_boot = mi_boot iface && fmap fst (if_rec_types gbl_env) == Just mod + ; let bad_boot = mi_boot iface == IsBoot && fmap fst (if_rec_types gbl_env) == Just mod -- Warn warn against an EPS-updating import -- of one's own boot file! (one-shot only) -- See Note [Loading your own hi-boot file] @@ -690,7 +690,7 @@ moduleFreeHolesPrecise doc_str mod Just ifhs -> Just (renameFreeHoles ifhs insts) _otherwise -> Nothing readAndCache imod insts = do - mb_iface <- findAndReadIface (text "moduleFreeHolesPrecise" <+> doc_str) imod mod False + mb_iface <- findAndReadIface (text "moduleFreeHolesPrecise" <+> doc_str) imod mod NotBoot case mb_iface of Succeeded (iface, _) -> do let ifhs = mi_free_holes iface @@ -706,23 +706,25 @@ wantHiBootFile :: DynFlags -> ExternalPackageState -> Module -> WhereFrom wantHiBootFile dflags eps mod from = case from of ImportByUser usr_boot - | usr_boot && not this_package + | usr_boot == IsBoot && not this_package -> Failed (badSourceImport mod) | otherwise -> Succeeded usr_boot ImportByPlugin - -> Succeeded False + -> Succeeded NotBoot ImportBySystem | not this_package -- If the module to be imported is not from this package - -> Succeeded False -- don't look it up in eps_is_boot, because that is keyed + -> Succeeded NotBoot -- don't look it up in eps_is_boot, because that is keyed -- on the ModuleName of *home-package* modules only. -- We never import boot modules from other packages! | otherwise -> case lookupUFM (eps_is_boot eps) (moduleName mod) of - Just (_, is_boot) -> Succeeded is_boot - Nothing -> Succeeded False + Just (GWIB { gwib_isBoot = is_boot }) -> + Succeeded is_boot + Nothing -> + Succeeded NotBoot -- The boot-ness of the requested interface, -- based on the dependencies in directly-imported modules where @@ -899,7 +901,7 @@ findAndReadIface :: SDoc -- sometimes it's ok to fail... see notes with loadInterface findAndReadIface doc_str mod wanted_mod_with_insts hi_boot_file = do traceIf (sep [hsep [text "Reading", - if hi_boot_file + if hi_boot_file == IsBoot then text "[boot]" else Outputable.empty, text "interface for", @@ -1219,11 +1221,11 @@ pprDeps (Deps { dep_mods = mods, dep_pkgs = pkgs, dep_orphs = orphs, text "family instance modules:" <+> fsep (map ppr finsts) ] where - ppr_mod (mod_name, boot) = ppr mod_name <+> ppr_boot boot + ppr_mod (GWIB { gwib_mod = mod_name, gwib_isBoot = boot }) = ppr mod_name <+> ppr_boot boot ppr_pkg (pkg,trust_req) = ppr pkg <> (if trust_req then text "*" else Outputable.empty) - ppr_boot True = text "[boot]" - ppr_boot False = Outputable.empty + ppr_boot IsBoot = text "[boot]" + ppr_boot NotBoot = Outputable.empty pprFixities :: [(OccName, Fixity)] -> SDoc pprFixities [] = Outputable.empty diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs index 68103fc1f4..03223c5712 100644 --- a/compiler/GHC/Iface/Recomp.hs +++ b/compiler/GHC/Iface/Recomp.hs @@ -252,7 +252,7 @@ checkVersions hsc_env mod_summary iface where this_pkg = thisPackage (hsc_dflags hsc_env) -- This is a bit of a hack really - mod_deps :: ModuleNameEnv (ModuleName, IsBootInterface) + mod_deps :: ModuleNameEnv ModuleNameWithIsBoot mod_deps = mkModDeps (dep_mods (mi_deps iface)) -- | Check if any plugins are requesting recompilation @@ -455,7 +455,7 @@ checkDependencies hsc_env summary iface case find_res of Found _ mod | pkg == this_pkg - -> if moduleName mod `notElem` map fst prev_dep_mods ++ prev_dep_plgn + -> if moduleName mod `notElem` map gwib_mod prev_dep_mods ++ prev_dep_plgn then do traceHiDiffs $ text "imported module " <> quotes (ppr mod) <> text " not among previous dependencies" @@ -474,7 +474,9 @@ checkDependencies hsc_env summary iface where pkg = moduleUnit mod _otherwise -> return (RecompBecause reason) - old_deps = Set.fromList $ map fst $ filter (not . snd) prev_dep_mods + projectNonBootNames = map gwib_mod . filter ((== NotBoot) . gwib_isBoot) + old_deps = Set.fromList + $ projectNonBootNames prev_dep_mods isOldHomeDeps = flip Set.member old_deps checkForNewHomeDependency (L _ mname) = do let @@ -489,7 +491,7 @@ checkDependencies hsc_env summary iface then return (UpToDate, []) else do mb_result <- getFromModIface "need mi_deps for" mod $ \imported_iface -> do - let mnames = mname:(map fst $ filter (not . snd) $ + let mnames = mname:(map gwib_mod $ filter ((== NotBoot) . gwib_isBoot) $ dep_mods $ mi_deps imported_iface) case find (not . isOldHomeDeps) mnames of Nothing -> return (UpToDate, mnames) @@ -1073,7 +1075,7 @@ getOrphanHashes hsc_env mods = do sortDependencies :: Dependencies -> Dependencies sortDependencies d - = Deps { dep_mods = sortBy (compare `on` (moduleNameFS.fst)) (dep_mods d), + = Deps { dep_mods = sortBy (compare `on` (moduleNameFS . gwib_mod)) (dep_mods d), dep_pkgs = sortBy (compare `on` fst) (dep_pkgs d), dep_orphs = sortBy stableModuleCmp (dep_orphs d), dep_finsts = sortBy stableModuleCmp (dep_finsts d), diff --git a/compiler/GHC/IfaceToCore.hs b/compiler/GHC/IfaceToCore.hs index 48652573f3..b84fe1619d 100644 --- a/compiler/GHC/IfaceToCore.hs +++ b/compiler/GHC/IfaceToCore.hs @@ -354,7 +354,7 @@ mergeIfaceDecls = plusOccEnv_C mergeIfaceDecl typecheckIfacesForMerging :: Module -> [ModIface] -> IORef TypeEnv -> IfM lcl (TypeEnv, [ModDetails]) typecheckIfacesForMerging mod ifaces tc_env_var = -- cannot be boot (False) - initIfaceLcl mod (text "typecheckIfacesForMerging") False $ do + initIfaceLcl mod (text "typecheckIfacesForMerging") NotBoot $ do ignore_prags <- goptM Opt_IgnoreInterfacePragmas -- Build the initial environment -- NB: Don't include dfuns here, because we don't want to @@ -506,7 +506,7 @@ tcHiBootIface hsc_src mod -- it's been compiled once, and we don't need to check the boot iface then do { hpt <- getHpt ; case lookupHpt hpt (moduleName mod) of - Just info | mi_boot (hm_iface info) + Just info | mi_boot (hm_iface info) == IsBoot -> mkSelfBootInfo (hm_iface info) (hm_details info) _ -> return NoSelfBoot } else do @@ -517,7 +517,7 @@ tcHiBootIface hsc_src mod -- that an hi-boot is necessary due to a circular import. { read_result <- findAndReadIface need (fst (getModuleInstantiation mod)) mod - True -- Hi-boot file + IsBoot -- Hi-boot file ; case read_result of { Succeeded (iface, _path) -> do { tc_iface <- initIfaceTcRn $ typecheckIface iface @@ -533,14 +533,15 @@ tcHiBootIface hsc_src mod -- disappeared. do { eps <- getEps ; case lookupUFM (eps_is_boot eps) (moduleName mod) of - Nothing -> return NoSelfBoot -- The typical case - - Just (_, False) -> failWithTc moduleLoop - -- Someone below us imported us! - -- This is a loop with no hi-boot in the way - - Just (_mod, True) -> failWithTc (elaborate err) - -- The hi-boot file has mysteriously disappeared. + -- The typical case + Nothing -> return NoSelfBoot + -- error cases + Just (GWIB { gwib_isBoot = is_boot }) -> case is_boot of + IsBoot -> failWithTc (elaborate err) + -- The hi-boot file has mysteriously disappeared. + NotBoot -> failWithTc moduleLoop + -- Someone below us imported us! + -- This is a loop with no hi-boot in the way }}}} where need = text "Need the hi-boot interface for" <+> ppr mod @@ -1480,8 +1481,9 @@ tcIdInfo ignore_prags toplvl name ty info = do lcl_env <- getLclEnv -- Set the CgInfo to something sensible but uninformative before -- we start; default assumption is that it has CAFs - let init_info | if_boot lcl_env = vanillaIdInfo `setUnfoldingInfo` BootUnfolding - | otherwise = vanillaIdInfo + let init_info = if if_boot lcl_env == IsBoot + then vanillaIdInfo `setUnfoldingInfo` BootUnfolding + else vanillaIdInfo let needed = needed_prags info foldlM tcPrag init_info needed diff --git a/compiler/GHC/Parser.y b/compiler/GHC/Parser.y index a9bb4fa87d..50459c673e 100644 --- a/compiler/GHC/Parser.y +++ b/compiler/GHC/Parser.y @@ -51,7 +51,7 @@ import qualified Prelude import GHC.Hs import GHC.Driver.Phases ( HscSource(..) ) -import GHC.Driver.Types ( IsBootInterface, WarningTxt(..) ) +import GHC.Driver.Types ( IsBootInterface(..), WarningTxt(..) ) import GHC.Driver.Session import GHC.Driver.Backpack.Syntax import GHC.Unit.Info @@ -722,8 +722,8 @@ unitdecl :: { LHsUnitDecl PackageName } -- XXX not accurate { sL1 $2 $ DeclD (case snd $3 of - False -> HsSrcFile - True -> HsBootFile) + NotBoot -> HsSrcFile + IsBoot -> HsBootFile) $4 (Just $ sL1 $2 (HsModule (Just $4) $6 (fst $ snd $8) (snd $ snd $8) $5 $1)) } | maybedocheader 'signature' modid maybemodwarning maybeexports 'where' body @@ -735,8 +735,8 @@ unitdecl :: { LHsUnitDecl PackageName } -- will prevent us from parsing both forms. | maybedocheader 'module' maybe_src modid { sL1 $2 $ DeclD (case snd $3 of - False -> HsSrcFile - True -> HsBootFile) $4 Nothing } + NotBoot -> HsSrcFile + IsBoot -> HsBootFile) $4 Nothing } | maybedocheader 'signature' modid { sL1 $2 $ DeclD HsigFile $3 Nothing } | 'dependency' unitid mayberns @@ -985,8 +985,8 @@ importdecl :: { LImportDecl GhcPs } maybe_src :: { (([AddAnn],SourceText),IsBootInterface) } : '{-# SOURCE' '#-}' { (([mo $1,mc $2],getSOURCE_PRAGs $1) - , True) } - | {- empty -} { (([],NoSourceText),False) } + , IsBoot) } + | {- empty -} { (([],NoSourceText),NotBoot) } maybe_safe :: { ([AddAnn],Bool) } : 'safe' { ([mj AnnSafe $1],True) } diff --git a/compiler/GHC/Parser/Header.hs b/compiler/GHC/Parser/Header.hs index f6be2a2487..bfdeb71631 100644 --- a/compiler/GHC/Parser/Header.hs +++ b/compiler/GHC/Parser/Header.hs @@ -91,7 +91,7 @@ getImports dflags buf filename source_filename = do main_loc = srcLocSpan (mkSrcLoc (mkFastString source_filename) 1 1) mod = mb_mod `orElse` L main_loc mAIN_NAME - (src_idecls, ord_idecls) = partition (ideclSource.unLoc) imps + (src_idecls, ord_idecls) = partition ((== IsBoot) . ideclSource . unLoc) imps -- GHC.Prim doesn't exist physically, so don't go looking for it. ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc @@ -135,7 +135,7 @@ mkPrelImports this_mod loc implicit_prelude import_decls ideclSourceSrc = NoSourceText, ideclName = L loc pRELUDE_NAME, ideclPkgQual = Nothing, - ideclSource = False, + ideclSource = NotBoot, ideclSafe = False, -- Not a safe import ideclQualified = NotQualified, ideclImplicit = True, -- Implicit! diff --git a/compiler/GHC/Rename/Env.hs b/compiler/GHC/Rename/Env.hs index e6fa48c004..89d1e66311 100644 --- a/compiler/GHC/Rename/Env.hs +++ b/compiler/GHC/Rename/Env.hs @@ -1347,7 +1347,7 @@ lookupQualifiedNameGHCi rdr_name , is_ghci , gopt Opt_ImplicitImportQualified dflags -- Enables this GHCi behaviour , not (safeDirectImpsReq dflags) -- See Note [Safe Haskell and GHCi] - = do { res <- loadSrcInterface_maybe doc mod False Nothing + = do { res <- loadSrcInterface_maybe doc mod NotBoot Nothing ; case res of Succeeded iface -> return [ name diff --git a/compiler/GHC/Rename/Names.hs b/compiler/GHC/Rename/Names.hs index 9e7f1a4216..354954f19c 100644 --- a/compiler/GHC/Rename/Names.hs +++ b/compiler/GHC/Rename/Names.hs @@ -176,7 +176,7 @@ rnImports imports = do -- module to import from its implementor let this_mod = tcg_mod tcg_env let (source, ordinary) = partition is_source_import imports - is_source_import d = ideclSource (unLoc d) + is_source_import d = ideclSource (unLoc d) == IsBoot stuff1 <- mapAndReportM (rnImportDecl this_mod) ordinary stuff2 <- mapAndReportM (rnImportDecl this_mod) source -- Safe Haskell: See Note [Tracking Trust Transitively] @@ -323,7 +323,7 @@ rnImportDecl this_mod -- Compiler sanity check: if the import didn't say -- {-# SOURCE #-} we should not get a hi-boot file - WARN( not want_boot && mi_boot iface, ppr imp_mod_name ) do + WARN( (want_boot == NotBoot) && (mi_boot iface == IsBoot), ppr imp_mod_name ) do -- Issue a user warning for a redundant {- SOURCE -} import -- NB that we arrange to read all the ordinary imports before @@ -334,7 +334,7 @@ rnImportDecl this_mod -- the non-boot module depends on the compilation order, which -- is not deterministic. The hs-boot test can show this up. dflags <- getDynFlags - warnIf (want_boot && not (mi_boot iface) && isOneShot (ghcMode dflags)) + warnIf ((want_boot == IsBoot) && (mi_boot iface == NotBoot) && isOneShot (ghcMode dflags)) (warnRedundantSourceImport imp_mod_name) when (mod_safe && not (safeImportsOn dflags)) $ addErr (text "safe import can't be used as Safe Haskell isn't on!" @@ -460,7 +460,10 @@ calculateAvails dflags iface mod_safe' want_boot imported_by = -- know if any of them depended on CM.hi-boot, in -- which case we should do the hi-boot consistency -- check. See GHC.Iface.Load.loadHiBootInterface - ((moduleName imp_mod,want_boot):dep_mods deps,dep_pkgs deps,ptrust) + ( GWIB { gwib_mod = moduleName imp_mod, gwib_isBoot = want_boot } : dep_mods deps + , dep_pkgs deps + , ptrust + ) | otherwise = -- Imported module is from another package @@ -1698,20 +1701,23 @@ qualImportItemErr rdr = hang (text "Illegal qualified name in import item:") 2 (ppr rdr) +pprImpDeclSpec :: ModIface -> ImpDeclSpec -> SDoc +pprImpDeclSpec iface decl_spec = + quotes (ppr (is_mod decl_spec)) <+> case mi_boot iface of + IsBoot -> text "(hi-boot interface)" + NotBoot -> Outputable.empty + badImportItemErrStd :: ModIface -> ImpDeclSpec -> IE GhcPs -> SDoc badImportItemErrStd iface decl_spec ie - = sep [text "Module", quotes (ppr (is_mod decl_spec)), source_import, + = sep [text "Module", pprImpDeclSpec iface decl_spec, text "does not export", quotes (ppr ie)] - where - source_import | mi_boot iface = text "(hi-boot interface)" - | otherwise = Outputable.empty badImportItemErrDataCon :: OccName -> ModIface -> ImpDeclSpec -> IE GhcPs -> SDoc badImportItemErrDataCon dataType_occ iface decl_spec ie = vcat [ text "In module" - <+> quotes (ppr (is_mod decl_spec)) - <+> source_import <> colon + <+> pprImpDeclSpec iface decl_spec + <> colon , nest 2 $ quotes datacon <+> text "is a data constructor of" <+> quotes dataType @@ -1728,8 +1734,6 @@ badImportItemErrDataCon dataType_occ iface decl_spec ie datacon_occ = rdrNameOcc $ ieName ie datacon = parenSymOcc datacon_occ (ppr datacon_occ) dataType = parenSymOcc dataType_occ (ppr dataType_occ) - source_import | mi_boot iface = text "(hi-boot interface)" - | otherwise = Outputable.empty parens_sp d = parens (space <> d <> space) -- T( f,g ) badImportItemErr :: ModIface -> ImpDeclSpec -> IE GhcPs -> [AvailInfo] -> SDoc diff --git a/compiler/GHC/Runtime/Linker.hs b/compiler/GHC/Runtime/Linker.hs index b936bde303..d6b916ff39 100644 --- a/compiler/GHC/Runtime/Linker.hs +++ b/compiler/GHC/Runtime/Linker.hs @@ -68,6 +68,7 @@ import Control.Monad import qualified Data.Set as Set import Data.Char (isSpace) +import Data.Function ((&)) import Data.IORef import Data.List (intercalate, isPrefixOf, isSuffixOf, nub, partition) import Data.Maybe @@ -670,21 +671,23 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods follow_deps (mod:mods) acc_mods acc_pkgs = do mb_iface <- initIfaceCheck (text "getLinkDeps") hsc_env $ - loadInterface msg mod (ImportByUser False) + loadInterface msg mod (ImportByUser NotBoot) iface <- case mb_iface of Maybes.Failed err -> throwGhcExceptionIO (ProgramError (showSDoc dflags err)) Maybes.Succeeded iface -> return iface - when (mi_boot iface) $ link_boot_mod_error mod + when (mi_boot iface == IsBoot) $ link_boot_mod_error mod let pkg = moduleUnit mod deps = mi_deps iface pkg_deps = dep_pkgs deps - (boot_deps, mod_deps) = partitionWith is_boot (dep_mods deps) - where is_boot (m,True) = Left m - is_boot (m,False) = Right m + (boot_deps, mod_deps) = flip partitionWith (dep_mods deps) $ + \ (GWIB { gwib_mod = m, gwib_isBoot = is_boot }) -> + m & case is_boot of + IsBoot -> Left + NotBoot -> Right boot_deps' = filter (not . (`elementOfUniqDSet` acc_mods)) boot_deps acc_mods' = addListToUniqDSet acc_mods (moduleName mod : mod_deps) diff --git a/compiler/GHC/Tc/Module.hs b/compiler/GHC/Tc/Module.hs index 94402c0989..267a36cd89 100644 --- a/compiler/GHC/Tc/Module.hs +++ b/compiler/GHC/Tc/Module.hs @@ -321,7 +321,7 @@ tcRnImports hsc_env import_decls = do { (rn_imports, rdr_env, imports, hpc_info) <- rnImports import_decls ; ; this_mod <- getModule - ; let { dep_mods :: ModuleNameEnv (ModuleName, IsBootInterface) + ; let { dep_mods :: ModuleNameEnv ModuleNameWithIsBoot ; dep_mods = imp_dep_mods imports -- We want instance declarations from all home-package @@ -1973,7 +1973,7 @@ runTcInteractive hsc_env thing_inside ; let getOrphans m mb_pkg = fmap (\iface -> mi_module iface : dep_orphs (mi_deps iface)) (loadSrcInterface (text "runTcInteractive") m - False mb_pkg) + NotBoot mb_pkg) ; !orphs <- fmap (force . concat) . forM (ic_imports icxt) $ \i -> case i of -- force above: see #15111 diff --git a/compiler/GHC/Tc/Types.hs b/compiler/GHC/Tc/Types.hs index 6e60efd4d5..4da234ea08 100644 --- a/compiler/GHC/Tc/Types.hs +++ b/compiler/GHC/Tc/Types.hs @@ -262,7 +262,7 @@ data IfLclEnv -- Whether or not the IfaceDecl came from a boot -- file or not; we'll use this to choose between -- NoUnfolding and BootUnfolding - if_boot :: Bool, + if_boot :: IsBootInterface, -- The field is used only for error reporting -- if (say) there's a Lint error in it @@ -1340,7 +1340,7 @@ data ImportAvails -- different packages. (currently not the case, but might be in the -- future). - imp_dep_mods :: ModuleNameEnv (ModuleName, IsBootInterface), + imp_dep_mods :: ModuleNameEnv ModuleNameWithIsBoot, -- ^ Home-package modules needed by the module being compiled -- -- It doesn't matter whether any of these dependencies @@ -1381,15 +1381,15 @@ data ImportAvails -- including us for imported modules) } -mkModDeps :: [(ModuleName, IsBootInterface)] - -> ModuleNameEnv (ModuleName, IsBootInterface) +mkModDeps :: [ModuleNameWithIsBoot] + -> ModuleNameEnv ModuleNameWithIsBoot mkModDeps deps = foldl' add emptyUFM deps - where - add env elt@(m,_) = addToUFM env m elt + where + add env elt = addToUFM env (gwib_mod elt) elt modDepsElts - :: ModuleNameEnv (ModuleName, IsBootInterface) - -> [(ModuleName, IsBootInterface)] + :: ModuleNameEnv ModuleNameWithIsBoot + -> [ModuleNameWithIsBoot] modDepsElts = sort . nonDetEltsUFM -- It's OK to use nonDetEltsUFM here because sorting by module names -- restores determinism @@ -1426,9 +1426,10 @@ plusImportAvails imp_orphs = orphs1 `unionLists` orphs2, imp_finsts = finsts1 `unionLists` finsts2 } where - plus_mod_dep r1@(m1, boot1) r2@(m2, boot2) - | ASSERT2( m1 == m2, (ppr m1 <+> ppr m2) $$ (ppr boot1 <+> ppr boot2) ) - boot1 = r2 + plus_mod_dep r1@(GWIB { gwib_mod = m1, gwib_isBoot = boot1 }) + r2@(GWIB {gwib_mod = m2, gwib_isBoot = boot2}) + | ASSERT2( m1 == m2, (ppr m1 <+> ppr m2) $$ (ppr (boot1 == IsBoot) <+> ppr (boot2 == IsBoot))) + boot1 == IsBoot = r2 | otherwise = r1 -- If either side can "see" a non-hi-boot interface, use that -- Reusing existing tuples saves 10% of allocations on test @@ -1451,8 +1452,8 @@ data WhereFrom -- See Note [Care with plugin imports] in GHC.Iface.Load instance Outputable WhereFrom where - ppr (ImportByUser is_boot) | is_boot = text "{- SOURCE -}" - | otherwise = empty + ppr (ImportByUser IsBoot) = text "{- SOURCE -}" + ppr (ImportByUser NotBoot) = empty ppr ImportBySystem = text "{- SYSTEM -}" ppr ImportByPlugin = text "{- PLUGIN -}" diff --git a/compiler/GHC/Tc/Utils/Backpack.hs b/compiler/GHC/Tc/Utils/Backpack.hs index d28dad8f70..98458b884b 100644 --- a/compiler/GHC/Tc/Utils/Backpack.hs +++ b/compiler/GHC/Tc/Utils/Backpack.hs @@ -549,7 +549,7 @@ mergeSignatures im = fst (getModuleInstantiation m) in fmap fst . withException - $ findAndReadIface (text "mergeSignatures") im m False + $ findAndReadIface (text "mergeSignatures") im m NotBoot -- STEP 3: Get the unrenamed exports of all these interfaces, -- thin it according to the export list, and do shaping on them. @@ -842,7 +842,7 @@ mergeSignatures -- supposed to include itself in its dep_orphs/dep_finsts. See #13214 iface' = iface { mi_final_exts = (mi_final_exts iface){ mi_orphan = False, mi_finsts = False } } avails = plusImportAvails (tcg_imports tcg_env) $ - calculateAvails dflags iface' False False ImportedBySystem + calculateAvails dflags iface' False NotBoot ImportedBySystem return tcg_env { tcg_inst_env = inst_env, tcg_insts = insts, @@ -929,7 +929,7 @@ checkImplements impl_mod req_mod@(Module uid mod_name) = dflags <- getDynFlags let avails = calculateAvails dflags - impl_iface False{- safe -} False{- boot -} ImportedBySystem + impl_iface False{- safe -} NotBoot ImportedBySystem fix_env = mkNameEnv [ (gre_name rdr_elt, FixItem occ f) | (occ, f) <- mi_fixities impl_iface , rdr_elt <- lookupGlobalRdrEnv impl_gr occ ] @@ -953,7 +953,7 @@ checkImplements impl_mod req_mod@(Module uid mod_name) = -- instantiation is correct. let sig_mod = mkModule (VirtUnit uid) mod_name isig_mod = fst (getModuleInstantiation sig_mod) - mb_isig_iface <- findAndReadIface (text "checkImplements 2") isig_mod sig_mod False + mb_isig_iface <- findAndReadIface (text "checkImplements 2") isig_mod sig_mod NotBoot isig_iface <- case mb_isig_iface of Succeeded (iface, _) -> return iface Failed err -> failWithTc $ diff --git a/compiler/GHC/Tc/Utils/Monad.hs b/compiler/GHC/Tc/Utils/Monad.hs index 85b3ad2e96..2fc741ce6f 100644 --- a/compiler/GHC/Tc/Utils/Monad.hs +++ b/compiler/GHC/Tc/Utils/Monad.hs @@ -1830,7 +1830,7 @@ setLocalRdrEnv rdr_env thing_inside ************************************************************************ -} -mkIfLclEnv :: Module -> SDoc -> Bool -> IfLclEnv +mkIfLclEnv :: Module -> SDoc -> IsBootInterface -> IfLclEnv mkIfLclEnv mod loc boot = IfLclEnv { if_mod = mod, if_loc = loc, @@ -1887,14 +1887,14 @@ initIfaceCheck doc hsc_env do_this } initTcRnIf 'i' hsc_env gbl_env () do_this -initIfaceLcl :: Module -> SDoc -> Bool -> IfL a -> IfM lcl a +initIfaceLcl :: Module -> SDoc -> IsBootInterface -> IfL a -> IfM lcl a initIfaceLcl mod loc_doc hi_boot_file thing_inside = setLclEnv (mkIfLclEnv mod loc_doc hi_boot_file) thing_inside -- | Initialize interface typechecking, but with a 'NameShape' -- to apply when typechecking top-level 'OccName's (see -- 'lookupIfaceTop') -initIfaceLclWithSubst :: Module -> SDoc -> Bool -> NameShape -> IfL a -> IfM lcl a +initIfaceLclWithSubst :: Module -> SDoc -> IsBootInterface -> NameShape -> IfL a -> IfM lcl a initIfaceLclWithSubst mod loc_doc hi_boot_file nsubst thing_inside = setLclEnv ((mkIfLclEnv mod loc_doc hi_boot_file) { if_nsubst = Just nsubst }) thing_inside diff --git a/compiler/GHC/Unit/Module.hs b/compiler/GHC/Unit/Module.hs index 7eed456311..14751d7003 100644 --- a/compiler/GHC/Unit/Module.hs +++ b/compiler/GHC/Unit/Module.hs @@ -9,13 +9,13 @@ These are Uniquable, hence we can build Maps with Modules as the keys. -} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE ExplicitNamespaces #-} -{-# LANGUAGE TypeSynonymInstances #-} -{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE ExplicitNamespaces #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TypeSynonymInstances #-} module GHC.Unit.Module ( module GHC.Unit.Types @@ -29,7 +29,6 @@ module GHC.Unit.Module -- * ModuleEnv , module GHC.Unit.Module.Env - -- * Generalization , getModuleInstantiation , getUnitInstantiations @@ -148,4 +147,3 @@ isHoleModule _ = False -- | Create a hole Module mkHoleModule :: ModuleName -> GenModule (GenUnit u) mkHoleModule = Module HoleUnit - diff --git a/compiler/GHC/Unit/Module/Location.hs b/compiler/GHC/Unit/Module/Location.hs index 540f2305d2..7518bd63e8 100644 --- a/compiler/GHC/Unit/Module/Location.hs +++ b/compiler/GHC/Unit/Module/Location.hs @@ -9,6 +9,7 @@ module GHC.Unit.Module.Location where import GHC.Prelude +import GHC.Unit.Types import GHC.Utils.Outputable -- | Module Location @@ -54,10 +55,10 @@ addBootSuffix :: FilePath -> FilePath addBootSuffix path = path ++ "-boot" -- | Add the @-boot@ suffix if the @Bool@ argument is @True@ -addBootSuffix_maybe :: Bool -> FilePath -> FilePath -addBootSuffix_maybe is_boot path - | is_boot = addBootSuffix path - | otherwise = path +addBootSuffix_maybe :: IsBootInterface -> FilePath -> FilePath +addBootSuffix_maybe is_boot path = case is_boot of + IsBoot -> addBootSuffix path + NotBoot -> path -- | Add the @-boot@ suffix to all file paths associated with the module addBootSuffixLocn :: ModLocation -> ModLocation diff --git a/compiler/GHC/Unit/Types.hs b/compiler/GHC/Unit/Types.hs index 7282b385b6..04db40a154 100644 --- a/compiler/GHC/Unit/Types.hs +++ b/compiler/GHC/Unit/Types.hs @@ -1,7 +1,8 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE DeriveDataTypeable #-} -{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE NamedFieldPuns #-} -- | Unit & Module types -- @@ -63,6 +64,12 @@ module GHC.Unit.Types , interactiveUnitId , isInteractiveModule , wiredInUnitIds + + -- * Boot modules + , IsBootInterface (..) + , GenWithIsBoot (..) + , ModuleNameWithIsBoot + , ModuleWithIsBoot ) where @@ -634,3 +641,64 @@ wiredInUnitIds = , thUnitId , thisGhcUnitId ] + +--------------------------------------------------------------------- +-- Boot Modules +--------------------------------------------------------------------- + +-- Note [Boot Module Naming] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~ +-- Why is this section here? After all, these modules are supposed to be about +-- ways of referring to modules, not modules themselves. Well, the "bootness" of +-- a module is in a way part of its name, because 'import {-# SOURCE #-} Foo' +-- references the boot module in particular while 'import Foo' references the +-- regular module. Backpack signatures live in the normal module namespace (no +-- special import), so they don't matter here. When dealing with the modules +-- themselves, however, one should use not 'IsBoot' or conflate signatures and +-- modules in opposition to boot interfaces. Instead, one should use +-- 'DriverPhases.HscSource'. See Note [HscSource types]. + +-- | Indicates whether a module name is referring to a boot interface (hs-boot +-- file) or regular module (hs file). We need to treat boot modules specially +-- when building compilation graphs, since they break cycles. Regular source +-- files and signature files are treated equivalently. +data IsBootInterface = NotBoot | IsBoot + deriving (Eq, Ord, Show, Data) + +instance Binary IsBootInterface where + put_ bh ib = put_ bh $ + case ib of + NotBoot -> False + IsBoot -> True + get bh = do + b <- get bh + return $ case b of + False -> NotBoot + True -> IsBoot + +-- | This data type just pairs a value 'mod' with an IsBootInterface flag. In +-- practice, 'mod' is usually a @Module@ or @ModuleName@'. +data GenWithIsBoot mod = GWIB + { gwib_mod :: mod + , gwib_isBoot :: IsBootInterface + } deriving ( Eq, Ord, Show + , Functor, Foldable, Traversable + ) + +type ModuleNameWithIsBoot = GenWithIsBoot ModuleName + +type ModuleWithIsBoot = GenWithIsBoot Module + +instance Binary a => Binary (GenWithIsBoot a) where + put_ bh (GWIB { gwib_mod, gwib_isBoot }) = do + put_ bh gwib_mod + put_ bh gwib_isBoot + get bh = do + gwib_mod <- get bh + gwib_isBoot <- get bh + pure $ GWIB { gwib_mod, gwib_isBoot } + +instance Outputable a => Outputable (GenWithIsBoot a) where + ppr (GWIB { gwib_mod, gwib_isBoot }) = hsep $ ppr gwib_mod : case gwib_isBoot of + IsBoot -> [] + NotBoot -> [text "{-# SOURCE #-}"] |