Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7b7e2bc
Function values are now pairs of (constrained, unconstrained)
jfecher Aug 13, 2025
e459dc4
Fix some typos that resulted in bugs
jfecher Aug 14, 2025
b16b052
Update snapshots
jfecher Aug 14, 2025
d97f64c
Merge branch 'master' into jf/double-lambdas
Aug 15, 2025
f2fc8ef
Experimental: ignore runtime pairs in monomorphized printer
jfecher Aug 15, 2025
dda4aa1
Merge branch 'jf/double-lambdas' of https://github.com/noir-lang/noir…
jfecher Aug 15, 2025
132ba09
Merge branch 'master' into jf/double-lambdas
jfecher Aug 15, 2025
c909ad3
Revert "Experimental: ignore runtime pairs in monomorphized printer"
jfecher Aug 15, 2025
9ede1a0
Add 'avoid_lambdas' to ast_fuzzer args
jfecher Aug 15, 2025
043c9c9
Clippy
jfecher Aug 15, 2025
16795c4
Update frontend test, format
jfecher Aug 18, 2025
3bd2fd5
Snaps
jfecher Aug 18, 2025
564b65f
Format
jfecher Aug 18, 2025
4bd7067
Function is now a tuple type
jfecher Aug 18, 2025
b62f7a7
Merge branch 'master' into jf/double-lambdas
Aug 19, 2025
cd576a1
Merge branch 'master' into jf/double-lambdas
jfecher Aug 20, 2025
4058ff9
Merge branch 'jf/double-lambdas' of https://github.com/noir-lang/noir…
jfecher Aug 20, 2025
be88050
Extend time for parity lib
jfecher Aug 20, 2025
ae7431d
Update compiler/noirc_frontend/src/monomorphization/printer.rs
jfecher Aug 20, 2025
b26ec72
Update compiler/noirc_frontend/src/monomorphization/mod.rs
jfecher Aug 20, 2025
a2b30ac
constrainedness
jfecher Aug 20, 2025
c7a7428
Merge branch 'jf/double-lambdas' of https://github.com/noir-lang/noir…
jfecher Aug 20, 2025
348ab59
Snap conflicts
jfecher Aug 22, 2025
f21f687
I just fixed these
jfecher Aug 22, 2025
adf99d9
Merge branch 'master' into jf/double-lambdas
jfecher Aug 26, 2025
a3d6a6b
Merge branch 'master' of https://github.com/noir-lang/noir into jf/do…
jfecher Aug 26, 2025
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
2 changes: 1 addition & 1 deletion EXTERNAL_NOIR_LIBRARIES.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ libraries:
repo: AztecProtocol/aztec-packages
ref: *AZ_COMMIT
path: noir-projects/noir-protocol-circuits/crates/parity-lib
timeout: 4
timeout: 7
critical: false
protocol_circuits_private_kernel_lib:
repo: AztecProtocol/aztec-packages
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2652,7 +2652,7 @@ pub mod test_utils {
};

let mut monomorphizer =
Monomorphizer::new(elaborator.interner, DebugTypeTracker::default());
Monomorphizer::new(elaborator.interner, DebugTypeTracker::default(), false);
Ok(monomorphizer.expr(expr_id).expect("monomorphization error while converting interpreter execution result, should not be possible"))
}
}
269 changes: 206 additions & 63 deletions compiler/noirc_frontend/src/monomorphization/mod.rs

Large diffs are not rendered by default.

58 changes: 39 additions & 19 deletions compiler/noirc_frontend/src/monomorphization/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct FunctionPrintOptions {
}

