Skip to content

Commit 0669e9d

Browse files
Improve shrinking performance
1 parent d20193c commit 0669e9d

File tree

2 files changed

+26
-22
lines changed

2 files changed

+26
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ cabal.project.local~
2222
.HTF/
2323
.ghc.environment.*
2424
*.*.sw*
25+
*.eventlog.json

src/Constrained/Generation.hs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -152,38 +152,41 @@ genFromSpecWithSeed seed size spec = unGen (genFromSpec spec) (mkQCGen seed) siz
152152
shrinkWithSpec :: forall a. HasSpec a => Specification a -> a -> [a]
153153
-- TODO: possibly allow for ignoring the `conformsToSpec` check in the `TypeSpec`
154154
-- case when you know what you're doing
155-
shrinkWithSpec (simplifySpec -> spec) a = filter (`conformsToSpec` spec) $ case spec of
155+
shrinkWithSpec (simplifySpec -> spec) a = case spec of
156156
ExplainSpec _ s -> shrinkWithSpec s a
157157
-- TODO: filter on can't if we have a known to be sound shrinker
158-
TypeSpec s _ -> shrinkWithTypeSpec s a
159-
SuspendedSpec x p -> shrinkFromPreds p x a ++ shr a
160-
MemberSpec {} -> shr a
161-
TrueSpec -> shr a
158+
TypeSpec s _ -> soundify $ shrinkWithTypeSpec s a
159+
SuspendedSpec x p -> shrinkFromPreds p x a
160+
-- TODO: it would be nice if there was some better way of doing this
161+
MemberSpec {} -> soundify $ shrinkWithTypeSpec (emptySpec @a) a
162+
TrueSpec -> shrinkWithTypeSpec (emptySpec @a) a
162163
ErrorSpec {} -> []
163-
where
164-
shr = shrinkWithTypeSpec (emptySpec @a)
164+
where soundify = filter (`conformsToSpec` spec)
165165

166-
shrinkFromPreds :: HasSpec a => Pred -> Var a -> a -> [a]
166+
shrinkFromPreds :: forall a. HasSpec a => Pred -> Var a -> a -> [a]
167167
shrinkFromPreds p
168168
| Result plan <- prepareLinearization p = \x a -> listFromGE $ do
169169
-- NOTE: we do this to e.g. guard against bad construction functions in Exists
170170
case checkPredE (Env.singleton x a) (NE.fromList []) p of
171171
Nothing -> pure ()
172172
Just err -> explainNE err $ fatalError "Trying to shrink a bad value, don't do that!"
173-
-- Get an `env` for the original value
174-
initialEnv <- envFromPred (Env.singleton x a) p
175-
return
176-
[ a'
177-
| -- Shrink the initialEnv
178-
env' <- shrinkEnvFromPlan initialEnv plan
179-
, -- Get the value of the constrained variable `x` in the shrunk env
180-
Just a' <- [Env.lookup env' x]
181-
, -- NOTE: this is necessary because it's possible that changing
182-
-- a particular value in the env during shrinking might not result
183-
-- in the value of `x` changing and there is no better way to know than
184-
-- to do this.
185-
a' /= a
186-
]
173+
if not $ Name x `appearsIn` p -- NOTE: this is safe because we just checked that p is SAT above
174+
then return $ shrinkWithTypeSpec (emptySpec @a) a
175+
else do
176+
-- Get an `env` for the original value
177+
initialEnv <- envFromPred (Env.singleton x a) p
178+
return
179+
[ a'
180+
| -- Shrink the initialEnv
181+
env' <- shrinkEnvFromPlan initialEnv plan
182+
, -- Get the value of the constrained variable `x` in the shrunk env
183+
Just a' <- [Env.lookup env' x]
184+
, -- NOTE: this is necessary because it's possible that changing
185+
-- a particular value in the env during shrinking might not result
186+
-- in the value of `x` changing and there is no better way to know than
187+
-- to do this.
188+
a' /= a
189+
]
187190
| otherwise = error "Bad pred"
188191

189192
-- Start with a valid Env for the plan and try to shrink it

0 commit comments

Comments
 (0)