Skip to content

Commit b75671b

Browse files
authored
Merge pull request #9792 from haskell/mergify/bp/3.12/pr-9768
Make `check` recognise `main-is` in conditional branches (backport #9768)
2 parents 880831f + 698339c commit b75671b

File tree

14 files changed

+216
-12
lines changed

14 files changed

+216
-12
lines changed

Cabal-syntax/src/Distribution/Types/CondTree.hs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module Distribution.Types.CondTree
2121
, traverseCondBranchC
2222
, extractCondition
2323
, simplifyCondTree
24+
, simplifyCondBranch
2425
, ignoreConditions
2526
) where
2627

@@ -169,21 +170,28 @@ extractCondition p = go
169170
in
170171
((c `cAnd` ct) `cOr` (CNot c `cAnd` ce)) `cAnd` goList cs
171172

172-
-- | Flattens a CondTree using a partial flag assignment. When a condition
173+
-- | Flattens a CondTree using a partial flag assignment. When a condition
173174
-- cannot be evaluated, both branches are ignored.
174175
simplifyCondTree
175176
:: (Semigroup a, Semigroup d)
176177
=> (v -> Either v Bool)
177178
-> CondTree v d a
178179
-> (d, a)
179180
simplifyCondTree env (CondNode a d ifs) =
180-
foldl (<>) (d, a) $ mapMaybe simplifyIf ifs
181-
where
182-
simplifyIf (CondBranch cnd t me) =
183-
case simplifyCondition cnd env of
184-
(Lit True, _) -> Just $ simplifyCondTree env t
185-
(Lit False, _) -> fmap (simplifyCondTree env) me
186-
_ -> Nothing
181+
foldl (<>) (d, a) $ mapMaybe (simplifyCondBranch env) ifs
182+
183+
-- | Realizes a 'CondBranch' using partial flag assignment. When a condition
184+
-- cannot be evaluated, returns 'Nothing'.
185+
simplifyCondBranch
186+
:: (Semigroup a, Semigroup d)
187+
=> (v -> Either v Bool)
188+
-> CondBranch v d a
189+
-> Maybe (d, a)
190+
simplifyCondBranch env (CondBranch cnd t me) =
191+
case simplifyCondition cnd env of
192+
(Lit True, _) -> Just $ simplifyCondTree env t
193+
(Lit False, _) -> fmap (simplifyCondTree env) me
194+
_ -> Nothing
187195

188196
-- | Flatten a CondTree. This will resolve the CondTree by taking all
189197
-- possible paths into account. Note that since branches represent exclusive

Cabal/src/Distribution/PackageDescription/Check/Conditional.hs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,16 @@ updateTargetAnnotation t ta = ta{taTarget = taTarget ta <> t}
5858
-- doc for more info).
5959
annotateCondTree
6060
:: forall a
61-
. Monoid a
61+
. (Eq a, Monoid a)
6262
=> [PackageFlag] -- User flags.
6363
-> TargetAnnotation a
6464
-> CondTree ConfVar [Dependency] a
6565
-> CondTree ConfVar [Dependency] (TargetAnnotation a)
6666
annotateCondTree fs ta (CondNode a c bs) =
6767
let ta' = updateTargetAnnotation a ta
6868
bs' = map (annotateBranch ta') bs
69-
in CondNode ta' c bs'
69+
bs'' = crossAnnotateBranches defTrueFlags bs'
70+
in CondNode ta' c bs''
7071
where
7172
annotateBranch
7273
:: TargetAnnotation a
@@ -107,12 +108,55 @@ annotateCondTree fs ta (CondNode a c bs) =
107108
)
108109
fs
109110

