summaryrefslogtreecommitdiff
path: root/compiler/ghci
diff options
context:
space:
mode:
authorEdward Z. Yang <ezyang@cs.stanford.edu>2014-10-07 20:54:54 -0700
committerEdward Z. Yang <ezyang@cs.stanford.edu>2015-04-07 11:55:49 -0700
commita7524eaed33324e2155c47d4a705bef1d70a2b5b (patch)
treed3bb67c7cdfc5a6afa663484efe7b15c87ce43f1 /compiler/ghci
parenta058ad65e0936c1b7104ee976cbf80d97fd7232e (diff)
downloadhaskell-a7524eaed33324e2155c47d4a705bef1d70a2b5b.tar.gz
Support for multiple signature files in scope.
Summary: A common pattern when programming with signatures is to combine multiple signatures together (signature linking). We achieve this by making it not-an-error to have multiple, distinct interface files for the same module name, as long as they have the same backing implementation. When a user imports a module name, they get ALL matching signatures dumped into their scope. On the way, I refactored the module finder code, which now distinguishes between exact finds (when you had a 'Module') and regular finds (when you had a 'ModuleName'). I also refactored the package finder code to use a Monoid instance on LookupResult to collect together various results. ToDo: At the moment, if a signature is declared in the local package, it completely overrides any remote signatures. Eventually, we'll want to also pull in the remote signatures (or even override the local signature, if the full implementation is available.) There are bunch of ToDos in the code for what to do once this is done. ToDo: At the moment, whenever a module name lookup occurs in GHCi and we would have seen a signature, we instead continue and return the Module for the backing implementation. This is correct for most cases, but there might be some situations where we want something a little more fine-grained (e.g. :browse should only list identifiers which are available through the in-scope signatures, and not ALL of them.) Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu> Test Plan: validate Reviewers: simonpj, hvr, austin Subscribers: carter, thomie Differential Revision: https://phabricator.haskell.org/D790 GHC Trac Issues: #9252
Diffstat (limited to 'compiler/ghci')
-rw-r--r--compiler/ghci/Linker.hs46
1 files changed, 30 insertions, 16 deletions
diff --git a/compiler/ghci/Linker.hs b/compiler/ghci/Linker.hs
index 9446e3df2b..cec09048c2 100644
--- a/compiler/ghci/Linker.hs
+++ b/compiler/ghci/Linker.hs
@@ -562,23 +562,29 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
-- 3. For each dependent module, find its linkable
-- This will either be in the HPT or (in the case of one-shot
- -- compilation) we may need to use maybe_getFileLinkable
+ -- compilation) we may need to use maybe_getFileLinkable.
+ -- If the module is actually a signature, there won't be a
+ -- linkable (thus catMaybes)
; let { osuf = objectSuf dflags }
- ; lnks_needed <- mapM (get_linkable osuf) mods_needed
+ ; lnks_needed <- fmap Maybes.catMaybes
+ $ mapM (get_linkable osuf) mods_needed
; return (lnks_needed, pkgs_needed) }
where
dflags = hsc_dflags hsc_env
this_pkg = thisPackage dflags
- -- The ModIface contains the transitive closure of the module dependencies
- -- within the current package, *except* for boot modules: if we encounter
- -- a boot module, we have to find its real interface and discover the
- -- dependencies of that. Hence we need to traverse the dependency
- -- tree recursively. See bug #936, testcase ghci/prog007.
- follow_deps :: [Module] -- modules to follow
- -> UniqSet ModuleName -- accum. module dependencies
- -> UniqSet PackageKey -- accum. package dependencies
+ -- | Given a list of modules @mods@, recursively discover all external
+ -- package and local module (according to @this_pkg@) dependencies.
+ --
+ -- The 'ModIface' contains the transitive closure of the module dependencies
+ -- within the current package, *except* for boot modules: if we encounter
+ -- a boot module, we have to find its real interface and discover the
+ -- dependencies of that. Hence we need to traverse the dependency
+ -- tree recursively. See bug #936, testcase ghci/prog007.
+ follow_deps :: [Module] -- modules to follow
+ -> UniqSet ModuleName -- accum. module dependencies
+ -> UniqSet PackageKey -- accum. package dependencies
-> IO ([ModuleName], [PackageKey]) -- result
follow_deps [] acc_mods acc_pkgs
= return (uniqSetToList acc_mods, uniqSetToList acc_pkgs)
@@ -601,6 +607,7 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
where is_boot (m,True) = Left m
is_boot (m,False) = Right m
+ -- Boot module dependencies which must be processed recursively
boot_deps' = filter (not . (`elementOfUniqSet` acc_mods)) boot_deps
acc_mods' = addListToUniqSet acc_mods (moduleName mod : mod_deps)
acc_pkgs' = addListToUniqSet acc_pkgs $ map fst pkg_deps
@@ -631,30 +638,37 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
get_linkable osuf mod_name -- A home-package module
| Just mod_info <- lookupUFM hpt mod_name
- = adjust_linkable (Maybes.expectJust "getLinkDeps" (hm_linkable mod_info))
+ = adjust_linkable (hm_iface mod_info)
+ (Maybes.expectJust "getLinkDeps" (hm_linkable mod_info))
| otherwise
= do -- It's not in the HPT because we are in one shot mode,
-- so use the Finder to get a ModLocation...
+ -- ezyang: I don't actually know how to trigger this codepath,
+ -- seeing as this is GHCi logic. Template Haskell, maybe?
mb_stuff <- findHomeModule hsc_env mod_name
case mb_stuff of
- Found loc mod -> found loc mod
+ FoundExact loc mod -> found loc mod
_ -> no_obj mod_name
where
found loc mod = do {
-- ...and then find the linkable for it
mb_lnk <- findObjectLinkableMaybe mod loc ;
+ iface <- initIfaceCheck hsc_env $
+ loadUserInterface False (text "getLinkDeps2") mod ;
case mb_lnk of {
Nothing -> no_obj mod ;
- Just lnk -> adjust_linkable lnk
+ Just lnk -> adjust_linkable iface lnk
}}
- adjust_linkable lnk
+ adjust_linkable iface lnk
+ -- Signatures have no linkables! Don't return one.
+ | Just _ <- mi_sig_of iface = return Nothing
| Just new_osuf <- replace_osuf = do
new_uls <- mapM (adjust_ul new_osuf)
(linkableUnlinked lnk)
- return lnk{ linkableUnlinked=new_uls }
+ return (Just lnk{ linkableUnlinked=new_uls })
| otherwise =
- return lnk
+ return (Just lnk)
adjust_ul new_osuf (DotO file) = do
MASSERT(osuf `isSuffixOf` file)