Skip to content

Commit 69b38ad

Browse files
committed
fix(cabal-install): rewrite instantiateInstallPlan
1 parent f5e1246 commit 69b38ad

File tree

1 file changed

+167
-136
lines changed

1 file changed

+167
-136
lines changed

cabal-install/src/Distribution/Client/ProjectPlanning.hs

Lines changed: 167 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ import Distribution.Types.PackageVersionConstraint
204204
import Distribution.Types.PkgconfigDependency
205205
import Distribution.Types.UnqualComponentName
206206

207-
import Distribution.Backpack
207+
import Distribution.Backpack hiding (mkDefUnitId)
208208
import Distribution.Backpack.ComponentsGraph
209209
import Distribution.Backpack.ConfiguredComponent
210210
import Distribution.Backpack.FullUnitId
@@ -229,7 +229,7 @@ import qualified Distribution.Compat.Graph as Graph
229229
import Control.Exception (assert)
230230
import Control.Monad (sequence)
231231
import Control.Monad.IO.Class (liftIO)
232-
import Control.Monad.State as State (State, execState, runState, state)
232+
import Control.Monad.State (State, execState, gets, modify)
233233
import Data.Foldable (fold)
234234
import Data.List (deleteBy, groupBy)
235235
import qualified Data.List.NonEmpty as NE
@@ -2791,7 +2791,7 @@ binDirectories layout config package = case elabBuildStyle package of
27912791
distBuildDirectory layout (elabDistDirParams config package)
27922792
</> "build"
27932793

2794-
type InstS = Map UnitId ElaboratedPlanPackage
2794+
type InstS = Map (WithStage UnitId) ElaboratedPlanPackage
27952795
type InstM a = State InstS a
27962796

27972797
getComponentId
@@ -2875,67 +2875,75 @@ instantiateInstallPlan storeDirLayout defaultInstallDirs elaboratedShared plan =
28752875
where
28762876
pkgs = InstallPlan.toList plan
28772877

2878-
cmap = Map.fromList [(getComponentId pkg, pkg) | pkg <- pkgs]
2878+
cmap = Map.fromList [(WithStage (stageOf pkg) (getComponentId pkg), pkg) | pkg <- pkgs]
28792879

28802880
instantiateUnitId
2881-
:: ComponentId
2881+
:: Stage
2882+
-> ComponentId
2883+
-- \^ The id of the component being instantiated
28822884
-> Map ModuleName (Module, BuildStyle)
2885+
-- \^ A mapping from module names (the "holes" or signatures in Backpack)
2886+
-- to the concrete modules (and their build styles) that should fill those
2887+
-- holes.
28832888
-> InstM (DefUnitId, BuildStyle)
2884-
instantiateUnitId cid insts = state $ \s ->
2885-
case Map.lookup uid s of
2886-
Nothing ->
2887-
-- Knot tied
2888-
-- TODO: I don't think the knot tying actually does
2889-
-- anything useful
2890-
let (r, s') =
2891-
runState
2892-
(instantiateComponent uid cid insts)
2893-
(Map.insert uid r s)
2894-
in ((def_uid, extractElabBuildStyle r), Map.insert uid r s')
2895-
Just r -> ((def_uid, extractElabBuildStyle r), s)
2889+
instantiateUnitId stage cid insts =
2890+
gets (Map.lookup (WithStage stage uid)) >>= \case
2891+
Nothing -> do
2892+
r <- instantiateComponent uid (WithStage stage cid) insts
2893+
modify (Map.insert (WithStage stage uid) r)
2894+
return (unsafeMkDefUnitId uid, extractElabBuildStyle r)
2895+
Just r ->
2896+
return (unsafeMkDefUnitId uid, extractElabBuildStyle r)
28962897
where
2897-
def_uid = mkDefUnitId cid (fmap fst insts)
2898-
uid = unDefUnitId def_uid
2898+
uid = mkDefUnitId cid (fmap fst insts)
28992899

29002900
-- No need to InplaceT; the inplace-ness is properly computed for
29012901
-- the ElaboratedPlanPackage, so that will implicitly pass it on
29022902
instantiateComponent
29032903
:: UnitId
2904-
-> ComponentId
2904+
-- \^ The unit id to assign to the instantiated component
2905+
-> WithStage ComponentId
2906+
-- \^ The id of the component being instantiated
29052907
-> Map ModuleName (Module, BuildStyle)
2908+
-- \^ A mapping from module names (the "holes" or signatures in Backpack)
2909+
-- to the concrete modules (and their build styles) that should fill those
2910+
-- holes.
29062911
-> InstM ElaboratedPlanPackage
2907-
instantiateComponent uid cid insts
2908-
| Just planpkg <- Map.lookup cid cmap =
2912+
instantiateComponent uid cidws@(WithStage stage cid) insts =
2913+
case Map.lookup cidws cmap of
2914+
Nothing -> error ("instantiateComponent: " ++ prettyShow cid)
2915+
Just planpkg ->
29092916
case planpkg of
2910-
InstallPlan.Configured
2911-
( elab0@ElaboratedConfiguredPackage
2912-
{ elabPkgOrComp = ElabComponent comp
2913-
}
2914-
) -> do
2915-
deps <-
2916-
traverse (fmap fst . substUnitId insts) (compLinkedLibDependencies comp)
2917-
let build_style = fold (fmap snd insts)
2918-
let getDep (Module dep_uid _) = [dep_uid]
2919-
elab1 =
2920-
fixupBuildStyle build_style $
2921-
elab0
2922-
{ elabUnitId = uid
2923-
, elabComponentId = cid
2924-
, elabIsCanonical = Map.null (fmap fst insts)
2925-
, elabPkgOrComp =
2926-
ElabComponent
2927-
comp
2928-
{ compOrderLibDependencies =
2929-
(if Map.null insts then [] else [newSimpleUnitId cid])
2930-
++ ordNub
2931-
( map
2932-
unDefUnitId
2933-
(deps ++ concatMap (getDep . fst) (Map.elems insts))
2934-
)
2935-
, compInstantiatedWith = fmap fst insts
2936-
}
2937-
}
2938-
elab =
2917+
InstallPlan.Installed{} -> return planpkg
2918+
InstallPlan.PreExisting{} -> return planpkg
2919+
InstallPlan.Configured elab0 ->
2920+
case elabPkgOrComp elab0 of
2921+
ElabPackage{} -> return planpkg
2922+
ElabComponent comp -> do
2923+
deps <- traverse (fmap fst . instantiateUnit stage insts) (compLinkedLibDependencies comp)
2924+
let build_style = fold (fmap snd insts)
2925+
let getDep (Module dep_uid _) = [dep_uid]
2926+
elab1 =
2927+
fixupBuildStyle build_style $
2928+
elab0
2929+
{ elabUnitId = uid
2930+
, elabComponentId = cid
2931+
, elabIsCanonical = Map.null (fmap fst insts)
2932+
, elabPkgOrComp =
2933+
ElabComponent
2934+
comp
2935+
{ compOrderLibDependencies =
2936+
(if Map.null insts then [] else [newSimpleUnitId cid])
2937+
++ ordNub
2938+
( map
2939+
unDefUnitId
2940+
(deps ++ concatMap (getDep . fst) (Map.elems insts))
2941+
)
2942+
, compInstantiatedWith = fmap fst insts
2943+
}
2944+
}
2945+
return $
2946+
InstallPlan.Configured
29392947
elab1
29402948
{ elabInstallDirs =
29412949
computeInstallDirs
@@ -2944,112 +2952,135 @@ instantiateInstallPlan storeDirLayout defaultInstallDirs elaboratedShared plan =
29442952
elaboratedShared
29452953
elab1
29462954
}
2947-
return $ InstallPlan.Configured elab
2948-
_ -> return planpkg
2949-
| otherwise = error ("instantiateComponent: " ++ prettyShow cid)
29502955

2951-
substUnitId :: Map ModuleName (Module, BuildStyle) -> OpenUnitId -> InstM (DefUnitId, BuildStyle)
2952-
substUnitId _ (DefiniteUnitId uid) =
2956+
-- \| Instantiates an OpenUnitId into a concrete UnitId, producing a concrete UnitId and its associated BuildStyle.
2957+
--
2958+
-- This function recursively applies a module substitution to an OpenUnitId, producing a fully instantiated
2959+
-- (definite) unit and its build style. This is a key step in Backpack-style instantiation, where "holes" in
2960+
-- a package are filled with concrete modules.
2961+
--
2962+
-- Behavior
2963+
--
2964+
-- If given a DefiniteUnitId, it returns the id and a default build style (BuildAndInstall).
2965+
--
2966+
-- If given an IndefFullUnitId, it:
2967+
-- Recursively applies the substitution to each module in the instantiation map using substSubst.
2968+
-- Calls instantiateUnitId to create or retrieve the fully instantiated unit id and build style for this instantiation.
2969+
--
2970+
instantiateUnit
2971+
:: Stage
2972+
-> Map ModuleName (Module, BuildStyle)
2973+
-- \^ A mapping from module names to their corresponding modules and build styles.
2974+
-> OpenUnitId
2975+
-- \^ The unit to instantiate. This can be:
2976+
-- DefiniteUnitId uid: already fully instantiated (no holes).
2977+
-- IndefFullUnitId cid insts: an indefinite unit (with holes), described by a component id and a mapping of holes to modules.
2978+
-> InstM (DefUnitId, BuildStyle)
2979+
instantiateUnit _stage _subst (DefiniteUnitId def_uid) =
29532980
-- This COULD actually, secretly, be an inplace package, but in
29542981
-- that case it doesn't matter as it's already been recorded
29552982
-- in the package that depends on this
2956-
return (uid, BuildAndInstall)
2957-
substUnitId subst (IndefFullUnitId cid insts) = do
2958-
insts' <- substSubst subst insts
2959-
instantiateUnitId cid insts'
2960-
2961-
-- NB: NOT composition
2962-
substSubst
2963-
:: Map ModuleName (Module, BuildStyle)
2964-
-> Map ModuleName OpenModule
2965-
-> InstM (Map ModuleName (Module, BuildStyle))
2966-
substSubst subst insts = traverse (substModule subst) insts
2967-
2968-
substModule :: Map ModuleName (Module, BuildStyle) -> OpenModule -> InstM (Module, BuildStyle)
2969-
substModule subst (OpenModuleVar mod_name)
2983+
return (def_uid, BuildAndInstall)
2984+
instantiateUnit stage subst (IndefFullUnitId cid insts) = do
2985+
insts' <- traverse (instantiateModule stage subst) insts
2986+
instantiateUnitId stage cid insts'
2987+
2988+
-- \| Instantiates an OpenModule into a concrete Module producing a concrete Module
2989+
-- and its associated BuildStyle.
2990+
instantiateModule
2991+
:: Stage
2992+
-> Map ModuleName (Module, BuildStyle)
2993+
-- \^ A mapping from module names to their corresponding modules and build styles.
2994+
-> OpenModule
2995+
-- \^ The module to substitute, which can be:
2996+
-- OpenModuleVar mod_name: a hole (variable) named mod_name
2997+
-- OpenModule uid mod_name: a module from a specific unit (uid).
2998+
-> InstM (Module, BuildStyle)
2999+
instantiateModule _stage subst (OpenModuleVar mod_name)
29703000
| Just m <- Map.lookup mod_name subst = return m
29713001
| otherwise = error "substModule: non-closing substitution"
2972-
substModule subst (OpenModule uid mod_name) = do
2973-
(uid', build_style) <- substUnitId subst uid
3002+
instantiateModule stage subst (OpenModule uid mod_name) = do
3003+
(uid', build_style) <- instantiateUnit stage subst uid
29743004
return (Module uid' mod_name, build_style)
29753005

2976-
indefiniteUnitId :: ComponentId -> InstM UnitId
2977-
indefiniteUnitId cid = do
2978-
let uid = newSimpleUnitId cid
2979-
r <- indefiniteComponent uid cid
2980-
state $ \s -> (uid, Map.insert uid r s)
2981-
2982-
indefiniteComponent :: UnitId -> ComponentId -> InstM ElaboratedPlanPackage
2983-
indefiniteComponent _uid cid
2984-
-- Only need Configured; this phase happens before improvement, so
2985-
-- there shouldn't be any Installed packages here.
2986-
| Just (InstallPlan.Configured epkg) <- Map.lookup cid cmap
2987-
, ElabComponent elab_comp <- elabPkgOrComp epkg =
2988-
do
2989-
-- We need to do a little more processing of the includes: some
2990-
-- of them are fully definite even without substitution. We
2991-
-- want to build those too; see #5634.
2992-
--
2993-
-- This code mimics similar code in Distribution.Backpack.ReadyComponent;
2994-
-- however, unlike the conversion from LinkedComponent to
2995-
-- ReadyComponent, this transformation is done *without*
2996-
-- changing the type in question; and what we are simply
2997-
-- doing is enforcing tighter invariants on the data
2998-
-- structure in question. The new invariant is that there
2999-
-- is no IndefFullUnitId in compLinkedLibDependencies that actually
3000-
-- has no holes. We couldn't specify this invariant when
3001-
-- we initially created the ElaboratedPlanPackage because
3002-
-- we have no way of actually reifying the UnitId into a
3003-
-- DefiniteUnitId (that's what substUnitId does!)
3004-
new_deps <- for (compLinkedLibDependencies elab_comp) $ \uid ->
3005-
if Set.null (openUnitIdFreeHoles uid)
3006-
then fmap (DefiniteUnitId . fst) (substUnitId Map.empty uid)
3007-
else return uid
3008-
-- NB: no fixupBuildStyle needed here, as if the indefinite
3009-
-- component depends on any inplace packages, it itself must
3010-
-- be indefinite! There is no substitution here, we can't
3011-
-- post facto add inplace deps
3012-
return . InstallPlan.Configured $
3013-
epkg
3014-
{ elabPkgOrComp =
3015-
ElabComponent
3016-
elab_comp
3017-
{ compLinkedLibDependencies = new_deps
3018-
, -- I think this is right: any new definite unit ids we
3019-
-- minted in the phase above need to be built before us.
3020-
-- Add 'em in. This doesn't remove any old dependencies
3021-
-- on the indefinite package; they're harmless.
3022-
compOrderLibDependencies =
3023-
ordNub $
3024-
compOrderLibDependencies elab_comp
3025-
++ [unDefUnitId d | DefiniteUnitId d <- new_deps]
3026-
}
3027-
}
3028-
| Just planpkg <- Map.lookup cid cmap =
3029-
return planpkg
3030-
| otherwise = error ("indefiniteComponent: " ++ prettyShow cid)
3006+
indefiniteComponent
3007+
:: ElaboratedConfiguredPackage
3008+
-> InstM ElaboratedConfiguredPackage
3009+
indefiniteComponent epkg =
3010+
case elabPkgOrComp epkg of
3011+
ElabPackage{} -> return epkg
3012+
ElabComponent elab_comp -> do
3013+
-- We need to do a little more processing of the includes: some
3014+
-- of them are fully definite even without substitution. We
3015+
-- want to build those too; see #5634.
3016+
--
3017+
-- This code mimics similar code in Distribution.Backpack.ReadyComponent;
3018+
-- however, unlike the conversion from LinkedComponent to
3019+
-- ReadyComponent, this transformation is done *without*
3020+
-- changing the type in question; and what we are simply
3021+
-- doing is enforcing tighter invariants on the data
3022+
-- structure in question. The new invariant is that there
3023+
-- is no IndefFullUnitId in compLinkedLibDependencies that actually
3024+
-- has no holes. We couldn't specify this invariant when
3025+
-- we initially created the ElaboratedPlanPackage because
3026+
-- we have no way of actually reifying the UnitId into a
3027+
-- DefiniteUnitId (that's what substUnitId does!)
3028+
new_deps <- for (compLinkedLibDependencies elab_comp) $ \uid ->
3029+
if Set.null (openUnitIdFreeHoles uid)
3030+
then fmap (DefiniteUnitId . fst) (instantiateUnit (elabStage epkg) Map.empty uid)
3031+
else return uid
3032+
-- NB: no fixupBuildStyle needed here, as if the indefinite
3033+
-- component depends on any inplace packages, it itself must
3034+
-- be indefinite! There is no substitution here, we can't
3035+
-- post facto add inplace deps
3036+
return
3037+
epkg
3038+
{ elabPkgOrComp =
3039+
ElabComponent
3040+
elab_comp
3041+
{ compLinkedLibDependencies = new_deps
3042+
, -- I think this is right: any new definite unit ids we
3043+
-- minted in the phase above need to be built before us.
3044+
-- Add 'em in. This doesn't remove any old dependencies
3045+
-- on the indefinite package; they're harmless.
3046+
compOrderLibDependencies =
3047+
ordNub $
3048+
compOrderLibDependencies elab_comp
3049+
++ [unDefUnitId d | DefiniteUnitId d <- new_deps]
3050+
}
3051+
}
30313052

30323053
fixupBuildStyle BuildAndInstall elab = elab
3033-
fixupBuildStyle _ (elab@ElaboratedConfiguredPackage{elabBuildStyle = BuildInplaceOnly{}}) = elab
3034-
fixupBuildStyle t@(BuildInplaceOnly{}) elab =
3054+
fixupBuildStyle _buildStyle (elab@ElaboratedConfiguredPackage{elabBuildStyle = BuildInplaceOnly{}}) = elab
3055+
fixupBuildStyle buildStyle@(BuildInplaceOnly{}) elab =
30353056
elab
3036-
{ elabBuildStyle = t
3057+
{ elabBuildStyle = buildStyle
30373058
, elabBuildPackageDBStack = elabInplaceBuildPackageDBStack elab
30383059
, elabRegisterPackageDBStack = elabInplaceRegisterPackageDBStack elab
30393060
, elabSetupPackageDBStack = elabInplaceSetupPackageDBStack elab
30403061
}
30413062

30423063
ready_map = execState work Map.empty
3043-
30443064
work = for_ pkgs $ \pkg ->
30453065
case pkg of
30463066
InstallPlan.Configured (elab@ElaboratedConfiguredPackage{elabPkgOrComp = ElabComponent comp})
3047-
| not (Map.null (compLinkedInstantiatedWith comp)) ->
3048-
indefiniteUnitId (elabComponentId elab)
3049-
>> return ()
3067+
| not (Map.null (compLinkedInstantiatedWith comp)) -> do
3068+
r <- indefiniteComponent elab
3069+
modify (Map.insert (WithStage (elabStage elab) (elabUnitId elab)) (InstallPlan.Configured r))
30503070
_ ->
3051-
instantiateUnitId (getComponentId pkg) Map.empty
3052-
>> return ()
3071+
void $ instantiateUnitId (stageOf pkg) (getComponentId pkg) Map.empty
3072+
3073+
-- | Create a 'DefUnitId' from a 'ComponentId' and an instantiation
3074+
-- with no holes.
3075+
--
3076+
-- This function is defined in Cabal-syntax but only cabal-install
3077+
-- cares about it so I am putting it here.
3078+
--
3079+
-- I am also not using the DefUnitId newtype since I believe it
3080+
-- provides little value in the code above.
3081+
mkDefUnitId :: ComponentId -> Map ModuleName Module -> UnitId
3082+
mkDefUnitId cid insts =
3083+
mkUnitId (unComponentId cid ++ maybe "" ("+" ++) (hashModuleSubst insts))
30533084

30543085
---------------------------
30553086
-- Build targets

0 commit comments

Comments
 (0)