Skip to content

Commit 9d65b0d

Browse files
authored
Change the structure of the GenT monad, to better track explanations. (#4838)
* Added Constrained.SumList.hs to repo Defined pickAll the basis of sums with fixed length. Added getSizedList as a method of the Foldy class getSizeList cost is metered at 1000 calls. Typical calls are less than 10. Gave HasSpec (optional) method 'typeSpecHasError' a better default value * Changed the monad in Constrained.GenT to use reader instead of state.
1 parent a45b1b3 commit 9d65b0d

File tree

6 files changed

+261
-196
lines changed

6 files changed

+261
-196
lines changed

libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance/ExecSpecRule/Core.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,13 +428,13 @@ conformsToImpl = property @(ImpTestM era Property) . (`runContT` pure) $ do
428428
forAllSpec spec = do
429429
let
430430
simplifiedSpec = simplifySpec spec
431-
generator = CV2.runGenT (CV2.genFromSpecT simplifiedSpec) Loose
432-
shrinker (Result _ x) = pure <$> shrinkWithSpec simplifiedSpec x
431+
generator = CV2.runGenT (CV2.genFromSpecT simplifiedSpec) Loose []
432+
shrinker (Result x) = pure <$> shrinkWithSpec simplifiedSpec x
433433
shrinker _ = []
434434
res :: GE a <- ContT $ \c ->
435435
pure $ forAllShrinkBlind generator shrinker c
436436
case res of
437-
Result _ x -> pure x
437+
Result x -> pure x
438438
_ -> ContT . const . pure $ property Discard
439439
env <- forAllSpec $ environmentSpec @fn @rule @era ctx
440440
deepEval env "environment"

libs/constrained-generators/src/Constrained/Base.hs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ import GHC.Natural
7474
import GHC.Real
7575
import GHC.Stack
7676
import GHC.TypeLits
77-
import Prettyprinter
77+
import Prettyprinter hiding (cat)
7878
import System.Random
7979
import System.Random.Stateful
8080
import Test.QuickCheck hiding (Args, Fun, forAll)
@@ -532,7 +532,7 @@ monitorPred env = \case
532532
monitorPred (extendEnv x val env) p
533533
Exists k (x :-> p) -> do
534534
case k (errorGE . explain1 "monitorPred: Exists" . runTerm env) of
535-
Result _ a -> monitorPred (extendEnv x a env) p
535+
Result a -> monitorPred (extendEnv x a env) p
536536
_ -> pure id
537537
Explain es p -> explain es $ monitorPred env p
538538

@@ -787,7 +787,7 @@ instance (HasSpec fn a, Arbitrary (TypeSpec fn a)) => Arbitrary (Specification f
787787
shrink (SuspendedSpec x p) =
788788
[TrueSpec, ErrorSpec (pure "From shrinking SuspendedSpec")]
789789
++ [ s
790-
| Result _ s <- [computeSpec x p]
790+
| Result s <- [computeSpec x p]
791791
, not $ isSuspendedSpec s
792792
]
793793
++ [SuspendedSpec x p' | p' <- shrinkPred p]
@@ -1167,8 +1167,7 @@ genFromSpecT (simplifySpec -> spec) = case spec of
11671167
[ "genFromSpecT on (TypeSpec tspec cant) at type " ++ showType @a
11681168
, "tspec = "
11691169
, show s
1170-
, "cant = "
1171-
, unlines (map (\x -> " " ++ show x) cant)
1170+
, "cant = " ++ show (short cant)
11721171
, "with mode " ++ show mode
11731172
]
11741173
)
@@ -1196,7 +1195,7 @@ shrinkWithSpec (simplifySpec -> spec) a = filter (`conformsToSpec` spec) $ case
11961195

11971196
shrinkFromPreds :: HasSpec fn a => Pred fn -> Var a -> a -> [a]
11981197
shrinkFromPreds p
1199-
| Result _ plan <- prepareLinearization p = \x a -> listFromGE $ do
1198+
| Result plan <- prepareLinearization p = \x a -> listFromGE $ do
12001199
-- NOTE: we do this to e.g. guard against bad construction functions in Exists
12011200
xaGood <- checkPred (singletonEnv x a) p
12021201
unless xaGood $
@@ -1292,7 +1291,7 @@ envFromPred env p = case p of
12921291
genFromSpec :: forall fn a. (HasCallStack, HasSpec fn a) => Specification fn a -> Gen a
12931292
genFromSpec spec = do
12941293
res <- catchGen $ genFromSpecT @fn @a @GE spec
1295-
either (error . show . NE.toList) pure res
1294+
either (error . show . catMessages) pure res
12961295

12971296
-- | A version of `genFromSpecT` that takes a seed and a size and gives you a result
12981297
genFromSpecWithSeed ::
@@ -1309,9 +1308,9 @@ debugSpec spec = do
13091308
then putStrLn "True"
13101309
else putStrLn "False, perhaps there is an unsafeExists in the spec?"
13111310
case ans of
1312-
FatalError xs x -> mapM f xs >> f x
1313-
GenError xs x -> mapM f xs >> f x
1314-
Result _ x -> print spec >> print x >> ok x
1311+
FatalError xs -> mapM_ f xs
1312+
GenError xs -> mapM_ f xs
1313+
Result x -> print spec >> print x >> ok x
13151314

13161315
genInverse ::
13171316
( MonadGenError m
@@ -1519,7 +1518,7 @@ backPropagation (SolverPlan plan graph) = SolverPlan (go [] (reverse plan)) grap
15191518
termVarEqCases spec x' t
15201519
| Just Refl <- eqVar x x'
15211520
, [Name y] <- Set.toList $ freeVarSet t
1522-
, Result _ ctx <- toCtx y t =
1521+
, Result ctx <- toCtx y t =
15231522
[SolverStage y [] (propagateSpec spec ctx)]
15241523
termVarEqCases _ _ _ = []
15251524

@@ -1608,7 +1607,7 @@ short xs = "([" <+> viaShow (length xs) <+> "elements ...] @" <> prettyType @a <
16081607
prettyPlan :: HasSpec fn a => Specification fn a -> Doc ann
16091608
prettyPlan (simplifySpec -> spec)
16101609
| SuspendedSpec _ p <- spec
1611-
, Result _ plan <- prepareLinearization p =
1610+
, Result plan <- prepareLinearization p =
16121611
vsep'
16131612
[ "Simplified spec:" /> pretty spec
16141613
, pretty plan
@@ -1761,9 +1760,9 @@ normalizeSolverStage (SolverStage x ps spec) = SolverStage x ps'' (spec <> spec'
17611760

17621761
fromGESpec :: HasCallStack => GE (Specification fn a) -> Specification fn a
17631762
fromGESpec ge = case ge of
1764-
Result [] s -> s
1765-
Result es s -> addToErrorSpec (foldr1 (<>) es) s
1766-
_ -> fromGE ErrorSpec ge
1763+
Result s -> s
1764+
GenError xs -> ErrorSpec (catMessageList xs)
1765+
FatalError es -> error $ catMessages es
17671766

17681767
-- | Add the explanations, if it's an ErrorSpec, else drop them
17691768
addToErrorSpec :: NE.NonEmpty String -> Specification fn a -> Specification fn a
@@ -1886,8 +1885,10 @@ computeSpecSimplified x p = localGESpec $ case p of
18861885
["The impossible happened in computeSpec: Reifies", " " ++ show x, show $ indent 2 (pretty p)]
18871886
where
18881887
-- We want `genError` to turn into `ErrorSpec` and we want `FatalError` to turn into `FatalError`
1889-
localGESpec ge@FatalError {} = ge
1890-
localGESpec ge = pure $ fromGESpec ge
1888+
localGESpec ge = case ge of
1889+
(GenError xs) -> Result $ ErrorSpec (catMessageList xs)
1890+
(FatalError es) -> FatalError es
1891+
(Result x) -> Result x
18911892

18921893
-- | Precondition: the `Pred fn` defines the `Var a`.
18931894
--
@@ -5636,7 +5637,7 @@ showType :: forall t. Typeable t => String
56365637
showType = show (typeRep (Proxy @t))
56375638

56385639
prettyType :: forall t x. Typeable t => Doc x
5639-
prettyType = fromString $ showType @t
5640+
prettyType = fromString $ show (typeRep (Proxy @t))
56405641

56415642
instance HasSpec fn a => Pretty (Term fn a) where
56425643
pretty = prettyPrec 0
@@ -6236,11 +6237,13 @@ checkPredE env msgs = \case
62366237
Right v -> v
62376238
Left es -> error $ unlines $ NE.toList (msgs <> es)
62386239
in case k eval of
6239-
Result _ a -> checkPredE (extendEnv x a env) msgs p
6240-
FatalError ess es -> Just (msgs <> foldr1 (<>) ess <> es)
6241-
GenError ess es -> Just (msgs <> foldr1 (<>) ess <> es)
6240+
Result a -> checkPredE (extendEnv x a env) msgs p
6241+
FatalError es -> Just (msgs <> catMessageList es)
6242+
GenError es -> Just (msgs <> catMessageList es)
62426243
Explain es p -> checkPredE env (msgs <> es) p
62436244

6245+
-- | conformsToSpec with explanation. Nothing if (conformsToSpec a spec),
6246+
-- but (Just explanations) if not(conformsToSpec a spec).
62446247
conformsToSpecE ::
62456248
forall fn a.
62466249
HasSpec fn a =>
@@ -6249,7 +6252,7 @@ conformsToSpecE ::
62496252
NE.NonEmpty String ->
62506253
Maybe (NE.NonEmpty String)
62516254
conformsToSpecE a (ExplainSpec [] s) msgs = conformsToSpecE a s msgs
6252-
conformsToSpecE a (ExplainSpec (x : xs) s) msgs = conformsToSpecE a s (msgs <> (x NE.:| xs))
6255+
conformsToSpecE a (ExplainSpec (x : xs) s) msgs = conformsToSpecE a s ((x :| xs) <> msgs)
62536256
conformsToSpecE _ TrueSpec _ = Nothing
62546257
conformsToSpecE a (MemberSpec as) msgs =
62556258
if elem a as

libs/constrained-generators/src/Constrained/Examples/Fold.hs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import Constrained.Base (Pred (..), genListWithSize, predSpecPair)
1414
import Constrained.Examples.List (Numbery)
1515
import Constrained.SumList
1616
import Data.List.NonEmpty (NonEmpty ((:|)))
17-
import qualified Data.List.NonEmpty as NE
1817
import Data.String (fromString)
1918
import Prettyprinter (fillSep, punctuate, space)
2019
import System.Random (Random)
@@ -141,14 +140,15 @@ testFoldSpec size elemSpec total outcome = do
141140
ans <- genFromGenT $ inspect $ genListWithSize size elemSpec total
142141
let callString = parensList ["GenListWithSize", show size, fst (predSpecPair elemSpec), show total]
143142
fails xs = unlines [callString, "Should fail, but it succeeds with", show xs]
144-
succeeds xs = unlines (callString : "Should succeed, but it fails with" : NE.toList xs)
143+
succeeds xs =
144+
unlines [callString, "Should succeed, but it fails with", catMessages xs]
145145
case (ans, outcome) of
146-
(Result _ _, Succeed) -> pure $ property True
147-
(Result _ xs, Fail) -> pure $ counterexample (fails xs) False
148-
(FatalError _ _, Fail) -> pure $ property True
149-
(FatalError _ xs, Succeed) -> pure $ counterexample (succeeds xs) False
150-
(GenError _ _, Fail) -> pure $ property True
151-
(GenError _ xs, Succeed) -> pure $ counterexample (succeeds xs) False
146+
(Result _, Succeed) -> pure $ property True
147+
(Result xs, Fail) -> pure $ counterexample (fails xs) False
148+
(FatalError _, Fail) -> pure $ property True
149+
(FatalError xs, Succeed) -> pure $ counterexample (succeeds xs) False
150+
(GenError _, Fail) -> pure $ property True
151+
(GenError xs, Succeed) -> pure $ counterexample (succeeds xs) False
152152

153153
-- | Generate a property from a call to 'pickAll'. We can test for success or failure using 'outcome'
154154
sumProp ::

0 commit comments

Comments
 (0)