noir-lang / noir

Noir is a domain specific language for zero knowledge proofs
https://noir-lang.org
Apache License 2.0
858 stars 186 forks source link

Value used in lvalue array indexing does not have its type inferred #5606

Open nventuro opened 1 month ago

nventuro commented 1 month ago

Aim

Below is a simplified version of a real life function I wrote:

fn push_to_array(array: [Field; 2], new_elem: Field) -> [Field; 3] {
    let mut concatenated = std::unsafe::zeroed();

    for i in 0..array.len() {
        concatenated[i] = array[i];
    }

    concatenated[concatenated.len() - 1] = new_elem;

    concatenated
}

This fails to compile: it resports ambiguous expression errors, and complains about using bracket indexing for concatenated when its type is _ and not array. Typing the value with let mut concatenated: [Field; 3] = std::unsafe::zeroed() causes for the function to compile with no errors. I'm however surprised that I need to specify this type however, since concatenated is the return value of the function: I'd expect its type to be inferred automatically.

This is of course not a huge issue, but I'm wondering whether this is a bug in the type inference mechanism, an oversight, or something that is not supported due to some implementation reason.

jfecher commented 1 month ago

This is from this chunk of code: https://github.com/noir-lang/noir/blob/master/compiler/noirc_frontend/src/elaborator/statements.rs#L322-L340 where we try to check the array or slice type instead of unifying.

It is a bit awkward to fix since we want to allow arrays and slices so can't unify with either. We can fix it by using try_unify to an array or slice first, then on failure trying to unify again to the other type and only then issuing an error if both fail.