@@ -3766,6 +3766,11 @@ pruneInstallPlanPass2 pkgs =
37663766 elabBuildTargets elab
37673767 ++ libTargetsRequiredForRevDeps
37683768 ++ exeTargetsRequiredForRevDeps
3769+ , elabBuildStyle =
3770+ if installedUnitId elab `Set.member` mustBuildOnDisk
3771+ && elabBuildStyle elab == BuildInplaceOnly InMemory
3772+ then BuildInplaceOnly OnDisk
3773+ else elabBuildStyle elab
37693774 , elabPkgOrComp =
37703775 case elabPkgOrComp elab of
37713776 ElabPackage pkg ->
@@ -3802,10 +3807,13 @@ pruneInstallPlanPass2 pkgs =
38023807
38033808 libTargetsRequiredForRevDeps =
38043809 [ c
3805- | installedUnitId elab `Set.member` hasReverseLibDeps
3810+ | installedUnitId elab `Set.member` libDeps
38063811 , let c = ComponentTarget (CLibName Cabal. defaultLibName) WholeComponent
3807- , -- Don't enable building for anything which is being build in memory
3812+ , -- Don't enable building for anything which is being built in memory,
3813+ -- unless it is a (transitive) library dependency of an exe build tool,
3814+ -- in which case it must be compiled to disk so the exe can link against it.
38083815 elabBuildStyle elab /= BuildInplaceOnly InMemory
3816+ || installedUnitId elab `Set.member` mustBuildOnDisk
38093817 ]
38103818 exeTargetsRequiredForRevDeps =
38113819 -- TODO: allow requesting executable with different name
@@ -3817,35 +3825,73 @@ pruneInstallPlanPass2 pkgs =
38173825 elabPkgSourceId elab
38183826 )
38193827 WholeComponent
3820- | installedUnitId elab `Set.member` hasReverseExeDeps
3828+ | installedUnitId elab `Set.member` exeDeps
38213829 ]
38223830
38233831 availablePkgs :: Set UnitId
38243832 availablePkgs = Set. fromList (map installedUnitId pkgs)
38253833
38263834 inMemoryTargets :: Set ConfiguredId
3827- inMemoryTargets = do
3835+ inMemoryTargets =
38283836 Set. fromList
38293837 [ configuredId pkg
38303838 | InstallPlan. Configured pkg <- pkgs
3839+ , -- Exclude packages that must be built on disk (for exe build tools).
3840+ -- Their dependents will receive a real -package-id, not a promise.
3841+ installedUnitId pkg `Set.notMember` mustBuildOnDisk
38313842 , BuildInplaceOnly InMemory <- [elabBuildStyle pkg]
38323843 ]
38333844
3834- hasReverseLibDeps :: Set UnitId
3835- hasReverseLibDeps =
3836- Set. fromList
3837- [ depid
3838- | InstallPlan. Configured pkg <- pkgs
3839- , depid <- elabOrderLibDependencies pkg
3840- ]
3845+ -- Packages that must be built on disk because they are (transitively)
3846+ -- needed as library dependencies by an exe build-tool. Even if such a
3847+ -- package was originally marked InMemory for the multi-repl session, it
3848+ -- must also produce real on-disk artifacts so the exe can link against it.
3849+ -- The repl phase still runs for these packages, so GHCi loads them from
3850+ -- source under the same package-id, preserving type identity.
3851+ mustBuildOnDisk :: Set UnitId
3852+ mustBuildOnDisk = go exeDeps Set. empty
3853+ where
3854+ go frontier visited
3855+ | Set. null frontier = visited
3856+ | otherwise =
3857+ let newVisited = visited <> frontier
3858+ newFrontier =
3859+ Set. fromList
3860+ [ dep
3861+ | uid <- Set. toList frontier
3862+ , dep <- Map. findWithDefault [] uid planLibDepMap
3863+ ]
3864+ Set. \\ newVisited
3865+ in go newFrontier newVisited
3866+
3867+ -- Lib and exe deps computed once per in-plan package, shared below.
3868+ -- Note: these must be the order-dependency UnitIds, which match the
3869+ -- 'installedUnitId' of the units in the plan; in particular for
3870+ -- Backpack-instantiated units they include the instantiation, unlike
3871+ -- the ComponentIds from 'elabLibDependencies'.
3872+ perPkgDeps :: [(UnitId , [UnitId ], [UnitId ])]
3873+ perPkgDeps =
3874+ [ ( installedUnitId pkg
3875+ , elabOrderLibDependencies pkg
3876+ , elabOrderExeDependencies pkg
3877+ )
3878+ | InstallPlan. Configured pkg <- pkgs
3879+ ]
38413880
3842- hasReverseExeDeps :: Set UnitId
3843- hasReverseExeDeps =
3844- Set. fromList
3845- [ depid
3846- | InstallPlan. Configured pkg <- pkgs
3847- , depid <- elabOrderExeDependencies pkg
3848- ]
3881+ -- Library-dependency adjacency for in-plan packages only.
3882+ planLibDepMap :: Map UnitId [UnitId ]
3883+ planLibDepMap =
3884+ Map. fromList [(uid, ls) | (uid, ls, _) <- perPkgDeps]
3885+
3886+ -- All packages that appear as a library dep of any in-plan package.
3887+ libDeps :: Set UnitId
3888+ libDeps =
3889+ Set. fromList [d | (_, ls, _) <- perPkgDeps, d <- ls]
3890+
3891+ -- All packages that appear as an exe dep of any in-plan package.
3892+ exeDeps :: Set UnitId
3893+ exeDeps =
3894+ Set. fromList [d | (_, _, es) <- perPkgDeps, d <- es]
38493895
38503896mapConfiguredPackage
38513897 :: (srcpkg -> srcpkg' )
0 commit comments