-
Notifications
You must be signed in to change notification settings - Fork 233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement numeric generics #620
Conversation
Note that this PR seems to have found a new bug in either the SSA pass or acir gen - likely with regards to array handling or generic arrays now being allowed within structs. The error is currently occurring while running the new Edit: I think it is a separate bug, perhaps more related to the |
Fixed the bug in the global_consts test. In the future we can look into changing it to officially allow this rule but it impacts name resolution which will be greatly changed once the higher order functions PR is merged so I'd like to avoid these conflicts for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this PR looks good. Just had a coupe minor questions
Added a commit fixing a bug where the previous representation of fn bad_id<N, M>(a: [Field; N]) -> [Field; M] { a } and now it correctly errors. |
Alright, I've added support for parsing numeric generic expressions within the normal generic brackets |
Does this PR contemplate support for numeric generics in implementations. I'm working on a bigint library and am particularly interested in support for something like this struct BigInt<N> {
limbs : [u32; N],
}
impl BigInt<N> {
fn mul(self, other : BigInt<N>) -> BigInt<N * 2> {
// ...
}
} Also this fn loop_example<N>() -> Field {
let mut sum = 0;
for i in 0..N {
sum = sum + i;
}
sum
} |
Unfortunately not, impls currently do not support generics on the impl at all. This is planned though, and once generics on impls are supported numeric generics should come naturally with that. As for your specific examples I'll break them down a bit on what is supported and what is not: // Structs generic over unsigned integer numerals will be entirely supported as of this PR
struct BigInt<N> {
limbs : [u32; N],
}
// Generics on impls are not currently supported, but are planned for a later date
impl BigInt<N> {
// Arithmetic on generic parameters (N here) is currently unsupported officially.
// This PR provides the beginnings of support for them but offering full support would
// require full unification support for these which would require a symbolic expression solver.
// I'd like to experiment with expanding support for this in the future but this feature may be
// unnecessary if Noir ever gets true array slice types `[T]` with no hidden size parameter.
fn mul(self, other : BigInt<N>) -> BigInt<N * 2> {
// ...
}
}
fn loop_example<N>() -> Field {
let mut sum = 0;
// Using numeric generics as expressions themselves is also not supported. You can accomplish
// something similar however by passing in N as a comptime Field parameter instead. If you have an
// array type parameterized over N you can also extract it into a comptime Field via std::array::len.
// I may work on making numeric generics directly useable within expressions eventually but it is
// admittedly not the highest of priorities since there are workarounds present.
for i in 0..N {
sum = sum + i;
}
sum
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that there are a lot of similar code and I am wondering if we could not try to unify somehow comptime and numeric generics in a new type which gets to become evaluated after monomorphisation?
I believe this new type would not be restricted to u64 and could be another integer size or fieldelement (of course it will be u64 is used for array len).
If you think it is a good idea but it would be a significant change, we should do it in a separate PR.
If you think it is a bad idea, we can forget about it.
Just added a commit removing the experimental feature of allowing arithmetic on generic integers like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's OK for me, I agree that trying to do more has some implications so it's a good first step for now.
* master: Rename methods that use `conditionalize` to be more descriptive (#739) feat(noir)!: Returned values are no longer required by the prover (#731) chore: explicit versions for dependencies (#727) chore: readability improvements (#726) feat(nargo): include short git commit in cli version output (#721) Remove print to console for named proofs in `nargo prove` (#718) chore: clean up serde-related dependencies (#722) Handle out-of-bound errors in CSE (#471) (#673) Remove unused dependencies and only use workspace inheritance on shared deps (#671) feat(std_lib)!: modulus bits/bytes methods, and to_bits -> to_le_bits (#697) Implement numeric generics (#620) Review some TODO in SSA (#698) Replace `toml_map_to_field` and `toml_remap` with traits to map between `InputValue`s and `TomlTypes` (#677) Apply witness visibility on a parameter level rather than witness level (#712)
Related issue(s)
Provides a workaround for #606 but does not resolve it
Description
Summary of changes
Allow generics to be used in array length types. For example, this allows
Structs can also be parameterized over array lengths:
Some basic math on constants and globals (using
+
,-
,*
, and/
) is also supported, although we do not officially support math on non-constants likeN
above. Supporting arithmetic on variables likeN
would require non-trivial unification and evaluation support on symbolic expressions.Test additions / changes
Added test
numeric_generics
Checklist
cargo fmt
with default settings.Additional context
Some care was taken to avoid naming this feature "const generics" even though it is effectively quite similar to rust's const generics feature. Avoiding this name lets us:
const
keyword being co-opted for compile-time evaluated expressions rather than just constants is confusing. This feature is also not calledcomptime
generics in noir as we do not currently allowcomptime
variables within these generics. This is becausecomptime
variables can be passed in as function arguments and allowing for these to be referenced would require something closer to dependent types.