@@ -14,6 +14,7 @@ use edge_ast::{
1414 Program ,
1515} ;
1616use indexmap:: IndexMap ;
17+ use ruint:: aliases:: U256 ;
1718use tiny_keccak:: { Hasher , Keccak } ;
1819
1920/// Storage slot assignment for contract fields
@@ -28,8 +29,8 @@ pub struct StorageLayout {
2829pub struct ConstValue {
2930 /// Constant name
3031 pub name : String ,
31- /// Resolved u256 value (fits in u64 for simple literals)
32- pub value : u64 ,
32+ /// Resolved value as big-endian 256-bit bytes
33+ pub value : [ u8 ; 32 ] ,
3334}
3435
3536/// A function's type information
@@ -179,12 +180,12 @@ impl TypeChecker {
179180 . collect ( ) ;
180181
181182 // Process constants (evaluate simple literal/arithmetic expressions)
182- let mut const_env: IndexMap < String , u64 > = IndexMap :: new ( ) ;
183+ let mut const_env: IndexMap < String , [ u8 ; 32 ] > = IndexMap :: new ( ) ;
183184 let consts = contract
184185 . consts
185186 . iter ( )
186187 . map ( |( decl, expr) | {
187- let value = Self :: eval_const_expr ( expr, & const_env) . unwrap_or ( 0 ) ;
188+ let value = Self :: eval_const_expr ( expr, & const_env) . unwrap_or ( [ 0u8 ; 32 ] ) ;
188189 const_env. insert ( decl. name . name . clone ( ) , value) ;
189190 ConstValue {
190191 name : decl. name . name . clone ( ) ,
@@ -293,54 +294,103 @@ impl TypeChecker {
293294 }
294295 }
295296
296- /// Evaluate a constant expression to a u64 value.
297+ /// Evaluate a constant expression to a 256-bit value.
297298 /// Supports literals and simple arithmetic over previously-defined constants.
298- fn eval_const_expr ( expr : & Expr , env : & IndexMap < String , u64 > ) -> Option < u64 > {
299+ /// Uses U256 arithmetic to match EVM semantics (256-bit wrapping).
300+ fn eval_const_expr ( expr : & Expr , env : & IndexMap < String , [ u8 ; 32 ] > ) -> Option < [ u8 ; 32 ] > {
299301 match expr {
300302 Expr :: Literal ( lit) => match lit. as_ref ( ) {
301- Lit :: Int ( bytes, _, _) => {
302- // Values >u64 can't be evaluated here yet — return None
303- // rather than silently truncating. Full U256 const eval
304- // is planned as part of issue #43.
305- if bytes[ ..24 ] . iter ( ) . any ( |& b| b != 0 ) {
306- return None ;
303+ Lit :: Int ( bytes, _, _) => Some ( * bytes) ,
304+ Lit :: Bool ( b, _) => {
305+ let mut result = [ 0u8 ; 32 ] ;
306+ if * b {
307+ result[ 31 ] = 1 ;
307308 }
308- Some ( u64 :: from_be_bytes ( bytes [ 24 .. 32 ] . try_into ( ) . unwrap ( ) ) )
309+ Some ( result )
309310 }
310- Lit :: Bool ( b, _) => Some ( if * b { 1 } else { 0 } ) ,
311311 Lit :: Hex ( bytes, _) | Lit :: Bin ( bytes, _) => {
312- let mut v = 0u64 ;
313- for & b in bytes. iter ( ) . take ( 8 ) {
314- v = ( v << 8 ) | ( b as u64 ) ;
315- }
316- Some ( v)
312+ let mut result = [ 0u8 ; 32 ] ;
313+ let len = bytes. len ( ) . min ( 32 ) ;
314+ result[ 32 - len..] . copy_from_slice ( & bytes[ ..len] ) ;
315+ Some ( result)
317316 }
318317 Lit :: Str ( _, _) => None ,
319318 } ,
320319 Expr :: Ident ( id) => env. get ( & id. name ) . copied ( ) ,
321320 Expr :: Paren ( inner, _) => Self :: eval_const_expr ( inner, env) ,
322321 Expr :: Binary ( lhs, op, rhs, _) => {
323- let l = Self :: eval_const_expr ( lhs, env) ?;
324- let r = Self :: eval_const_expr ( rhs, env) ?;
325- match op {
326- BinOp :: Add => Some ( l. wrapping_add ( r) ) ,
327- BinOp :: Sub => Some ( l. wrapping_sub ( r) ) ,
328- BinOp :: Mul => Some ( l. wrapping_mul ( r) ) ,
329- BinOp :: Div if r != 0 => Some ( l / r) ,
330- BinOp :: Mod if r != 0 => Some ( l % r) ,
331- BinOp :: BitwiseAnd => Some ( l & r) ,
332- BinOp :: BitwiseOr => Some ( l | r) ,
333- BinOp :: BitwiseXor => Some ( l ^ r) ,
334- BinOp :: Shl => Some ( l << ( r & 63 ) ) ,
335- BinOp :: Shr => Some ( l >> ( r & 63 ) ) ,
336- BinOp :: Eq => Some ( if l == r { 1 } else { 0 } ) ,
337- BinOp :: Neq => Some ( if l != r { 1 } else { 0 } ) ,
338- BinOp :: Lt => Some ( if l < r { 1 } else { 0 } ) ,
339- BinOp :: Gt => Some ( if l > r { 1 } else { 0 } ) ,
340- BinOp :: Lte => Some ( if l <= r { 1 } else { 0 } ) ,
341- BinOp :: Gte => Some ( if l >= r { 1 } else { 0 } ) ,
342- _ => None ,
343- }
322+ let l_bytes = Self :: eval_const_expr ( lhs, env) ?;
323+ let r_bytes = Self :: eval_const_expr ( rhs, env) ?;
324+ let l = U256 :: from_be_bytes ( l_bytes) ;
325+ let r = U256 :: from_be_bytes ( r_bytes) ;
326+ let result = match op {
327+ BinOp :: Add => l. wrapping_add ( r) ,
328+ BinOp :: Sub => l. wrapping_sub ( r) ,
329+ BinOp :: Mul => l. wrapping_mul ( r) ,
330+ BinOp :: Div if !r. is_zero ( ) => l / r,
331+ BinOp :: Mod if !r. is_zero ( ) => l % r,
332+ BinOp :: BitwiseAnd => l & r,
333+ BinOp :: BitwiseOr => l | r,
334+ BinOp :: BitwiseXor => l ^ r,
335+ BinOp :: Shl => {
336+ if r >= U256 :: from ( 256 ) {
337+ U256 :: ZERO
338+ } else {
339+ l << r. to :: < usize > ( )
340+ }
341+ }
342+ BinOp :: Shr => {
343+ if r >= U256 :: from ( 256 ) {
344+ U256 :: ZERO
345+ } else {
346+ l >> r. to :: < usize > ( )
347+ }
348+ }
349+ BinOp :: Eq => {
350+ if l == r {
351+ U256 :: from ( 1 )
352+ } else {
353+ U256 :: ZERO
354+ }
355+ }
356+ BinOp :: Neq => {
357+ if l != r {
358+ U256 :: from ( 1 )
359+ } else {
360+ U256 :: ZERO
361+ }
362+ }
363+ BinOp :: Lt => {
364+ if l < r {
365+ U256 :: from ( 1 )
366+ } else {
367+ U256 :: ZERO
368+ }
369+ }
370+ BinOp :: Gt => {
371+ if l > r {
372+ U256 :: from ( 1 )
373+ } else {
374+ U256 :: ZERO
375+ }
376+ }
377+ BinOp :: Lte => {
378+ if l <= r {
379+ U256 :: from ( 1 )
380+ } else {
381+ U256 :: ZERO
382+ }
383+ }
384+ BinOp :: Gte => {
385+ if l >= r {
386+ U256 :: from ( 1 )
387+ } else {
388+ U256 :: ZERO
389+ }
390+ }
391+ _ => return None ,
392+ } ;
393+ Some ( result. to_be_bytes ( ) )
344394 }
345395 _ => None ,
346396 }
0 commit comments