Skip to content

Commit 2492721

Browse files
authored
Merge pull request #33 from well-typed/jdral/tweak-variable-context-helpers
Tweak variable context helpers
2 parents 98dd62e + ff353fe commit 2492721

File tree

7 files changed

+64
-34
lines changed

7 files changed

+64
-34
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
## ?.?.? -- ????-??-??
44

5+
* BREAKING: Rename `lookupGVar` to `realLookupVar`, and add a `RealLookup`
6+
convenience alias that is used in the type of `RealLookupVar`. The type of
7+
`realLookupVar` is slightly different than the type of `lookupGVar`, but only
8+
in the positions of universal quantification over types.
9+
* NON-BREAKING: improved error messages for `realLookupVar` and `lookupVar`,
10+
which might throw an error when variables are ill-defined or unevaluable.
11+
* PATCH: some documentation is moved from convenience aliases like
12+
`ModelFindVariables` to the functions have these aliases in their type, like
13+
`findVars`.
514
* BREAKING: Enable verbose counterexamples by default in the 'postcondition'
615
function using 'postconditionWith'.
716
* NON-BREAKING: Add a new 'postconditionWith' function that can be configured to

src/Test/QuickCheck/StateModel/Lockstep.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@ module Test.QuickCheck.StateModel.Lockstep (
2222
, ModelLookUp
2323
, ModelShrinkVar
2424
, ModelVar
25+
, RealLookUp
2526
-- * Variable context
2627
, ModelVarContext
2728
, lookupVar
2829
, findVars
2930
, shrinkVar
31+
, realLookupVar
3032
-- * Variables
3133
, GVar -- opaque
3234
, AnyGVar(..)
3335
, unsafeMkGVar
34-
, lookUpGVar
3536
, mapGVar
3637
-- ** Operations
3738
, Operation(..)

src/Test/QuickCheck/StateModel/Lockstep/API.hs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,21 @@ module Test.QuickCheck.StateModel.Lockstep.API (
1616
, ModelLookUp
1717
, ModelVar
1818
, ModelShrinkVar
19+
, RealLookUp
1920
-- * Variable context
2021
, ModelVarContext
2122
, findVars
2223
, lookupVar
2324
, shrinkVar
25+
, realLookupVar
2426
) where
2527

2628
import Data.Constraint (Dict(..))
2729
import Data.Kind
2830
import Data.Typeable
2931

3032
import Test.QuickCheck (Gen)
31-
import Test.QuickCheck.StateModel (StateModel, Any, RunModel, Realized, Action)
33+
import Test.QuickCheck.StateModel (StateModel, Any, RunModel, Realized, Action, LookUp)
3234

3335
import Test.QuickCheck.StateModel.Lockstep.EnvF (EnvF)
3436
import Test.QuickCheck.StateModel.Lockstep.GVar (GVar, AnyGVar(..), fromVar)
@@ -181,21 +183,19 @@ class ( InLockstep state
181183
-- | An action in the lock-step model
182184
type LockstepAction state = Action (Lockstep state)
183185

184-
-- | Look up a variable for model execution
185-
--
186-
-- The type of the variable is the type in the /real/ system.
186+
-- | See 'lookupVar'.
187187
type ModelLookUp state = forall a. ModelVar state a -> ModelValue state a
188188

189-
-- | Find variables of the appropriate type
190-
--
191-
-- The type you pass must be the result type of (previously executed) actions.
192-
-- If you want to change the type of the variable, see 'EnvF.mapGVar'.
189+
-- | See 'findVars'.
193190
type ModelFindVariables state = forall a.
194191
Typeable a
195192
=> Proxy a -> [GVar (ModelOp state) a]
196193

197-
-- | Shrink variables to /earlier/ variables of the same type.
198-
type ModelShrinkVar state a = ModelVar state a -> [ModelVar state a]
194+
-- | See 'shrinkVar'.
195+
type ModelShrinkVar state = forall a. ModelVar state a -> [ModelVar state a]
196+
197+
-- | See 'realLookupVar'.
198+
type RealLookUp m op = forall a. Proxy m -> LookUp m -> GVar op a -> Realized m a
199199

200200
-- | Variables with a "functor-esque" instance
201201
type ModelVar state = GVar (ModelOp state)
@@ -207,24 +207,45 @@ type ModelVar state = GVar (ModelOp state)
207207
-- | The environment of known variables and their (model) values.
208208
--
209209
-- This environment can be queried for information about known variables through
210-
-- 'findVars' and 'lookupVar'. This environment is updated automically by the
211-
-- lockstep framework.
210+
-- 'findVars', 'lookupVar', and 'shrinkVar'. This environment is updated
211+
-- automically by the lockstep framework.
212212
type ModelVarContext state = EnvF (ModelValue state)
213213

214-
-- | See 'ModelFindVariables'.
214+
-- | Find variables of the appropriate type
215+
--
216+
-- The type you pass must be the result type of (previously executed) actions.
217+
-- If you want to change the type of the variable, see 'EnvF.mapGVar'.
215218
findVars ::
216219
InLockstep state
217220
=> ModelVarContext state -> ModelFindVariables state
218221
findVars env _ = map fromVar $ EnvF.keysOfType env
219222

220-
-- | See 'ModelLookUp'.
223+
-- | Look up a variable for execution of the model.
224+
--
225+
-- The type of the variable is the type in the /real/ system.
221226
lookupVar ::
222227
InLockstep state
223228
=> ModelVarContext state -> ModelLookUp state
224-
lookupVar env = EnvF.lookUpEnvF env
229+
lookupVar env gvar = case EnvF.lookUpEnvF env gvar of
230+
Just x -> x
231+
Nothing -> error
232+
"lookupVar: the variable (ModelVar) must be well-defined and evaluable, \
233+
\but this requirement was violated. Normally, this is guaranteed by the \
234+
\default test 'precondition'."
225235

226-
-- | See 'ModelShrinkVar'.
236+
-- | Shrink variables to /earlier/ variables of the same type.
227237
shrinkVar ::
228238
(Typeable state, InterpretOp (ModelOp state) (ModelValue state))
229-
=> ModelVarContext state -> ModelShrinkVar state a
230-
shrinkVar env var = EnvF.shrinkGVar env var
239+
=> ModelVarContext state -> ModelShrinkVar state
240+
shrinkVar env var = EnvF.shrinkGVar env var
241+
242+
-- | Look up a variable for execution of the real system.
243+
--
244+
-- The type of the variable is the type in the /real/ system.
245+
realLookupVar :: InterpretOp op (WrapRealized m) => RealLookUp m op
246+
realLookupVar p lookUp gvar = case EnvF.lookUpGVar p lookUp gvar of
247+
Just x -> x
248+
Nothing -> error
249+
"realLookupVar: the variable (GVar) must be well-defined and evaluable, \
250+
\but this requirement was violated. Normally, this is guaranteed by the \
251+
\default test 'precondition'."

src/Test/QuickCheck/StateModel/Lockstep/GVar.hs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module Test.QuickCheck.StateModel.Lockstep.GVar (
2323

2424
import Prelude hiding (map)
2525

26-
import Data.Maybe (isJust, fromJust)
26+
import Data.Maybe (isJust)
2727
import Data.Typeable
2828

2929
import GHC.Show
@@ -96,30 +96,29 @@ lookUpWrapped _ m v = WrapRealized (m v)
9696

9797
-- | Lookup 'GVar' given a lookup function for 'Var'
9898
--
99-
-- The variable must be in the environment and evaluation must succeed.
100-
-- This is normally guaranteed by the default test 'precondition'.
99+
-- The result is 'Just' if the variable is in the environment and evaluation
100+
-- succeeds. This is normally guaranteed by the default test 'precondition'.
101101
lookUpGVar ::
102102
InterpretOp op (WrapRealized m)
103-
=> Proxy m -> LookUp m -> GVar op a -> Realized m a
103+
=> Proxy m -> LookUp m -> GVar op a -> Maybe (Realized m a)
104104
lookUpGVar p lookUp (GVar var op) =
105-
unwrapRealized $ fromJust $ intOp op (lookUpWrapped p lookUp var)
105+
unwrapRealized <$> intOp op (lookUpWrapped p lookUp var)
106106

107107
{-------------------------------------------------------------------------------
108108
Interop with EnvF
109109
-------------------------------------------------------------------------------}
110110

111111
-- | Lookup 'GVar'
112112
--
113-
-- The variable must be in the environment and evaluation must succeed.
114-
-- This is normally guaranteed by the default test 'precondition'.
115-
lookUpEnvF :: (Typeable f, InterpretOp op f) => EnvF f -> GVar op a -> f a
116-
lookUpEnvF env (GVar var op) = fromJust $
113+
-- The result is 'Just' if the variable is in the environment and evaluation
114+
-- succeeds. This is normally guaranteed by the default test 'precondition'.
115+
lookUpEnvF :: (Typeable f, InterpretOp op f) => EnvF f -> GVar op a -> Maybe (f a)
116+
lookUpEnvF env (GVar var op) =
117117
EnvF.lookup var env >>= intOp op
118118

119119
-- | Check if the variable is well-defined and evaluation will succeed.
120120
definedInEnvF :: (Typeable f, InterpretOp op f) => EnvF f -> GVar op a -> Bool
121-
definedInEnvF env (GVar var op) = isJust $
122-
EnvF.lookup var env >>= intOp op
121+
definedInEnvF env gvar = isJust (lookUpEnvF env gvar)
123122

124123
-- | Shrink a 'GVar' to earlier 'GVar's of the same type. It is guaranteed that
125124
-- the shrunk variables are in the environment and that evaluation will succeed.

test/Test/IORef/Full.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,11 @@ runIO action lookUp = ReaderT $ \(buggy, brokenRef) ->
208208
Read v -> readIORef (lookUpRef v)
209209
where
210210
lookUpRef :: ModelVar M (IORef Int) -> IORef Int
211-
lookUpRef = lookUpGVar (Proxy @RealMonad) lookUp
211+
lookUpRef = realLookupVar (Proxy @RealMonad) lookUp
212212

213213
lookUpInt :: Either Int (ModelVar M Int) -> Int
214214
lookUpInt (Left x) = x
215-
lookUpInt (Right v) = lookUpGVar (Proxy @RealMonad) lookUp v
215+
lookUpInt (Right v) = realLookupVar (Proxy @RealMonad) lookUp v
216216

217217
-- | The second write to the same variable will be broken
218218
brokenWrite :: Buggy -> IORef BrokenRef -> IORef Int -> Int -> IO Int

test/Test/IORef/Simple.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ runIO action lookUp =
155155
Read v -> readIORef (lookUpRef v)
156156
where
157157
lookUpRef :: ModelVar M (IORef Int) -> IORef Int
158-
lookUpRef = lookUpGVar (Proxy @RealMonad) lookUp
158+
lookUpRef = realLookupVar (Proxy @RealMonad) lookUp
159159

160160
runModel ::
161161
Action (Lockstep M) a

test/Test/MockFS.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ runIO action lookUp = ReaderT $ \root -> aux root action
351351
_ -> pure s
352352
where
353353
lookUp' :: FsVar x -> x
354-
lookUp' = lookUpGVar (Proxy @RealMonad) lookUp
354+
lookUp' = realLookupVar (Proxy @RealMonad) lookUp
355355

356356
catchErr :: forall a. IO a -> IO (Either Err a)
357357
catchErr act = catch (Right <$> act) handler

0 commit comments

Comments
 (0)