Description
In alloc.rs
, we have the following implementation for Vec<T>
:
/// This blanket implementation just allocates variables in `Self`
/// element by element.
impl<I, F: Field, A: AllocVar<I, F>> AllocVar<[I], F> for Vec<A> {
fn new_variable<T: Borrow<[I]>>(
cs: impl Into<Namespace<F>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
let mut vec = Vec::new();
for value in f()?.borrow().iter() {
vec.push(A::new_variable(cs.clone(), || Ok(value), mode)?);
}
Ok(vec)
}
}
However, in the setup mode, assignments are missing, and we expect all executions of f
to be wrapped, layer by layer, inside the closures of new_variable
. But the current implementation does not respect the setup mode. Instead, it runs f
and unwraps its result in the setup mode.
There seems no easy solution. One may want to unwrap f()
in each A::new_variable
, but f
is FnOnce
, so calling f()?
inside the closure of each value in the Vec
does not work.
Now let me describe some thinking on how to solve it.
First, we can let new_variable
break the "fourth wall" and check whether the ConstraintSystem being referenced is in the setup mode. This would allow it to treat the case in the setup mode differently.
However, this is not enough, because it also needs to learn the size of the Vec
. If f()
cannot be run and unwrapped, there is no way for it to learn the size.
So, this becomes a tangled situation. Going further, did we use this Vec<T>
blanket implementation anywhere?