fix: correct type bindings when invoking closure in comptime interpreter
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 fmton default settings.