Skip to content

Commit

Permalink
fix: invalid folded mutable constant value
Browse files Browse the repository at this point in the history
  • Loading branch information
katat committed Jan 4, 2025
1 parent 6f8db33 commit 0b91748
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/negative_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,29 @@ fn test_generic_custom_type_mismatched() {
));
}

#[test]
fn test_generic_mutated_cst_var_in_loop() {
let code = r#"
fn gen(const LEN: Field) -> [Field; LEN] {
return [0; LEN];
}
fn main(pub xx: Field) {
let mut loopvar = 1;
for ii in 0..3 {
loopvar = loopvar + 1;
}
let arr = gen(loopvar);
}
"#;

let res = tast_pass(code).0;
assert!(matches!(
res.unwrap_err().kind,
ErrorKind::ArgumentTypeMismatch(..)
));
}

#[test]
fn test_array_bounds() {
let code = r#"
Expand Down
4 changes: 4 additions & 0 deletions src/type_checker/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ impl<B: Backend> TypeChecker<B> {
.compute_type(lhs, typed_fn_env)?
.expect("type-checker bug: lhs access on an empty var");

if let Some(var_name) = &lhs_node.var_name {
typed_fn_env.invalidate_cst_var(var_name);
}

// todo: check and update the const field type for other cases
// lhs can be a local variable or a path to an array
let lhs_name = match &lhs.kind {
Expand Down
22 changes: 22 additions & 0 deletions src/type_checker/fn_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,28 @@ impl TypedFnEnv {
self.current_scope >= prefix_scope
}

/// Because we don't support forloop unrolling,
/// we should invalidate the constant value behind a mutable variable, which is used in a forloop.
/// ```ignore
/// let mut pow2 = 1;
/// for ii in 0..LEN {
/// pow2 = pow2 + pow2;
/// }
/// ```
/// Instead of folding the constant value to the mutable variable in this case,
/// the actual value will be calculated during synthesizer phase.
pub fn invalidate_cst_var(&mut self, ident: &str) {
// only applies to the variables in the parent scopes
// remove the constant value
if let Some((scope, info)) = self.vars.get_mut(ident) {
if scope < &mut self.current_scope
&& matches!(info.typ, TyKind::Field { constant: true })
{
info.typ = TyKind::Field { constant: false };
}
}
}

/// Since currently we don't support unrolling, the generic function calls are assumed to target a same instance.
/// Each loop iteration should instantiate generic function calls with the same parameters.
/// This assumption requires a few type checking rules to forbid the cases that needs unrolling.
Expand Down

0 comments on commit 0b91748

Please sign in to comment.