Skip to content

Conversation

@guipublic
Copy link
Contributor

Description

Problem

Resolves #10385

Summary

Use the lambda runtime context for the 'constrain-ness'.
Also fix in case of nested lambdas by checking for any unconstrained lambda.

Additional Context

User Documentation

Check one:

  • No user documentation needed.
  • Changes in docs/ included in this PR.
  • [For Experimental Features] Changes in docs/ to be submitted in a separate PR.

PR Checklist

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Test Suite Duration'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: cdbf64c Previous: b8d4eea Ratio
test_report_zkpassport_noir-ecdsa_ 2 s 1 s 2
test_report_zkpassport_noir_rsa_ 2 s 1 s 2

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Execution Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 7443722 Previous: e48a0d8 Ratio
rollup-block-root-single-tx 0.003 s 0.002 s 1.50
rollup-root 0.005 s 0.004 s 1.25

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench


// Check if we're in a comptime context (and not in a lambda that will run at runtime).
// Lambdas in global initializers are elaborated in comptime context but execute at runtime.
if self.in_comptime_context() && self.lambda_stack.is_empty() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about when we have a lambda stack is not empty? It looks like this valid code will error now:

unconstrained fn bar() {}

fn main() {
    comptime {
        let _ = || bar();
    }
}

Could we add a test case for this under the runtime unit tests as well.

It looks like we will need to track whether we are resolving a global more explicitly.

Copy link
Contributor

@vezenovm vezenovm Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not investigated whether this is the exact cause but it looks like we are getting a lot more constrained/unconstrained boundary errors https://github.com/noir-lang/noir/actions/runs/21208049227/job/61009656909?pr=11280. The crux of the problem just looks to be that there are comptime contexts aside globals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it could be because of this.
Your example fails because it ask for unsafe { bar()}, but then it works with it.
I think it is fine to require it, although in this specific case it is not useful. The compiler is currently not smart enough to see when unsafe can be avoided.
However, it seems that a lot Aztec code will need to be updated...

fn in_constrained_function(&self) -> bool {
if self.in_comptime_context() {
// Check if any lambda in the nesting chain is unconstrained.
let in_unconstrained_lambda = self.lambda_stack.iter().any(|ctx| ctx.unconstrained);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not enough to just look at the last member of the lambda stack? Would be nice to have a unit test that displays a failure when that check is not enough.

#[test]
fn cannot_call_unconstrained_function_in_lambda_in_global() {
let src = r#"
pub global foo: fn() = || bar();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am now unsure whether we need to prevent this type of code in the first place.

This code is equivalent to the following (which passes w/o errors):

unconstrained fn bar() {}
comptime fn baz() {
    bar()
}
pub global foo_global: fn() = || baz();
fn main() {
    comptime {
        let _ = baz();
    }
}

Yet in the snippet above we do not need any unsafe blocks as baz acts as a comptime fn wrapper around bar. It makes sense that the call to bar would not need an unsafe block as we only check from constrained -> unconstrained calls in our type checking (in fact the error message looks like it could be updated). comptime should not need unsafe blocks to called unconstrained functions and as globals are evaluated in comptime that should apply to them as well.

@asterite I see you came to a similar conclusion as well #10385 (comment).

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Brillig Execution Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: cdbf64c Previous: b8d4eea Ratio
rollup-tx-merge 0.002 s 0.001 s 2

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Compilation Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: cdbf64c Previous: b8d4eea Ratio
rollup-tx-base-private 25.86 s 19.2 s 1.35

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unconstrained function can be called without unsafe in a global function

3 participants