Merge pull request #822 from Zokrates/stricter_function_match
Consider input count and generics count in semantic checker
This commit is contained in:
commit
0d20f6a107
5 changed files with 32 additions and 2 deletions
1
changelogs/unreleased/822-schaeff
Normal file
1
changelogs/unreleased/822-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Make function selection stricter in function calls
|
|
@ -0,0 +1,5 @@
|
|||
def foo() -> field:
|
||||
return 1
|
||||
|
||||
def main() -> field:
|
||||
return foo(42)
|
|
@ -0,0 +1,5 @@
|
|||
def foo() -> field:
|
||||
return 1
|
||||
|
||||
def main() -> field:
|
||||
return foo::<42>()
|
|
@ -134,6 +134,7 @@ impl fmt::Display for ErrorInner {
|
|||
#[derive(Debug)]
|
||||
struct FunctionQuery<'ast, T> {
|
||||
id: Identifier<'ast>,
|
||||
generics_count: Option<usize>,
|
||||
inputs: Vec<Type<'ast, T>>,
|
||||
/// Output types are optional as we try to infer them
|
||||
outputs: Vec<Option<Type<'ast, T>>>,
|
||||
|
@ -141,6 +142,17 @@ struct FunctionQuery<'ast, T> {
|
|||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for FunctionQuery<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(count) = self.generics_count {
|
||||
write!(
|
||||
f,
|
||||
"<{}>",
|
||||
(0..count)
|
||||
.map(|_| String::from("_"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?
|
||||
}
|
||||
|
||||
write!(f, "(")?;
|
||||
for (i, t) in self.inputs.iter().enumerate() {
|
||||
write!(f, "{}", t)?;
|
||||
|
@ -181,11 +193,13 @@ impl<'ast, T: Field> FunctionQuery<'ast, T> {
|
|||
/// Create a new query.
|
||||
fn new(
|
||||
id: Identifier<'ast>,
|
||||
generics: &Option<Vec<Option<UExpression<'ast, T>>>>,
|
||||
inputs: &[Type<'ast, T>],
|
||||
outputs: &[Option<Type<'ast, T>>],
|
||||
) -> Self {
|
||||
FunctionQuery {
|
||||
id,
|
||||
generics_count: generics.as_ref().map(|g| g.len()),
|
||||
inputs: inputs.to_owned(),
|
||||
outputs: outputs.to_owned(),
|
||||
}
|
||||
|
@ -194,6 +208,8 @@ impl<'ast, T: Field> FunctionQuery<'ast, T> {
|
|||
/// match a `FunctionKey` against this `FunctionQuery`
|
||||
fn match_func(&self, func: &DeclarationFunctionKey<'ast>) -> bool {
|
||||
self.id == func.id
|
||||
&& self.generics_count.map(|count| count == func.signature.generics.len()).unwrap_or(true) // we do not look at the values here, this will be checked when inlining anyway
|
||||
&& self.inputs.len() == func.signature.inputs.len()
|
||||
&& self
|
||||
.inputs
|
||||
.iter()
|
||||
|
@ -1340,7 +1356,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
let arguments_types: Vec<_> =
|
||||
arguments_checked.iter().map(|a| a.get_type()).collect();
|
||||
|
||||
let query = FunctionQuery::new(&fun_id, &arguments_types, &assignee_types);
|
||||
let query = FunctionQuery::new(&fun_id, &generics_checked, &arguments_types, &assignee_types);
|
||||
|
||||
let functions = self.find_functions(&query);
|
||||
|
||||
|
@ -1883,7 +1899,8 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
|
||||
// outside of multidef, function calls must have a single return value
|
||||
// we use type inference to determine the type of the return, so we don't specify it
|
||||
let query = FunctionQuery::new(&fun_id, &arguments_types, &[None]);
|
||||
let query =
|
||||
FunctionQuery::new(&fun_id, &generics_checked, &arguments_types, &[None]);
|
||||
|
||||
let functions = self.find_functions(&query);
|
||||
|
||||
|
|
|
@ -993,6 +993,8 @@ pub mod signature {
|
|||
// we keep track of the value of constants in a map, as a given constant can only have one value
|
||||
let mut constants = ConcreteGenericsAssignment::default();
|
||||
|
||||
assert_eq!(self.inputs.len(), signature.inputs.len());
|
||||
assert_eq!(self.outputs.len(), signature.outputs.len());
|
||||
assert_eq!(self.generics.len(), values.len());
|
||||
|
||||
let decl_generics = self.generics.iter().map(|g| match g.clone().unwrap() {
|
||||
|
|
Loading…
Reference in a new issue