44module Act.Bounds (addBounds ) where
55
66import Data.Maybe
7- import Data.List (nub )
7+ import Data.List (nub , partition )
8+ import Data.Type.Equality
89
910import Act.Syntax
1011import Act.Syntax.TypedExplicit
@@ -37,10 +38,18 @@ addBoundsConstructor ctor@(Constructor _ (Interface _ decls) _ pre post invs sta
3738 pre' = pre
3839 <> mkCallDataBounds decls
3940 <> mkEthEnvBounds (ethEnvFromConstructor ctor)
40- <> mkStorageBoundsLoc (nub $ concatMap locsFromExp pre <> concatMap locsFromUpdateRHS stateUpdates)
41+ -- The following is sound as values of locations outside local storage
42+ -- already exist as the constructor starts executing,
43+ -- and the constructor cannot modify non-local locations.
44+ <> mkLocationBounds nonlocalLocs
4145 invs' = addBoundsInvariant ctor <$> invs
4246 post' = post <> mkStorageBounds stateUpdates Post
4347
48+ locs = concatMap locsFromExp (pre <> post)
49+ <> concatMap locsFromInvariant invs
50+ <> concatMap locsFromUpdate stateUpdates
51+ nonlocalLocs = filter (not . isLocalLoc) locs
52+
4453-- | Adds type bounds for calldata, environment vars, and storage vars as preconditions
4554addBoundsBehaviour :: Behaviour -> Behaviour
4655addBoundsBehaviour behv@ (Behaviour _ _ (Interface _ decls) _ pre cases post stateUpdates _) =
@@ -49,11 +58,14 @@ addBoundsBehaviour behv@(Behaviour _ _ (Interface _ decls) _ pre cases post stat
4958 pre' = pre
5059 <> mkCallDataBounds decls
5160 <> mkStorageBounds stateUpdates Pre
52- <> mkStorageBoundsLoc (nub $ concatMap locsFromExp (pre <> cases) <> concatMap locsFromUpdateRHS stateUpdates)
61+ <> mkLocationBounds locs
5362 <> mkEthEnvBounds (ethEnvFromBehaviour behv)
5463 post' = post
5564 <> mkStorageBounds stateUpdates Post
5665
66+ locs = concatMap locsFromExp (pre <> post <> cases)
67+ <> concatMap locsFromUpdate stateUpdates
68+
5769-- | Adds type bounds for calldata, environment vars, and storage vars
5870addBoundsInvariant :: Constructor -> Invariant -> Invariant
5971addBoundsInvariant (Constructor _ (Interface _ decls) _ _ _ _ _) inv@ (Invariant _ preconds storagebounds (PredTimed predicate _)) =
@@ -62,8 +74,13 @@ addBoundsInvariant (Constructor _ (Interface _ decls) _ _ _ _ _) inv@(Invariant
6274 preconds' = preconds
6375 <> mkCallDataBounds decls
6476 <> mkEthEnvBounds (ethEnvFromExp predicate)
77+ <> mkLocationBounds nonlocalLocs
6578 storagebounds' = storagebounds
66- <> mkStorageBoundsLoc (locsFromExp predicate)
79+ <> mkLocationBounds localLocs
80+
81+ locs = concatMap locsFromExp (preconds <> storagebounds)
82+ <> locsFromExp predicate
83+ (nonlocalLocs, localLocs) = partition (not . isLocalLoc) locs
6784
6885mkEthEnvBounds :: [EthEnv ] -> [Exp ABoolean ]
6986mkEthEnvBounds vars = catMaybes $ mkBound <$> nub vars
@@ -94,21 +111,36 @@ mkStorageBounds :: [StorageUpdate] -> When -> [Exp ABoolean]
94111mkStorageBounds refs t = concatMap mkBound refs
95112 where
96113 mkBound :: StorageUpdate -> [Exp ABoolean ]
97- mkBound (Update SInteger item _) = [mkItemBounds t item]
114+ mkBound (Update SInteger item _) = [mkSItemBounds t item]
115+ mkBound (Update typ item@ (Item _ (PrimitiveType at) _) _) | isNothing $ flattenArrayAbiType at =
116+ maybe [] (\ Refl -> mkSItemBounds t <$> expandItem item) $ testEquality (flattenSType typ) SInteger
98117 mkBound _ = []
99118
100- mkItemBounds :: When -> TItem AInteger Storage -> Exp ABoolean
101- mkItemBounds whn item@ (Item _ (PrimitiveType vt) _) = bound vt (VarRef nowhere whn SStorage item)
102- mkItemBounds _ (Item _ (ContractType _) _) = LitBool nowhere True
119+ mkSItemBounds :: When -> TItem AInteger Storage -> Exp ABoolean
120+ mkSItemBounds whn item@ (Item _ (PrimitiveType vt) _) = bound vt (VarRef nowhere whn SStorage item)
121+ mkSItemBounds _ (Item _ (ContractType _) _) = LitBool nowhere True
103122
104- mkStorageBoundsLoc :: [StorageLocation ] -> [Exp ABoolean ]
105- mkStorageBoundsLoc refs = concatMap mkBound refs
123+ mkCItemBounds :: TItem AInteger Calldata -> Exp ABoolean
124+ mkCItemBounds item@ (Item _ (PrimitiveType vt) _) = bound vt (VarRef nowhere Pre SCalldata item)
125+ mkCItemBounds (Item _ (ContractType _) _) = LitBool nowhere True
126+
127+ mkLocationBounds :: [Location ] -> [Exp ABoolean ]
128+ mkLocationBounds refs = concatMap mkBound refs
106129 where
107- mkBound :: StorageLocation -> [Exp ABoolean ]
108- mkBound (Loc SInteger item) = [mkItemBounds Pre item]
130+ mkBound :: Location -> [Exp ABoolean ]
131+ mkBound (Loc SInteger rk item) = [mkItemBounds rk item]
132+ mkBound (Loc typ rk item@ (Item _ (PrimitiveType at) _)) | isNothing $ flattenArrayAbiType at =
133+ maybe [] (\ Refl -> mkItemBounds rk <$> expandItem item) $ testEquality (flattenSType typ) SInteger
109134 mkBound _ = []
110135
136+ mkItemBounds :: SRefKind k -> TItem AInteger k -> Exp ABoolean
137+ mkItemBounds SStorage = mkSItemBounds Pre
138+ mkItemBounds SCalldata = mkCItemBounds
139+
111140mkCallDataBounds :: [Decl ] -> [Exp ABoolean ]
112- mkCallDataBounds = concatMap $ \ (Decl typ name) -> case fromAbiType typ of
113- AInteger -> [bound typ (_Var typ name)]
114- _ -> []
141+ mkCallDataBounds = concatMap $ \ (Decl typ name) -> case typ of
142+ -- Array element bounds are applied lazily when needed in mkCalldataLocationBounds
143+ (AbiArrayType _ _) -> []
144+ _ -> case fromAbiType typ of
145+ AInteger -> [bound typ (_Var typ name)]
146+ _ -> []
0 commit comments