Merge pull request #798 from Zokrates/accept-explicit-generics
Accept explicit generic parameters for function calls
This commit is contained in:
commit
f4faad94f1
5 changed files with 36 additions and 4 deletions
1
changelogs/unreleased/798-schaeff
Normal file
1
changelogs/unreleased/798-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Accept explicit generic parameters outside of definitions
|
|
@ -0,0 +1,5 @@
|
|||
def foo<N>() -> field[N]:
|
||||
return [42; N]
|
||||
|
||||
def main() -> field[2]:
|
||||
return foo() // N is currently not infered to 2 here
|
6
zokrates_cli/examples/explicit_generic.zok
Normal file
6
zokrates_cli/examples/explicit_generic.zok
Normal file
|
@ -0,0 +1,6 @@
|
|||
def foo<N>() -> field[N]:
|
||||
return [42; N]
|
||||
|
||||
def main() -> field[2]:
|
||||
field a = foo::<3>()[0]
|
||||
return foo::<2>()
|
|
@ -1923,16 +1923,19 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
message: format!("Expected function call argument to be of type {}, found {}", e.1, e.0)
|
||||
})?;
|
||||
|
||||
let output_types = signature.get_output_types(arguments_checked.iter().map(|a| a.get_type()).collect()).map_err(|e| ErrorInner {
|
||||
let generics_checked = generics_checked.unwrap_or_else(|| vec![None; signature.generics.len()]);
|
||||
|
||||
let output_types = signature.get_output_types(
|
||||
generics_checked.clone(),
|
||||
arguments_checked.iter().map(|a| a.get_type()).collect()
|
||||
).map_err(|e| ErrorInner {
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Failed to infer value for generic parameter `{}`, try being more explicit by using an intermediate variable",
|
||||
"Failed to infer value for generic parameter `{}`, try providing an explicit value",
|
||||
e,
|
||||
),
|
||||
})?;
|
||||
|
||||
let generics_checked = generics_checked.unwrap_or_else(|| vec![None; signature.generics.len()]);
|
||||
|
||||
// the return count has to be 1
|
||||
match output_types.len() {
|
||||
1 => match &output_types[0] {
|
||||
|
|
|
@ -1047,11 +1047,28 @@ pub mod signature {
|
|||
|
||||
pub fn get_output_types<T: Clone + PartialEq + fmt::Debug>(
|
||||
&self,
|
||||
generics: Vec<Option<UExpression<'ast, T>>>,
|
||||
inputs: Vec<Type<'ast, T>>,
|
||||
) -> Result<Vec<Type<'ast, T>>, GenericIdentifier<'ast>> {
|
||||
// we keep track of the value of constants in a map, as a given constant can only have one value
|
||||
let mut constants = GenericsAssignment::default();
|
||||
|
||||
// initialise the map with the explicitly provided generics
|
||||
constants
|
||||
.0
|
||||
.extend(self.generics.iter().zip(generics).filter_map(|(g, v)| {
|
||||
// only add to the map when there's indeed a generic value being provided
|
||||
v.map(|v| {
|
||||
(
|
||||
match g.clone().unwrap() {
|
||||
Constant::Generic(g) => g,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
v,
|
||||
)
|
||||
})
|
||||
}));
|
||||
|
||||
// fill the map with the inputs
|
||||
let _ = self
|
||||
.inputs
|
||||
|
|
Loading…
Reference in a new issue