diff options
Diffstat (limited to 'compiler/main/Finder.hs')
| -rw-r--r-- | compiler/main/Finder.hs | 203 | 
1 files changed, 142 insertions, 61 deletions
diff --git a/compiler/main/Finder.hs b/compiler/main/Finder.hs index e813e9e52c..2bcdd3360c 100644 --- a/compiler/main/Finder.hs +++ b/compiler/main/Finder.hs @@ -71,25 +71,25 @@ type BaseName = String  -- Basename of file  -- assumed to not move around during a session.  flushFinderCaches :: HscEnv -> IO ()  flushFinderCaches hsc_env = -  atomicModifyIORef' fc_ref $ \fm -> (filterModuleEnv is_ext fm, ()) +  atomicModifyIORef' fc_ref $ \fm -> (filterInstalledModuleEnv is_ext fm, ())   where          this_pkg = thisPackage (hsc_dflags hsc_env)          fc_ref = hsc_FC hsc_env -        is_ext mod _ | moduleUnitId mod /= this_pkg = True +        is_ext mod _ | not (installedModuleUnitId mod `installedUnitIdEq` this_pkg) = True                       | otherwise = False -addToFinderCache :: IORef FinderCache -> Module -> FindResult -> IO () +addToFinderCache :: IORef FinderCache -> InstalledModule -> InstalledFindResult -> IO ()  addToFinderCache ref key val = -  atomicModifyIORef' ref $ \c -> (extendModuleEnv c key val, ()) +  atomicModifyIORef' ref $ \c -> (extendInstalledModuleEnv c key val, ()) -removeFromFinderCache :: IORef FinderCache -> Module -> IO () +removeFromFinderCache :: IORef FinderCache -> InstalledModule -> IO ()  removeFromFinderCache ref key = -  atomicModifyIORef' ref $ \c -> (delModuleEnv c key, ()) +  atomicModifyIORef' ref $ \c -> (delInstalledModuleEnv c key, ()) -lookupFinderCache :: IORef FinderCache -> VirginModule -> IO (Maybe FindResult) +lookupFinderCache :: IORef FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)  lookupFinderCache ref key = do     c <- readIORef ref -   return $! lookupModuleEnv c key +   return $! lookupInstalledModuleEnv c key  -- -----------------------------------------------------------------------------  -- The three external entry points @@ -131,11 +131,11 @@ findPluginModule hsc_env mod_name =  -- reading the interface for a module mentioned by another interface,  -- for example (a "system import"). -findExactModule :: HscEnv -> VirginModule -> IO FindResult +findExactModule :: HscEnv -> InstalledModule -> IO InstalledFindResult  findExactModule hsc_env mod =      let dflags = hsc_dflags hsc_env -    in if moduleUnitId mod == thisPackage dflags -       then findHomeModule hsc_env (moduleName mod) +    in if installedModuleUnitId mod `installedUnitIdEq` thisPackage dflags +       then findInstalledHomeModule hsc_env (installedModuleName mod)         else findPackageModule hsc_env mod  -- ----------------------------------------------------------------------------- @@ -169,9 +169,9 @@ orIfNotFound this or_this = do  -- been done.  Otherwise, do the lookup (with the IO action) and save  -- the result in the finder cache and the module location cache (if it  -- was successful.) -homeSearchCache :: HscEnv -> ModuleName -> IO FindResult -> IO FindResult +homeSearchCache :: HscEnv -> ModuleName -> IO InstalledFindResult -> IO InstalledFindResult  homeSearchCache hsc_env mod_name do_this = do -  let mod = mkModule (thisPackage (hsc_dflags hsc_env)) mod_name +  let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name    modLocationCache hsc_env mod do_this  findExposedPackageModule :: HscEnv -> ModuleName -> Maybe FastString @@ -190,8 +190,20 @@ findExposedPluginPackageModule hsc_env mod_name  findLookupResult :: HscEnv -> LookupResult -> IO FindResult  findLookupResult hsc_env r = case r of -     LookupFound m pkg_conf -> -       findPackageModule_ hsc_env m pkg_conf +     LookupFound m pkg_conf -> do +       let im = fst (splitModuleInsts m) +       r' <- findPackageModule_ hsc_env im pkg_conf +       case r' of +        -- TODO: ghc -M is unlikely to do the right thing +        -- with just the location of the thing that was +        -- instantiated; you probably also need all of the +        -- implicit locations from the instances +        InstalledFound loc   _ -> return (Found loc m) +        InstalledNoPackage   _ -> return (NoPackage (moduleUnitId m)) +        InstalledNotFound fp _ -> return (NotFound{ fr_paths = fp, fr_pkg = Just (moduleUnitId m) +                                         , fr_pkgs_hidden = [] +                                         , fr_mods_hidden = [] +                                         , fr_suggestions = []})       LookupMultiple rs ->         return (FoundMultiple rs)       LookupHidden pkg_hiddens mod_hiddens -> @@ -205,7 +217,7 @@ findLookupResult hsc_env r = case r of                         , fr_mods_hidden = []                         , fr_suggestions = suggest }) -modLocationCache :: HscEnv -> VirginModule -> IO FindResult -> IO FindResult +modLocationCache :: HscEnv -> InstalledModule -> IO InstalledFindResult -> IO InstalledFindResult  modLocationCache hsc_env mod do_this = do    m <- lookupFinderCache (hsc_FC hsc_env) mod    case m of @@ -215,20 +227,43 @@ modLocationCache hsc_env mod do_this = do          addToFinderCache (hsc_FC hsc_env) mod result          return result +mkHomeInstalledModule :: DynFlags -> ModuleName -> InstalledModule +mkHomeInstalledModule dflags mod_name = +  let iuid = fst (splitUnitIdInsts (thisPackage dflags)) +  in InstalledModule iuid mod_name + +-- This returns a module because it's more convenient for users  addHomeModuleToFinder :: HscEnv -> ModuleName -> ModLocation -> IO Module  addHomeModuleToFinder hsc_env mod_name loc = do -  let mod = mkModule (thisPackage (hsc_dflags hsc_env)) mod_name -  addToFinderCache (hsc_FC hsc_env) mod (Found loc mod) -  return mod +  let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name +  addToFinderCache (hsc_FC hsc_env) mod (InstalledFound loc mod) +  return (mkModule (thisPackage (hsc_dflags hsc_env)) mod_name)  uncacheModule :: HscEnv -> ModuleName -> IO () -uncacheModule hsc_env mod = do -  let this_pkg = thisPackage (hsc_dflags hsc_env) -  removeFromFinderCache (hsc_FC hsc_env) (mkModule this_pkg mod) +uncacheModule hsc_env mod_name = do +  let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name +  removeFromFinderCache (hsc_FC hsc_env) mod  -- -----------------------------------------------------------------------------  --      The internal workers +findHomeModule :: HscEnv -> ModuleName -> IO FindResult +findHomeModule hsc_env mod_name = do +  r <- findInstalledHomeModule hsc_env mod_name +  return $ case r of +    InstalledFound loc _ -> Found loc (mkModule uid mod_name) +    InstalledNoPackage _ -> NoPackage uid -- impossible +    InstalledNotFound fps _ -> NotFound { +        fr_paths = fps, +        fr_pkg = Just uid, +        fr_mods_hidden = [], +        fr_pkgs_hidden = [], +        fr_suggestions = [] +      } + where +  dflags = hsc_dflags hsc_env +  uid = thisPackage dflags +  -- | Implements the search for a module name in the home package only.  Calling  -- this function directly is usually *not* what you want; currently, it's used  -- as a building block for the following operations: @@ -245,14 +280,14 @@ uncacheModule hsc_env mod = do  --  --  4. Some special-case code in GHCi (ToDo: Figure out why that needs to  --  call this.) -findHomeModule :: HscEnv -> ModuleName -> IO FindResult -findHomeModule hsc_env mod_name = +findInstalledHomeModule :: HscEnv -> ModuleName -> IO InstalledFindResult +findInstalledHomeModule hsc_env mod_name =     homeSearchCache hsc_env mod_name $     let       dflags = hsc_dflags hsc_env       home_path = importPaths dflags       hisuf = hiSuf dflags -     mod = mkModule (thisPackage dflags) mod_name +     mod = mkHomeInstalledModule dflags mod_name       source_exts =        [ ("hs",   mkHomeModLocationSearched dflags mod_name "hs") @@ -275,20 +310,20 @@ findHomeModule hsc_env mod_name =    -- special case for GHC.Prim; we won't find it in the filesystem.    -- This is important only when compiling the base package (where GHC.Prim    -- is a home module). -  if mod == gHC_PRIM -        then return (Found (error "GHC.Prim ModLocation") mod) +  if mod `installedModuleEq` gHC_PRIM +        then return (InstalledFound (error "GHC.Prim ModLocation") mod)          else searchPathExts home_path mod exts  -- | Search for a module in external packages only. -findPackageModule :: HscEnv -> VirginModule -> IO FindResult +findPackageModule :: HscEnv -> InstalledModule -> IO InstalledFindResult  findPackageModule hsc_env mod = do    let          dflags = hsc_dflags hsc_env -        pkg_id = moduleUnitId mod +        pkg_id = installedModuleUnitId mod    -- -  case lookupPackage dflags pkg_id of -     Nothing -> return (NoPackage pkg_id) +  case lookupInstalledPackage dflags pkg_id of +     Nothing -> return (InstalledNoPackage pkg_id)       Just pkg_conf -> findPackageModule_ hsc_env mod pkg_conf  -- | Look up the interface file associated with module @mod@.  This function @@ -298,14 +333,14 @@ findPackageModule hsc_env mod = do  -- the 'PackageConfig' must be consistent with the unit id in the 'Module'.  -- The redundancy is to avoid an extra lookup in the package state  -- for the appropriate config. -findPackageModule_ :: HscEnv -> VirginModule -> PackageConfig -> IO FindResult +findPackageModule_ :: HscEnv -> InstalledModule -> PackageConfig -> IO InstalledFindResult  findPackageModule_ hsc_env mod pkg_conf = -  ASSERT( moduleUnitId mod == packageConfigId pkg_conf ) +  ASSERT( installedModuleUnitId mod == installedPackageConfigId pkg_conf )    modLocationCache hsc_env mod $    -- special case for GHC.Prim; we won't find it in the filesystem. -  if mod == gHC_PRIM -        then return (Found (error "GHC.Prim ModLocation") mod) +  if mod `installedModuleEq` gHC_PRIM +        then return (InstalledFound (error "GHC.Prim ModLocation") mod)          else    let @@ -326,9 +361,9 @@ findPackageModule_ hsc_env mod pkg_conf =      [one] | MkDepend <- ghcMode dflags -> do            -- there's only one place that this .hi file can be, so            -- don't bother looking for it. -          let basename = moduleNameSlashes (moduleName mod) +          let basename = moduleNameSlashes (installedModuleName mod)            loc <- mk_hi_loc one basename -          return (Found loc mod) +          return (InstalledFound loc mod)      _otherwise ->            searchPathExts import_dirs mod [(package_hisuf, mk_hi_loc)] @@ -337,13 +372,13 @@ findPackageModule_ hsc_env mod pkg_conf =  searchPathExts    :: [FilePath]         -- paths to search -  -> Module             -- module name +  -> InstalledModule             -- module name    -> [ (          FileExt,                                -- suffix          FilePath -> BaseName -> IO ModLocation  -- action         )       ] -  -> IO FindResult +  -> IO InstalledFindResult  searchPathExts paths mod exts     = do result <- search to_search @@ -358,7 +393,7 @@ searchPathExts paths mod exts          return result    where -    basename = moduleNameSlashes (moduleName mod) +    basename = moduleNameSlashes (installedModuleName mod)      to_search :: [(FilePath, IO ModLocation)]      to_search = [ (file, fn path basename) @@ -369,15 +404,12 @@ searchPathExts paths mod exts                        file = base <.> ext                  ] -    search [] = return (NotFound { fr_paths = map fst to_search -                                 , fr_pkg   = Just (moduleUnitId mod) -                                 , fr_mods_hidden = [], fr_pkgs_hidden = [] -                                 , fr_suggestions = [] }) +    search [] = return (InstalledNotFound (map fst to_search) (Just (installedModuleUnitId mod)))      search ((file, mk_result) : rest) = do        b <- doesFileExist file        if b -        then do { loc <- mk_result; return (Found loc mod) } +        then do { loc <- mk_result; return (InstalledFound loc mod) }          else search rest  mkHomeModLocationSearched :: DynFlags -> ModuleName -> FileExt @@ -539,9 +571,9 @@ cannotFindModule :: DynFlags -> ModuleName -> FindResult -> SDoc  cannotFindModule = cantFindErr (sLit "Could not find module")                                 (sLit "Ambiguous module name") -cannotFindInterface  :: DynFlags -> ModuleName -> FindResult -> SDoc -cannotFindInterface = cantFindErr (sLit "Failed to load interface for") -                                  (sLit "Ambiguous interface for") +cannotFindInterface  :: DynFlags -> ModuleName -> InstalledFindResult -> SDoc +cannotFindInterface = cantFindInstalledErr (sLit "Failed to load interface for") +                                           (sLit "Ambiguous interface for")  cantFindErr :: LitString -> LitString -> DynFlags -> ModuleName -> FindResult              -> SDoc @@ -581,7 +613,7 @@ cantFindErr cannot_find _ dflags mod_name find_result        = case find_result of              NoPackage pkg                  -> text "no unit id matching" <+> quotes (ppr pkg) <+> -                   text "was found" $$ looks_like_srcpkgid pkg +                   text "was found"              NotFound { fr_paths = files, fr_pkg = mb_pkg                       , fr_mods_hidden = mod_hiddens, fr_pkgs_hidden = pkg_hiddens @@ -642,18 +674,6 @@ cantFindErr cannot_find _ dflags mod_name find_result                text "to the build-depends in your .cabal file."       | otherwise = Outputable.empty -    looks_like_srcpkgid :: UnitId -> SDoc -    looks_like_srcpkgid pk -     -- Unsafely coerce a unit id FastString into a source package ID -     -- FastString and see if it means anything. -     | (pkg:pkgs) <- searchPackageId dflags (SourcePackageId (unitIdFS pk)) -     = parens (text "This unit ID looks like the source package ID;" $$ -       text "the real unit ID is" <+> quotes (ftext (unitIdFS (unitId pkg))) $$ -       (if null pkgs then Outputable.empty -        else text "and" <+> int (length pkgs) <+> text "other candidates")) -     -- Todo: also check if it looks like a package name! -     | otherwise = Outputable.empty -      mod_hidden pkg =          text "it is a hidden module in the package" <+> quotes (ppr pkg) @@ -693,3 +713,64 @@ cantFindErr cannot_find _ dflags mod_name find_result                   = parens (text "needs flag -package-id"                      <+> ppr (packageConfigId pkg))                | otherwise = Outputable.empty + +cantFindInstalledErr :: LitString -> LitString -> DynFlags -> ModuleName -> InstalledFindResult +            -> SDoc +cantFindInstalledErr cannot_find _ dflags mod_name find_result +  = ptext cannot_find <+> quotes (ppr mod_name) +    $$ more_info +  where +    more_info +      = case find_result of +            InstalledNoPackage pkg +                -> text "no unit id matching" <+> quotes (ppr pkg) <+> +                   text "was found" $$ looks_like_srcpkgid pkg + +            InstalledNotFound files mb_pkg +                | Just pkg <- mb_pkg, not (pkg `installedUnitIdEq` thisPackage dflags) +                -> not_found_in_package pkg files + +                | null files +                -> text "It is not a module in the current program, or in any known package." + +                | otherwise +                -> tried_these files + +            _ -> panic "cantFindInstalledErr" + +    build_tag = buildTag dflags + +    looks_like_srcpkgid :: InstalledUnitId -> SDoc +    looks_like_srcpkgid pk +     -- Unsafely coerce a unit id FastString into a source package ID +     -- FastString and see if it means anything. +     | (pkg:pkgs) <- searchPackageId dflags (SourcePackageId (installedUnitIdFS pk)) +     = parens (text "This unit ID looks like the source package ID;" $$ +       text "the real unit ID is" <+> quotes (ftext (installedUnitIdFS (unitId pkg))) $$ +       (if null pkgs then Outputable.empty +        else text "and" <+> int (length pkgs) <+> text "other candidates")) +     -- Todo: also check if it looks like a package name! +     | otherwise = Outputable.empty + +    not_found_in_package pkg files +       | build_tag /= "" +       = let +            build = if build_tag == "p" then "profiling" +                                        else "\"" ++ build_tag ++ "\"" +         in +         text "Perhaps you haven't installed the " <> text build <> +         text " libraries for package " <> quotes (ppr pkg) <> char '?' $$ +         tried_these files + +       | otherwise +       = text "There are files missing in the " <> quotes (ppr pkg) <> +         text " package," $$ +         text "try running 'ghc-pkg check'." $$ +         tried_these files + +    tried_these files +        | null files = Outputable.empty +        | verbosity dflags < 3 = +              text "Use -v to see a list of the files searched for." +        | otherwise = +               hang (text "Locations searched:") 2 $ vcat (map text files)  | 
