noir icon indicating copy to clipboard operation
noir copied to clipboard

fix: correct type bindings when invoking closure in comptime interpreter

Open asterite opened this issue 5 months ago • 0 comments

Description

Problem

Resolves #10613

Summary

This was one trickier than I thought.

This code used to error:

fn main() {
    comptime {
        let _ = foo(1_u8);
    }
}

fn foo<T: Eq>(x: T) -> bool {
    bar(x, |x| {
        x == x // Error: No matching impl found for `T: Eq`
    })
}

fn bar<U>(x: U, f: fn(U) -> bool) -> bool {
    f(x)
}

When debugging the bindings, some named parameter T was bound at u8 but was eventually unbound before interpreting that line.

The way things work, when a function is called we unbind the previous function's bindings and bing the current ones.

The problem was that when the closure is interpreted, we need the bindings that are in scope for "foo". However, the old code used the ones in "bar" (forgetting the ones from "foo" when "bar" was called).

The solution here is to remember the bindings at the closure creation location. Then when the closure is invoked we apply those bindings (previously forgetting the old ones).

Additional Context

At first I implemented this by remembering the depth at which a closure was created, then looking up the bindings in self.bound_generics at that depth. However, this doesn't work if a closure is returned from a function and later invoked on, as the bindings will no longer be there in self.bound_generics.

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.

asterite avatar Nov 27 '25 19:11 asterite