111+
defTrueFlags :: [PackageFlag]
112+
defTrueFlags = filter flagDefault fs
113+
114+
-- Propagate contextual information in CondTree branches. This is
115+
-- needed as CondTree is a rosetree and not a binary tree.
116+
crossAnnotateBranches
117+
:: forall a
118+
. (Eq a, Monoid a)
119+
=> [PackageFlag] -- `default: true` flags.
120+
-> [CondBranch ConfVar [Dependency] (TargetAnnotation a)]
121+
-> [CondBranch ConfVar [Dependency] (TargetAnnotation a)]
122+
crossAnnotateBranches fs bs = map crossAnnBranch bs
123+
where
124+
crossAnnBranch
125+
:: CondBranch ConfVar [Dependency] (TargetAnnotation a)
126+
-> CondBranch ConfVar [Dependency] (TargetAnnotation a)
127+
crossAnnBranch wr =
128+
let
129+
rs = filter (/= wr) bs
130+
ts = mapMaybe realiseBranch rs
131+
in
132+
updateTargetAnnBranch (mconcat ts) wr
133+
134+
realiseBranch :: CondBranch ConfVar [Dependency] (TargetAnnotation a) -> Maybe a
135+
realiseBranch b =
136+
let
137+
-- We are only interested in True by default package flags.
138+
realiseBranchFunction :: ConfVar -> Either ConfVar Bool
139+
realiseBranchFunction (PackageFlag n) | elem n (map flagName fs) = Right True
140+
realiseBranchFunction _ = Right False
141+
ms = simplifyCondBranch realiseBranchFunction (fmap taTarget b)
142+
in
143+
fmap snd ms
144+
145+
updateTargetAnnBranch
146+
:: a
147+
-> CondBranch ConfVar [Dependency] (TargetAnnotation a)
148+
-> CondBranch ConfVar [Dependency] (TargetAnnotation a)
149+
updateTargetAnnBranch a (CondBranch k t mt) =
150+
let updateTargetAnnTree (CondNode ka c wbs) =
151+
(CondNode (updateTargetAnnotation a ka) c wbs)
152+
in CondBranch k (updateTargetAnnTree t) (updateTargetAnnTree <$> mt)
153+
110154
-- | A conditional target is a library, exe, benchmark etc., destructured
111155
-- in a CondTree. Traversing method: we render the branches, pass a
112156
-- relevant context, collect checks.
113157
checkCondTarget
114158
:: forall m a
115-
. (Monad m, Monoid a)
159+
. (Monad m, Eq a, Monoid a)
116160
=> [PackageFlag] -- User flags.
117161
-> (a -> CheckM m ()) -- Check function (a = target).
118162
-> (UnqualComponentName -> a -> a)
@@ -131,7 +175,7 @@ checkCondTarget fs cf nf (unqualName, ct) =
131175
:: CondTree ConfVar [Dependency] (TargetAnnotation a)
132176
-> CheckM m ()
133177
wTree (CondNode ta _ bs)
134-
-- There are no branches (and [] == True) *or* every branch
178+
-- There are no branches ([] == True) *or* every branch
135179
-- is “simple” (i.e. missing a 'condBranchIfFalse' part).
136180
-- This is convenient but not necessarily correct in all
137181
-- cases; a more precise way would be to check incompatibility
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# cabal check
2+
No errors or warnings could be found in the package.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Test.Cabal.Prelude
2+
3+
-- `main-is` in both branches is not missing (after).
4+
main = cabalTest $
5+
cabal "check" []
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cabal-version: 3.0
2+
name: pkg
3+
synopsis: synopsis
4+
description: description
5+
version: 0
6+
category: example
7+
maintainer: [email protected]
8+
license: GPL-3.0-or-later
9+
10+
flag my-flag
11+
description: Test for branches.
12+
default: False
13+
manual: True
14+
15+
executable exe
16+
if os(windows)
17+
ghc-options: -pgml misc/static-libstdc++
18+
19+
if flag(my-flag)
20+
main-is: Main.hs
21+
build-depends: async, unix
22+
c-sources: executable/link.c
23+
else
24+
main-is: ParallelMain.hs
25+
26+
default-language: Haskell2010
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# cabal check
2+
No errors or warnings could be found in the package.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Test.Cabal.Prelude
2+
3+
-- `main-is` in both branches is not missing.
4+
main = cabalTest $
5+
cabal "check" []
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cabal-version: 3.0
2+
name: pkg
3+
synopsis: synopsis
4+
description: description
5+
version: 0
6+
category: example
7+
maintainer: [email protected]
8+
license: GPL-3.0-or-later
9+
10+
flag my-flag
11+
description: Test for branches.
12+
default: False
13+
manual: True
14+
15+
executable exe
16+
if flag(my-flag)
17+
main-is: Main.hs
18+
build-depends: async, unix
19+
c-sources: executable/link.c
20+
else
21+
main-is: ParallelMain.hs
22+
23+
if os(windows)
24+
ghc-options: -pgml misc/static-libstdc++
25+
26+
default-language: Haskell2010
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# cabal check
2+
No errors or warnings could be found in the package.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Test.Cabal.Prelude
2+
3+
-- `main-is` in both branches is not missing (deep).
4+
main = cabalTest $
5+
cabal "check" []

0 commit comments

Comments
 (0)