Cabal-2.0.0.2: Distribution/Backpack/ModuleScope.hs
-- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst>
module Distribution.Backpack.ModuleScope (
-- * Module scopes
ModuleScope(..),
ModuleProvides,
ModuleRequires,
ModuleSource(..),
emptyModuleScope,
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.ModuleName
import Distribution.Types.IncludeRenaming
import Distribution.Types.PackageName
import Distribution.Types.ComponentName
import Distribution.Backpack
import Distribution.Backpack.ModSubst
import qualified Data.Map as Map
-----------------------------------------------------------------------
-- Module scopes
-- Why is ModuleProvides so complicated? The basic problem is that
-- we want to support this:
--
-- package p where
-- include q (A)
-- include r (A)
-- module B where
-- import "q" A
-- import "r" A
--
-- Specifically, in Cabal today it is NOT an error have two modules in
-- scope with the same identifier. So we need to preserve this for
-- Backpack. The modification is that an ambiguous module name is
-- OK... as long as it is NOT used to fill a requirement!
--
-- So as a first try, we might try deferring unifying provisions that
-- are being glommed together, and check for equality after the fact.
-- But this doesn't work, because what if a multi-module provision
-- is used to fill a requirement?! So you do the equality test
-- IMMEDIATELY before a requirement fill happens... or never at all.
--
-- Alternate strategy: go ahead and unify, and then if it is revealed
-- that some requirements got filled "out-of-thin-air", error.
-- | A 'ModuleScope' describes the modules and requirements that
-- are in-scope as we are processing a Cabal package. Unlike
-- a 'ModuleShape', there may be multiple modules in scope at
-- the same 'ModuleName'; this is only an error if we attempt
-- to use those modules to fill a requirement. A 'ModuleScope'
-- can influence the 'ModuleShape' via a reexport.
data ModuleScope = ModuleScope {
modScopeProvides :: ModuleProvides,
modScopeRequires :: ModuleRequires
}
-- | Every 'Module' in scope at a 'ModuleName' is annotated with
-- the 'PackageName' it comes from.
type ModuleProvides = Map ModuleName [ModuleSource]
-- | INVARIANT: entries for ModuleName m, have msrc_module is OpenModuleVar m
type ModuleRequires = Map ModuleName [ModuleSource]
-- TODO: consider newtping the two types above.
data ModuleSource =
ModuleSource {
-- We don't have line numbers, but if we did the
-- package name and renaming could be associated
-- with that as well
msrc_pkgname :: PackageName,
msrc_compname :: ComponentName,
msrc_renaming :: IncludeRenaming,
msrc_module :: OpenModule,
msrc_implicit :: Bool
}
-- | An empty 'ModuleScope'.
emptyModuleScope :: ModuleScope
emptyModuleScope = ModuleScope Map.empty Map.empty
instance ModSubst ModuleSource where
modSubst subst src = src { msrc_module = modSubst subst (msrc_module src) }