Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions run_contests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bash ./contest.sh test/examples/dispatch/fallback.json
bash ./contest.sh test/examples/dispatch/ecrecover.json
bash ./contest.sh test/examples/dispatch/memory.json
bash ./contest.sh test/examples/dispatch/storage.json
bash ./contest.sh test/examples/dispatch/transient_field.json
bash ./contest.sh test/examples/dispatch/generic_sum.json
bash ./contest.sh test/examples/dispatch/generic_product.json
bash ./contest.sh test/examples/dispatch/sum_wide_product.json
Expand Down
11 changes: 7 additions & 4 deletions src/Solcore/Desugarer/FieldAccess.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extraTopDeclsForContract includeSingleton (Contract cname _ts cdecls) = do
offset = foldr pair unit tys

extraTopDeclsForContractField :: ContractName -> NmField -> Ty -> [NmTopDecl]
extraTopDeclsForContractField cname (Field fname fty _minit) offset = [selDecl, TInstDef sfInstance]
extraTopDeclsForContractField cname (Field fname fty _minit loc) offset = [selDecl, TInstDef sfInstance]
where
-- data b_sel = n_sel
selName = selectorNameForField cname fname
Expand All @@ -90,13 +90,16 @@ extraTopDeclsForContractField cname (Field fname fty _minit) offset = [selDecl,
instVars = [],
instContext = [],
instName = "CStructField",
paramsTy = [translateFieldType fty, offset],
paramsTy = [translateFieldType loc fty, offset],
mainTy = TyCon "StructField" [ctxTy, selType],
instFunctions = []
}

translateFieldType :: Ty -> Ty
translateFieldType t = TyCon "storage" [t]
-- A regular field of type `t` is stored in persistent storage as `storage(t)`;
-- a `transient` field lives in EVM transient storage as `tstorage(t)`.
translateFieldType :: StorageLocation -> Ty -> Ty
translateFieldType Storage t = TyCon "storage" [t]
translateFieldType Transient t = TyCon "tstorage" [t]

--------------------------------
-- # Contract Desugaring
Expand Down
4 changes: 2 additions & 2 deletions src/Solcore/Desugarer/IndirectCall.hs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ instance Desugar (ContractDecl Name) where
desugar d = pure d

instance Desugar (Field Name) where
desugar (Field n t me) =
Field n t <$> desugar me
desugar (Field n t me loc) =
(\me' -> Field n t me' loc) <$> desugar me

instance Desugar (Constructor Name) where
desugar (Constructor ps bd payable) =
Expand Down
1 change: 1 addition & 0 deletions src/Solcore/Frontend/Lexer/SolcoreLexer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ reservedWords =
"fallback",
"payable",
"public",
"transient",
"constructor",
"return",
"lam",
Expand Down
8 changes: 4 additions & 4 deletions src/Solcore/Frontend/Module/Loader.hs
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,8 @@ stubTopDeclBody decl =
decl

stubContractDeclBody :: ContractDecl -> ContractDecl
stubContractDeclBody (CFieldDecl (Field n ty _initExp)) =
CFieldDecl (Field n ty Nothing)
stubContractDeclBody (CFieldDecl (Field n ty _initExp loc)) =
CFieldDecl (Field n ty Nothing loc)
stubContractDeclBody (CFunDecl fd) =
CFunDecl (stubFunDefBody fd)
stubContractDeclBody (CConstrDecl (Constructor params _body payable)) =
Expand Down Expand Up @@ -1575,9 +1575,9 @@ renameContractTypeRefs renameMap (Contract n ts ds) =
renameContractDeclTypeRefs :: Map Name Name -> ContractDecl -> ContractDecl
renameContractDeclTypeRefs renameMap (CDataDecl d) =
CDataDecl (renameDataTyTypeRefs renameMap d)
renameContractDeclTypeRefs renameMap (CFieldDecl (Field n ty me)) =
renameContractDeclTypeRefs renameMap (CFieldDecl (Field n ty me loc)) =
CFieldDecl
(Field n (renameTyTypeRefs renameMap ty) (renameExpTypeRefs renameMap <$> me))
(Field n (renameTyTypeRefs renameMap ty) (renameExpTypeRefs renameMap <$> me) loc)
renameContractDeclTypeRefs renameMap (CFunDecl fd) =
CFunDecl (renameFunDefTypeRefs renameMap fd)
renameContractDeclTypeRefs renameMap (CConstrDecl (Constructor ps body payable)) =
Expand Down
4 changes: 3 additions & 1 deletion src/Solcore/Frontend/Parser/Decl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Solcore.Frontend.Parser.SolcoreTypes
import Solcore.Frontend.Parser.Stmt (bodyP)
import Solcore.Frontend.Syntax.Name
import Solcore.Frontend.Syntax.SyntaxTree
import Solcore.Frontend.Syntax.Ty (StorageLocation (..))

-- Top-level entry point

Expand Down Expand Up @@ -379,10 +380,11 @@ fieldDeclP :: Parser Field
fieldDeclP = do
n <- simpleNameP
_ <- colon
loc <- option Storage (Transient <$ keyword "transient")
ty <- typeP
me <- optional (equalsP *> expP)
_ <- semicolon
return (Field n ty me)
return (Field n ty me loc)

constructorDeclP :: Parser Constructor
constructorDeclP = do
Expand Down
8 changes: 6 additions & 2 deletions src/Solcore/Frontend/Pretty/SolcorePretty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,12 @@ pprFunBlock =
vcat . map ppr

instance (Pretty a) => Pretty (Field a) where
ppr (Field n ty e) =
ppr n <+> colon <+> (ppr ty) <+> pprInitOpt e
ppr (Field n ty e loc) =
ppr n <+> colon <+> locTy <+> pprInitOpt e
where
locTy = case loc of
Storage -> ppr ty
Transient -> text "transient" <+> ppr ty

instance (Pretty a) => Pretty (Body a) where
ppr = vcat . map ppr
Expand Down
9 changes: 7 additions & 2 deletions src/Solcore/Frontend/Pretty/TreePretty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Common.Pretty
import Data.List.NonEmpty qualified as N
import Solcore.Frontend.Syntax.Name
import Solcore.Frontend.Syntax.SyntaxTree
import Solcore.Frontend.Syntax.Ty (StorageLocation (..))

pretty :: (Pretty a) => a -> String
pretty = render . ppr
Expand Down Expand Up @@ -238,8 +239,12 @@ pprFunBlock =
vcat . map ppr

instance Pretty Field where
ppr (Field n ty e) =
ppr n <+> colon <+> (ppr ty) <+> pprInitOpt e
ppr (Field n ty e loc) =
ppr n <+> colon <+> locTy <+> pprInitOpt e
where
locTy = case loc of
Storage -> ppr ty
Transient -> text "transient" <+> ppr ty

instance Pretty Body where
ppr = vcat . map ppr
Expand Down
5 changes: 3 additions & 2 deletions src/Solcore/Frontend/Syntax/Contract.hs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ data Field a
= Field
{ fieldName :: Name,
fieldTy :: Ty,
fieldInit :: Maybe (Exp a)
fieldInit :: Maybe (Exp a),
fieldLoc :: StorageLocation
}
deriving (Eq, Ord, Show, Data, Typeable)

Expand Down Expand Up @@ -344,7 +345,7 @@ instance (HasSourceSpan a) => HasSourceSpan (Instance a) where
firstSourceSpan [sourceSpanOf vars, sourceSpanOf context, sourceSpanOf clsName, sourceSpanOf params, sourceSpanOf main, sourceSpanOf funs]

instance (HasSourceSpan a) => HasSourceSpan (Field a) where
sourceSpanOf (Field n ty initExp) =
sourceSpanOf (Field n ty initExp _) =
firstSourceSpan [sourceSpanOf n, sourceSpanOf ty, sourceSpanOf initExp]

instance (HasSourceSpan a) => HasSourceSpan (FunDef a) where
Expand Down
6 changes: 3 additions & 3 deletions src/Solcore/Frontend/Syntax/NameResolution.hs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ addContractDecl (S.CDataDecl (S.DataTy n _ cons)) =
do
addTyCon n
mapM_ (addDataCon n . S.constrName) cons
addContractDecl (S.CFieldDecl (S.Field n _ _)) =
addContractDecl (S.CFieldDecl (S.Field n _ _ _)) =
addField n
addContractDecl (S.CFunDecl (S.FunDef _ sig _)) =
addFunctionName (S.sigName sig)
Expand Down Expand Up @@ -260,11 +260,11 @@ instance Resolve S.Constructor where
instance Resolve S.Field where
type Result S.Field = Field Name

resolve f@(S.Field n t me) =
resolve f@(S.Field n t me loc) =
do
t' <- resolve t `wrapError` f
me' <- resolve me `wrapError` f
pure (Field n t' me')
pure (Field n t' me' loc)

instance Resolve S.Class where
type Result S.Class = Class Name
Expand Down
6 changes: 4 additions & 2 deletions src/Solcore/Frontend/Syntax/SyntaxTree.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Language.Yul
import Solcore.Diagnostics (SourceSpan)
import Solcore.Frontend.Syntax.Location
import Solcore.Frontend.Syntax.Name
import Solcore.Frontend.Syntax.Ty (StorageLocation (..))
import Prelude hiding (exp)

-- compilation unit
Expand Down Expand Up @@ -237,7 +238,8 @@ data Field
= Field
{ fieldName :: Name,
fieldTy :: Ty,
fieldInit :: Maybe Exp
fieldInit :: Maybe Exp,
fieldLoc :: StorageLocation
}
deriving (Eq, Ord, Show, Data, Typeable)

Expand Down Expand Up @@ -364,7 +366,7 @@ instance HasSourceSpan Instance where
firstSourceSpan [sourceSpanOf vars, sourceSpanOf context, sourceSpanOf clsName, sourceSpanOf params, sourceSpanOf main, sourceSpanOf funs]

instance HasSourceSpan Field where
sourceSpanOf (Field n ty initExp) =
sourceSpanOf (Field n ty initExp _) =
firstSourceSpan [sourceSpanOf n, sourceSpanOf ty, sourceSpanOf initExp]

instance HasSourceSpan FunDef where
Expand Down
7 changes: 7 additions & 0 deletions src/Solcore/Frontend/Syntax/Ty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import Solcore.Frontend.Syntax.Name

-- basic typing infrastructure

-- | Storage location of a contract field. Fields default to persistent
-- 'Storage'; 'Transient' selects EVM transient storage (tload/tstore).
data StorageLocation
= Storage
| Transient
deriving (Eq, Ord, Show, Data, Typeable)

data Tyvar
= TVar {var :: Name} -- bound variable
| Skolem Name -- skolem constant
Expand Down
2 changes: 1 addition & 1 deletion src/Solcore/Frontend/TypeInference/SccAnalysis.hs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ instance Names Pred where
names [t1, t2]

instance Names (Field Name) where
names (Field _ t me) =
names (Field _ t me _) =
names t `union` names me

instance Names TySym where
Expand Down
8 changes: 4 additions & 4 deletions src/Solcore/Frontend/TypeInference/TcContract.hs
Original file line number Diff line number Diff line change
Expand Up @@ -343,18 +343,18 @@ tcConstr (Constr n ts) =
-- type checking fields

tcField :: Field Name -> TcM (Field Id)
tcField d@(Field n t (Just e)) =
tcField d@(Field n t (Just e) loc) =
do
(e', _, t') <- tcExp e
t1 <- kindCheck t `wrapError` d
_ <- mgu t t' `wrapError` d
extEnv n (monotype t1)
return (Field n t1 (Just e'))
tcField d@(Field n t _) =
return (Field n t1 (Just e') loc)
tcField d@(Field n t _ loc) =
do
t1 <- kindCheck t `wrapError` d
extEnv n (monotype t1)
pure (Field n t1 Nothing)
pure (Field n t1 Nothing loc)

tcClass :: Class Name -> TcM (Class Id)
tcClass iclass@(Class bvs classCtx n vs v sigs) =
Expand Down
10 changes: 5 additions & 5 deletions src/Solcore/Frontend/TypeInference/TcSubst.hs
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,11 @@ instance (HasType a) => HasType (ContractDecl a) where
bv _ = []

instance (HasType a) => HasType (Field a) where
apply s (Field n t me) =
Field n (apply s t) (apply s me)
fv (Field _ t me) = fv t `union` fv me
mv (Field _ t me) = mv t `union` mv me
bv (Field _ t me) = bv t `union` bv me
apply s (Field n t me loc) =
Field n (apply s t) (apply s me) loc
fv (Field _ t me _) = fv t `union` fv me
mv (Field _ t me _) = mv t `union` mv me
bv (Field _ t me _) = bv t `union` bv me

instance (HasType a) => HasType (Constructor a) where
apply s (Constructor ps bd payable) =
Expand Down
27 changes: 17 additions & 10 deletions std/std.solc
Original file line number Diff line number Diff line change
Expand Up @@ -1650,25 +1650,32 @@ function memberAccessBase(x:MemberAccessProxy(a, field, fieldType, offset)) ->
// Contract field access
// ------------------------------------------------------------------

forall cxt fieldSelector loadType offsetType storageType
. StructField(ContractStorage(cxt), fieldSelector) :CStructField(storage(storageType), offsetType)
// These instances are abstract over the reference type `refType` that the
// field's CStructField maps to (`storage(_)` for a regular field, `tstorage(_)`
// for a `transient` field). The reference is built from the slot offset via
// `Typedef.abs`, and loaded/stored via `CanStore`, so the same instance serves
// both storage locations; FieldAccess picks the location by choosing refType.
forall cxt fieldSelector loadType offsetType refType
. StructField(ContractStorage(cxt), fieldSelector) :CStructField(refType, offsetType)
, offsetType : StorageSize
, storage(storageType): CanStore(loadType)
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType) : LVA (storage(storageType)) {
function acc (x : MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType)) -> storage(storageType) {
, refType : Typedef(word)
, refType : CanStore(loadType)
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType) : LVA (refType) {
function acc (x : MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType)) -> refType {
let offset : word = StorageSize.size(Proxy : Proxy(offsetType)) ;
return storage(offset):storage(storageType);
return Typedef.abs(offset):refType;
}
}

forall cxt fieldSelector loadType offsetType storageType
. StructField(ContractStorage(cxt), fieldSelector):CStructField(storage(storageType), offsetType)
, storage(storageType):CanStore(loadType)
forall cxt fieldSelector loadType offsetType refType
. StructField(ContractStorage(cxt), fieldSelector):CStructField(refType, offsetType)
, refType : Typedef(word)
, refType:CanStore(loadType)
, offsetType:StorageSize
=> instance MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType):RVA(loadType) {
function acc(x:MemberAccessProxy(ContractStorage(cxt), fieldSelector, loadType, offsetType)) -> loadType {
let offset:word = StorageSize.size(Proxy:Proxy(offsetType));
return CanStore.load(storage(offset):storage(storageType)):loadType;
return CanStore.load(Typedef.abs(offset):refType):loadType;
}
}

Expand Down
Loading
Loading