-
Notifications
You must be signed in to change notification settings - Fork 370
Description
This particular case is caused by #11403 but the knock-on effects are different enough that I think it warrants a separate issue.
Consider the program below.
fn main(b: Field) {
unsafe {
assert_eq(func_4(([0, 0], b)), func_4(([0, 0], b)));
}
}
unconstrained fn func_4(b: ([Field; 2], Field)) -> Field {
let (_, _) = b;
b.1
}This compiles to the SSA
acir(inline) impure fn main f0 {
b0(v0: Field):
v2 = make_array [Field 0, Field 0] : [Field; 2]
v4 = call f1(v2, v0) -> Field
v5 = call f1(v2, v0) -> Field
constrain v4 == v5
return
}
brillig(inline) impure fn func_4 f1 {
b0(v0: [Field; 2], v1: Field):
inc_rc v0
inc_rc v0
return v1
}
func_4 is listed as impure here because it contains inc_rc instructions and so mutates the reference counter for the array v0. This is expected in the case where func_4 is potentially called by other brillig functions as the inc_rc instructions will affect the arrays constructed by those other functions.
However in this case func_4 set up these arrays itself and therefore "owns" them. Therefore func_4 is in fact pure. Despite this however we don't end up deduplicating the two calls to func_4 from main because we always consider a function which contains an inc_rc instruction to be impure.
We should modify our concept of purity so that if a function is incrementing a reference counter to a array which is has created (i.e. make_array instruction or received from an ACIR function) then this is still considered pure.