Skip to content

Commit

Permalink
Nits in the typechecker and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zoep committed Oct 27, 2024
1 parent 7fc2910 commit 942f4f4
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 40 deletions.
42 changes: 42 additions & 0 deletions src/Act/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,48 @@ itemType (Item t _ _) = actType t
isMapping :: StorageLocation t -> Bool
isMapping = not . null . ixsFromLocation

posnFromExp :: Exp a t -> Pn
posnFromExp e = case e of
And p _ _ -> p
Or p _ _ -> p
Impl p _ _ -> p
Neg p _ -> p
LT p _ _ -> p
LEQ p _ _ -> p
GEQ p _ _ -> p
GT p _ _ -> p
LitBool p _ -> p
-- integers
Add p _ _ -> p
Sub p _ _ -> p
Mul p _ _ -> p
Div p _ _ -> p
Mod p _ _ -> p
Exp p _ _ -> p
LitInt p _ -> p
IntEnv p _ -> p
-- bounds
IntMin p _ -> p
IntMax p _ -> p
UIntMin p _ -> p
UIntMax p _ -> p
InRange p _ _ -> p

-- bytestrings
Cat p _ _ -> p
Slice p _ _ _ -> p
ByStr p _ -> p
ByLit p _ -> p
ByEnv p _ -> p
-- contracts
Create p _ _ -> p

-- polymorphic
Eq p _ _ _ -> p
NEq p _ _ _ -> p
ITE p _ _ _ -> p
TEntry p _ _ -> p
Var p _ _ _ _ -> p
--------------------------------------
-- * Extraction from untyped ASTs * --
--------------------------------------
Expand Down
24 changes: 12 additions & 12 deletions src/Act/Type.hs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ andExps (c:cs) = foldl (\cs' c' -> And nowhere c' cs') c cs

-- | Check the type of an expression and construct a typed expression
checkExpr :: forall a t. Typeable t => Env -> SType a -> U.Expr -> Err (Exp a t)
checkExpr env@Env{constructors} typ e = case (typ, e) of
checkExpr env@Env{constructors, calldata} typ e = case (typ, e) of
-- Boolean expressions
(SBoolean, U.ENot p v1) -> Neg p <$> checkExpr env SBoolean v1
(SBoolean, U.EAnd p v1 v2) -> And p <$> checkExpr env SBoolean v1 <*> checkExpr env SBoolean v2
Expand All @@ -516,8 +516,8 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
(SInteger, U.ECreate p c args) -> case Map.lookup c constructors of
Just ctrs ->
let (typs, ptrs) = unzip ctrs in
checkIxs env p args (fmap PrimitiveType typs) `bindValidation` (\args ->
pure (Create p c args) <* traverse_ (\(e, t) -> checkContractType env e t) (zip args ptrs))
checkIxs env p args (fmap PrimitiveType typs) `bindValidation` (\args' ->
pure (Create p c args') <* traverse_ (\(e', t) -> checkContractType env e' t) (zip args' ptrs))
Nothing -> throw (p, "Unknown constructor " <> show c)

-- Control
Expand All @@ -537,16 +537,16 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
_ -> throw (p, "Unknown environment variable " <> show v1)

