Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 58 additions & 7 deletions compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,11 @@ impl DefunctionalizationContext {
};

// Find the correct apply function
let apply_function = self.get_apply_function(signature, func.runtime());
let Some(apply_function) =
self.get_apply_function(signature, func.runtime())
else {
continue;
};

// Replace the instruction with a call to apply
let apply_function_value_id = func.dfg.import_function(apply_function.id);
Expand All @@ -201,8 +205,12 @@ impl DefunctionalizationContext {
}

/// Returns the apply function for the given signature
fn get_apply_function(&self, signature: Signature, runtime: RuntimeType) -> ApplyFunction {
*self.apply_functions.get(&(signature, runtime)).expect("Could not find apply function")
fn get_apply_function(
&self,
signature: Signature,
runtime: RuntimeType,
) -> Option<ApplyFunction> {
self.apply_functions.get(&(signature, runtime)).copied()
}
}

Expand Down Expand Up @@ -376,10 +384,10 @@ fn find_dynamic_dispatches(func: &Function) -> BTreeSet<Signature> {
fn create_apply_functions(ssa: &mut Ssa, variants_map: Variants) -> ApplyFunctions {
let mut apply_functions = HashMap::default();
for ((mut signature, runtime), variants) in variants_map.into_iter() {
assert!(
!variants.is_empty(),
"ICE: at least one variant should exist for a dynamic call {signature:?}"
);
if variants.is_empty() {
// If no variants exist for a dynamic call we leave removing those dead parameters to DIE
continue;
}
let dispatches_to_multiple_functions = variants.len() > 1;

// Update the shared function signature of the higher-order function variants
Expand Down Expand Up @@ -804,4 +812,47 @@ mod tests {
"
);
}

#[test]
fn missing_fn_variant() {
let src = "
brillig(inline) fn main f0 {
b0():
v2 = call f1(f2) -> i64
return v2
}
brillig(inline) fn func_3 f1 {
b0(v0: function):
return i64 0
}
brillig(inline) fn func_2 f2 {
b0(v0: function):
v2 = call v0(u128 1) -> u1
return v2
}
";

let ssa = Ssa::from_str(src).unwrap();
let ssa = ssa.defunctionalize();

// We still expect all parameters with a function type to be replaced.
// However, this is fine as a function with no variants means that function
// was never actually called.
assert_ssa_snapshot!(ssa, @r"
brillig(inline) fn main f0 {
b0():
v2 = call f1(Field 2) -> i64
return v2
}
brillig(inline) fn func_3 f1 {
b0(v0: Field):
return i64 0
}
brillig(inline) fn func_2 f2 {
b0(v0: Field):
v2 = call v0(u128 1) -> u1
return v2
}
");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "lambda_taking_lambda_regression_8543"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Regression for issue #8543 (https://github.com/noir-lang/noir/issues/8543)
unconstrained fn main() -> pub i64 {
func_3(func_2)
}

unconstrained fn func_2(a: unconstrained fn(u128) -> bool) -> bool {
a(1)
}
unconstrained fn func_3(_b: unconstrained fn(unconstrained fn(u128) -> bool) -> bool) -> i64 {
0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[lambda_taking_lambda_regression_8543] Circuit output: Field(0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "lambda_taking_lambda_with_variant"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This is the same as `lambda_taking_lambda_regression_8543` except that there is
// actually a variant which has been constructed.
unconstrained fn main() -> pub i64 {
func_3(func_2)
}

unconstrained fn func_2(a: unconstrained fn(u128) -> bool) -> bool {
a(1)
}
unconstrained fn func_3(b: unconstrained fn(unconstrained fn(u128) -> bool) -> bool) -> i64 {
let _s = b(func_1);
0
}

unconstrained fn func_1(a: u128) -> bool {
a > 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[lambda_taking_lambda_with_variant] Circuit output: Field(0)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading