@@ -148,42 +148,48 @@ genFromSpecWithSeed seed size spec = unGen (genFromSpec spec) (mkQCGen seed) siz
148148
149149-- ----------------------- Shrinking -------------------------------
150150
151+ naiveShrink :: forall a . HasSpec a => a -> [a ]
152+ naiveShrink = shrinkWithTypeSpec (emptySpec @ a )
153+
151154-- | Shrink a value while preserving adherence to a `Specification`
152155shrinkWithSpec :: forall a . HasSpec a => Specification a -> a -> [a ]
153- -- TODO: possibly allow for ignoring the `conformsToSpec` check in the `TypeSpec`
154- -- case when you know what you're doing
155- shrinkWithSpec (simplifySpec -> spec) a = filter ( `conformsToSpec` spec) $ case spec of
156- ExplainSpec _ s -> shrinkWithSpec s a
157- -- 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
156+ shrinkWithSpec ( ExplainSpec _ s) a = shrinkWithSpec s a
157+ shrinkWithSpec (simplifySpec -> spec) a = case spec of
158+ -- TODO: It would be nice to avoid the extra `conformsToSpec` check here and only look
159+ -- at the cant set instead
160+ TypeSpec s _ -> [ a' | a' <- shrinkWithTypeSpec s a, a' `conformsToSpec` spec ]
161+ SuspendedSpec x p -> shrinkFromPreds p x a
162+ -- TODO: it would be nice if there was some better way of doing this
163+ MemberSpec as -> [ a' | a' <- naiveShrink a, a' `elem` as ]
164+ TrueSpec -> naiveShrink a
162165 ErrorSpec {} -> []
163- where
164- shr = shrinkWithTypeSpec (emptySpec @ a )
166+ -- Should be impossible?
167+ ExplainSpec _ s -> shrinkWithSpec s a
165168
166- shrinkFromPreds :: HasSpec a => Pred -> Var a -> a -> [a ]
169+ shrinkFromPreds :: forall a . HasSpec a => Pred -> Var a -> a -> [a ]
167170shrinkFromPreds p
168171 | Result plan <- prepareLinearization p = \ x a -> listFromGE $ do
169172 -- NOTE: we do this to e.g. guard against bad construction functions in Exists
170173 case checkPredE (Env. singleton x a) (NE. fromList [] ) p of
171174 Nothing -> pure ()
172175 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- ]
176+ if not $ Name x `appearsIn` p -- NOTE: this is safe because we just checked that p is SAT above
177+ then return $ naiveShrink a
178+ else do
179+ -- Get an `env` for the original value
180+ initialEnv <- envFromPred (Env. singleton x a) p
181+ return
182+ [ a'
183+ | -- Shrink the initialEnv
184+ env' <- shrinkEnvFromPlan initialEnv plan
185+ , -- Get the value of the constrained variable `x` in the shrunk env
186+ Just a' <- [Env. lookup env' x]
187+ , -- NOTE: this is necessary because it's possible that changing
188+ -- a particular value in the env during shrinking might not result
189+ -- in the value of `x` changing and there is no better way to know than
190+ -- to do this.
191+ a' /= a
192+ ]
187193 | otherwise = error " Bad pred"
188194
189195-- Start with a valid Env for the plan and try to shrink it
0 commit comments