/// Some calls can be printed with the intention of parsing the code.
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
enum SpecialCall {
Print,
Object(String),
Expand Down Expand Up @@ -499,29 +499,49 @@ impl AstPrinter {
write!(f, ")")
}

fn get_called_function(expr: &Expression) -> Option<(bool, &Definition, &String)> {
let is_unconstrained = |typ: &Type| match typ {
Type::Function(_, _, _, unconstrained) => *unconstrained,
Type::Tuple(elements) => match elements.first() {
Some(Type::Function(_, _, _, unconstrained)) => *unconstrained,
_ => false,
},
_ => false,
};

match expr {
Expression::Ident(Ident { typ, definition, name, .. }) => {
Some((is_unconstrained(typ), definition, name))
}
Expression::Tuple(elements) => match elements.first() {
Some(Expression::Ident(Ident { typ, definition, name, .. })) => {
Some((is_unconstrained(typ), definition, name))
}
_ => None,
},
_ => None,
}
}

fn print_call(
&mut self,
call: &super::ast::Call,
f: &mut Formatter,
) -> Result<(), std::fmt::Error> {
let (print_unsafe, special) = match call.func.as_ref() {
Expression::Ident(Ident {
typ: Type::Function(_, _, _, unconstrained),
definition,
name,
..
}) => {
let is_unsafe = *unconstrained && !self.in_unconstrained;
let special = match definition {
Definition::Oracle(s) if s == "print" => Some(SpecialCall::Print),
Definition::Builtin(s) if s.starts_with("array") || s.starts_with("slice") => {
Some(SpecialCall::Object(name.clone()))
}
_ => None,
};
(is_unsafe, special)
}
_ => (false, None),
let (print_unsafe, special) = if let Some((unconstrained, definition, name)) =
Self::get_called_function(&call.func)
{
let is_unsafe = unconstrained && !self.in_unconstrained;
let special = match definition {
Definition::Oracle(s) if s == "print" => Some(SpecialCall::Print),
Definition::Builtin(s) if s.starts_with("array") || s.starts_with("slice") => {
Some(SpecialCall::Object(name.clone()))
}
_ => None,
};
(is_unsafe, special)
} else {
(false, None)
};

if let Some(special) = special {
Expand Down
17 changes: 13 additions & 4 deletions compiler/noirc_frontend/src/monomorphization/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,29 @@ fn simple_closure_with_no_captured_variables() {
insta::assert_snapshot!(program, @r"
fn main$f0(y$l0: call_data(0) Field) -> pub Field {
let x$l1 = 1;
let closure$l4 = {
let closure$l6 = ({
let closure_variable$l3 = {
let env$l2 = (x$l1);
(env$l2, lambda$f1)
};
closure_variable$l3
};
}, {
let closure_variable$l5 = {
let env$l4 = (x$l1);
(env$l4, lambda$f2)
};
closure_variable$l5
});
{
let tmp$l5 = closure$l4;
tmp$l5.1(tmp$l5.0)
let tmp$l7 = closure$l6.0;
tmp$l7.1(tmp$l7.0)
}
}
fn lambda$f1(mut env$l2: (Field,)) -> Field {
env$l2.0
}
unconstrained fn lambda$f2(mut env$l4: (Field,)) -> Field {
env$l4.0
}
");
}
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"comptime",
"concat",
"cond",
"constrainedness",
"cpus",
"cranelift",
"critesjosh",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "dual_constrained_lambdas"
type = "bin"
authors = [""]

[dependencies]
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
fn main() {
foo(|| std::runtime::is_unconstrained());
}

// #7289 originates from a lambda being used in both acir & brillig
fn foo(is_brillig: fn() -> bool) {
// If this is true the `--force-brillig` flag was passed
let force_brillig = std::runtime::is_unconstrained();

assert(!acir_function(is_brillig) | force_brillig);

// safety:
unsafe {
assert(brillig_function(is_brillig));
assert(brillig_function2(is_brillig));
};
}

fn acir_function(f: fn() -> bool) -> bool {
f()
}

unconstrained fn brillig_function(f: fn() -> bool) -> bool {
f()
}

// acir_function should become unconstrained when called in
// an unconstrained context - and this should apply to the lambda
// it takes as an argument as well.
unconstrained fn brillig_function2(f: fn() -> bool) -> bool {
acir_function(f)
}
5 changes: 5 additions & 0 deletions tooling/ast_fuzzer/tests/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ fn arb_ast_roundtrip() {
// and also rationalizes removes branches that can never be matched,
// (like repeated patterns, superfluous defaults). For now ignore these.
avoid_match: true,
// Since #9484 the monomorphizer represents function values as a pair of
// `(constrained, unconstrained)` where each element is a different runtime of the same
// function. The fuzzer has not yet been updated to mimic this so first-class functions
// are avoided for now.
avoid_lambdas: true,
// The formatting of `unsafe { ` becomes `{ unsafe {` with extra line breaks.
// Let's stick to just Brillig so there is no need for `unsafe` at all.
force_brillig: true,
Expand Down
3 changes: 2 additions & 1 deletion tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,8 @@ fn generate_interpret_execution_success_tests(test_file: &mut File, test_data_di
}

/// Run integration tests with the `--minimal-ssa` option and check that the return
/// value matches the expectations.
/// value matches the expectations. This also enables `--force-brillig` since `--minimal-ssa`
/// is only valid when all functions are unconstrained.
fn generate_minimal_execution_success_tests(test_file: &mut File, test_data_dir: &Path) {
let test_type = "execution_success";
let test_cases = read_test_cases(test_data_dir, test_type);
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading