1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveGeneric #-}
3-- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst>
4module Distribution.Backpack.ModuleShape (
5    -- * Module shapes
6    ModuleShape(..),
7    emptyModuleShape,
8    shapeInstalledPackage,
9) where
10
11import Prelude ()
12import Distribution.Compat.Prelude hiding (mod)
13
14import Distribution.ModuleName
15import Distribution.InstalledPackageInfo as IPI
16
17import Distribution.Backpack.ModSubst
18import Distribution.Backpack
19
20import qualified Data.Map as Map
21import qualified Data.Set as Set
22
23-----------------------------------------------------------------------
24-- Module shapes
25
26-- | A 'ModuleShape' describes the provisions and requirements of
27-- a library.  We can extract a 'ModuleShape' from an
28-- 'InstalledPackageInfo'.
29data ModuleShape = ModuleShape {
30    modShapeProvides :: OpenModuleSubst,
31    modShapeRequires :: Set ModuleName
32    }
33    deriving (Eq, Show, Generic, Typeable)
34
35instance Binary ModuleShape
36instance Structured ModuleShape
37
38instance ModSubst ModuleShape where
39    modSubst subst (ModuleShape provs reqs)
40        = ModuleShape (modSubst subst provs) (modSubst subst reqs)
41
42-- | The default module shape, with no provisions and no requirements.
43emptyModuleShape :: ModuleShape
44emptyModuleShape = ModuleShape Map.empty Set.empty
45
46-- Food for thought: suppose we apply the Merkel tree optimization.
47-- Imagine this situation:
48--
49--      component p
50--          signature H
51--          module P
52--      component h
53--          module H
54--      component a
55--          signature P
56--          module A
57--      component q(P)
58--          include p
59--          include h
60--      component r
61--          include q (P)
62--          include p (P) requires (H)
63--          include h (H)
64--          include a (A) requires (P)
65--
66-- Component r should not have any conflicts, since after mix-in linking
67-- the two P imports will end up being the same, so we can properly
68-- instantiate it.  But to know that q's P is p:P instantiated with h:H,
69-- we have to be able to expand its unit id.  Maybe we can expand it
70-- lazily but in some cases it will need to be expanded.
71--
72-- FWIW, the way that GHC handles this is by improving unit IDs as
73-- soon as it sees an improved one in the package database.  This
74-- is a bit disgusting.
75shapeInstalledPackage :: IPI.InstalledPackageInfo -> ModuleShape
76shapeInstalledPackage ipi = ModuleShape (Map.fromList provs) reqs
77  where
78    uid = installedOpenUnitId ipi
79    provs = map shapeExposedModule (IPI.exposedModules ipi)
80    reqs = requiredSignatures ipi
81    shapeExposedModule (IPI.ExposedModule mod_name Nothing)
82        = (mod_name, OpenModule uid mod_name)
83    shapeExposedModule (IPI.ExposedModule mod_name (Just mod))
84        = (mod_name, mod)
85