1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

Merge pull request #822 from Zokrates/stricter_function_match

Consider input count and generics count in semantic checker
This commit is contained in:
Thibaut Schaeffer 2021-04-19 20:50:38 +02:00 committed by GitHub
commit 0d20f6a107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 2 deletions

View file

@ -0,0 +1 @@
Make function selection stricter in function calls

View file

@ -0,0 +1,5 @@
def foo() -> field:
return 1
def main() -> field:
return foo(42)

View file

@ -0,0 +1,5 @@
def foo() -> field:
return 1
def main() -> field:
return foo::<42>()

View file

@ -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);

View file

@ -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() {