-- Variable references
(_, U.EUTEntry entry) | isCalldataEntry env entry -> -- TODO more principled way of treating timings
(_, U.EUTEntry entry) | isCalldataEntry entry -> -- TODO more principled way of treating timings
case (eqT @t @Timed, eqT @t @Untimed) of
(Just Refl, _) -> validateVar env entry `bindValidation` \(vt@(FromVType typ'), ref) ->
Var (getPosEntry entry) Pre typ vt ref <$ checkEq (getPosEntry entry) typ typ'
(_, Just Refl) -> validateVar env entry `bindValidation` \(vt@(FromVType typ'), ref) ->
Var (getPosEntry entry) Neither typ vt ref <$ checkEq (getPosEntry entry) typ typ'
(_,_) -> error "Internal error: Timing should be either Timed or Untimed"
-- Var (getPosEntry entry) Neither typ vt ref <$ checkEq (getPosEntry entry) typ typ'
(_, U.EPreEntry entry) | isCalldataEntry env entry -> error "Not supported"
(_, U.EPostEntry entry) | isCalldataEntry env entry -> error "Not supported"
(_, U.EPreEntry entry) | isCalldataEntry entry -> error "Not supported"
(_, U.EPostEntry entry) | isCalldataEntry entry -> error "Not supported"
-- Storage references
(_, U.EUTEntry entry) -> validateEntry env entry `bindValidation` \(vt@(FromVType typ'), ref) ->
checkTime (getPosEntry entry) <*> (TEntry (getPosEntry entry) Neither (Item typ vt ref) <$ checkEq (getPosEntry entry) typ typ')
Expand Down Expand Up @@ -576,11 +576,11 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
Nothing -> throw (pn, (tail . show $ typeRep @t) <> " variable needed here.")

-- TODO FIX
isCalldataEntry Env{calldata} (U.EVar _ name) = case Map.lookup name calldata of
isCalldataEntry (U.EVar _ name) = case Map.lookup name calldata of
Just _ -> True
_ -> False
isCalldataEntry env (U.EMapping _ entry _) = isCalldataEntry env entry
isCalldataEntry env (U.EField _ entry _) = isCalldataEntry env entry
isCalldataEntry (U.EMapping _ entry _) = isCalldataEntry entry
isCalldataEntry (U.EField _ entry _) = isCalldataEntry entry


-- | Find the contract id of an expression with contract type
Expand All @@ -601,9 +601,9 @@ checkContractType :: Env -> TypedExp t -> Maybe Id -> Err ()
checkContractType _ _ Nothing = pure ()
checkContractType env (TExp _ e) (Just c) =
findContractType env e `bindValidation` \oc ->
case oc of -- TODO fix position
Just c' -> assert (nowhere, "Expression was expected to have contract type " <> c <> " but has contract type " <> c') (c == c')
Nothing -> throw (nowhere, "Expression was expected to have contract type " <> c)
case oc of
Just c' -> assert (posnFromExp e, "Expression was expected to have contract type " <> c <> " but has contract type " <> c') (c == c')
Nothing -> throw (posnFromExp e, "Expression was expected to have contract type " <> c)

checkEq :: forall a b. Pn -> SType a -> SType b -> Err ()
checkEq p t1 t2 = maybe err (\Refl -> pure ()) $ testEquality t1 t2
Expand Down
43 changes: 43 additions & 0 deletions tests/frontend/fail/cast.act
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
constructor of A
interface constructor(uint w1)

iff
CALLVALUE == 0

creates
uint w := w1

constructor of B
interface constructor(uint z1)

iff
CALLVALUE == 0

creates
uint z := z1

constructor of C
interface constructor(address a1, address a2)

pointers
a1 |-> A
a2 |-> B

iff
CALLVALUE == 0

creates
A a := a1
B b := a2

constructor of D
interface constructor(address a1, address a2)

pointers
a1 |-> A

iff
CALLVALUE == 0

creates
C c1 := create C(a1, a2)
37 changes: 23 additions & 14 deletions tests/hevm/pass/cast-5/cast-5.act
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
constructor of C
constructor of A
interface constructor(uint w1)

iff
CALLVALUE == 0

creates
uint w := w1

constructor of B
interface constructor(uint z1)

iff
Expand All @@ -7,28 +16,28 @@ iff
creates
uint z := z1

constructor of A
interface constructor(uint x1)
constructor of C
interface constructor(address a1, address a2)

pointers
a1 |-> A
a2 |-> B

iff
CALLVALUE == 0

creates
uint x := x1
C c := create C(42)
A a := a1
B b := a2


constructor of B
interface constructor(address x, address y)
constructor of D
interface constructor(address a1, address a2)

pointers
x |-> A
y |-> A
a1 |-> A

iff
CALLVALUE == 0
x =/= y
CALLVALUE == 0

creates
A a1 := x
C c := x.c
C c1 := create C(a1, a2)
31 changes: 17 additions & 14 deletions tests/hevm/pass/cast-5/cast-5.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pragma solidity >=0.8.0;

contract C {
contract A {
uint z;

constructor(uint z1) {
Expand All @@ -9,25 +9,28 @@ contract C {

}

contract B {
uint t;

contract A {
uint x;
public C c;

constructor(uint x1) {
x = x1;
c = new C(42);
constructor(uint t1) {
t = t1;
}
}

contract C {
A a;
B b;

contract B {
A a1;
A a2;
constructor(address x, address y) {
a = A(x);
b = B(y);
}
}

contract D {
C c2;

constructor(address x, address y) {
require (x != y);
a1 = A(x);
a2 = a1.c();
c2 = new C(x,y);
}
}
40 changes: 40 additions & 0 deletions tests/hevm/pass/cast-6/cast-6.act
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
constructor of C
interface constructor(uint z1)

iff
CALLVALUE == 0

creates
uint z := z1

constructor of A
interface constructor(uint x1)

iff
CALLVALUE == 0

creates
uint x := x1
C c := create C(42)


behaviour c of A
interface c()

iff
CALLVALUE == 0

returns (pre(c))

constructor of B
interface constructor(address x)

pointers
x |-> A

iff
CALLVALUE == 0

creates
A a := x
C c := x.c
32 changes: 32 additions & 0 deletions tests/hevm/pass/cast-6/cast-6.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pragma solidity >=0.8.0;

contract C {
uint z;

constructor(uint z1) {
z = z1;
}

}


contract A {
uint x;
C public c;

constructor(uint x1) {
x = x1;
c = new C(42);
}
}


contract B {
A a;
C c;

constructor(address x) {
a = A(x);
c = a.c();
}
}

0 comments on commit 942f4f4

Please sign in to comment.