Skip to content

Commit

Permalink
fix: correctly evaluate public constants (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Jan 12, 2025
1 parent 0cc0b31 commit 1c781b2
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 11 deletions.
11 changes: 7 additions & 4 deletions crates/sema/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ impl<'gcx> ConstantEvaluator<'gcx> {
fn eval_expr(&mut self, expr: &hir::Expr<'_>) -> EvalResult<'gcx> {
let expr = expr.peel_parens();
match expr.kind {
// hir::ExprKind::Array(_) => {
// unimplemented!()
// }
// hir::ExprKind::Array(_) => unimplemented!(),
// hir::ExprKind::Assign(_, _, _) => unimplemented!(),
hir::ExprKind::Binary(l, bin_op, r) => {
let l = self.try_eval(l)?;
Expand All @@ -74,7 +72,12 @@ impl<'gcx> ConstantEvaluator<'gcx> {
// hir::ExprKind::Call(_, _) => unimplemented!(),
// hir::ExprKind::CallOptions(_, _) => unimplemented!(),
// hir::ExprKind::Delete(_) => unimplemented!(),
hir::ExprKind::Ident(&[hir::Res::Item(hir::ItemId::Variable(v))]) => {
hir::ExprKind::Ident(res) => {
// Ignore invalid overloads since they will get correctly detected later.
let Some(v) = res.iter().find_map(|res| res.as_variable()) else {
return Err(EE::NonConstantVar.into());
};

let v = self.gcx.hir.variable(v);
if v.mutability != Some(hir::VarMut::Constant) {
return Err(EE::NonConstantVar.into());
Expand Down
10 changes: 7 additions & 3 deletions crates/sema/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ impl LoopSource {
}

/// Resolved name.
#[derive(Clone, Copy, PartialEq, Eq, From, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, From, EnumIs)]
pub enum Res {
/// A resolved item.
Item(ItemId),
Expand Down Expand Up @@ -1091,8 +1091,12 @@ impl Res {
}
}

pub fn is_err(&self) -> bool {
matches!(self, Self::Err(_))
pub fn as_variable(&self) -> Option<VariableId> {
if let Self::Item(id) = self {
id.as_variable()
} else {
None
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion tests/ui/typeck/eval.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ uint constant tooBigLiteral = 11579208923731619542357098500868790785326998466564

contract C {
uint constant zero = x - x;
uint public constant zeroPublic = x / x - 1;
uint[zero] public zeroArray; //~ ERROR: array length must be greater than zero
uint[zeroPublic + 1] public oneArray;

uint[bigLiteral] public big;
uint[bigLiteral + 1] public tooBig1; //~ ERROR: evaluation of constant value failed
Expand All @@ -25,10 +28,11 @@ contract C {

function g(uint[0] memory) public {} //~ ERROR: array length must be greater than zero
function h(uint[zero] memory) public {} //~ ERROR: array length must be greater than zero
function h2(uint[zeroPublic] memory) public {} //~ ERROR: array length must be greater than zero

function i(uint[block.timestamp] memory) public {} //~ ERROR: evaluation of constant value failed
function j(uint["lol"] memory) public {} //~ ERROR: evaluation of constant value failed
function k(uint[--x] memory) public {} //~ ERROR: evaluation of constant value failed
function l(uint[stateVar] memory) public {} //~ ERROR: evaluation of constant value failed
function l(uint[stateVarPublic] memory) public {} //~ ERROR: evaluation of constant value failed
function m(uint[stateVarPublic] memory) public {} //~ ERROR: evaluation of constant value failed
}
20 changes: 17 additions & 3 deletions tests/ui/typeck/eval.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ LL | function h(uint[zero] memory) public {}
| ^^^^
|

error: array length must be greater than zero
--> ROOT/tests/ui/typeck/eval.sol:LL:CC
|
LL | function h2(uint[zeroPublic] memory) public {}
| ^^^^^^^^^^
|

error: evaluation of constant value failed
--> ROOT/tests/ui/typeck/eval.sol:LL:CC
|
Expand Down Expand Up @@ -93,10 +100,17 @@ LL | function l(uint[stateVar] memory) public {}
error: evaluation of constant value failed
--> ROOT/tests/ui/typeck/eval.sol:LL:CC
|
LL | function l(uint[stateVarPublic] memory) public {}
LL | function m(uint[stateVarPublic] memory) public {}
| --------------
| |
| note: unsupported expression
| note: only constant variables are allowed
|

error: array length must be greater than zero
--> ROOT/tests/ui/typeck/eval.sol:LL:CC
|
LL | uint[zero] public zeroArray;
| ^^^^
|

error: evaluation of constant value failed
Expand All @@ -120,5 +134,5 @@ LL | uint[tooBigLiteral] public tooBig2;
| ^^^^^^^^^^^^^
|

error: aborting due to 13 previous errors
error: aborting due to 15 previous errors

0 comments on commit 1c781b2

Please sign in to comment.