-
Notifications
You must be signed in to change notification settings - Fork 370
fix: unify macro call type with actual type in comptime blocks #11411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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: 630f649 | Previous: fa8934d | Ratio |
|---|---|---|---|
test_report_zkpassport_noir-ecdsa_ |
3 s |
1 s |
3 |
This comment was automatically generated by workflow using github-action-benchmark.
CC: @TomAFrench
| if self.in_comptime_context() { | ||
| return; | ||
| } | ||
|
|
||
| let var = RequiredTypeVariable { type_variable_id, typ, kind, location }; | ||
| self.get_function_context_mut().required_type_variables.push(var); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if self.in_comptime_context() { | |
| return; | |
| } | |
| let var = RequiredTypeVariable { type_variable_id, typ, kind, location }; | |
| self.get_function_context_mut().required_type_variables.push(var); | |
| if !self.in_comptime_context() { | |
| let var = RequiredTypeVariable { type_variable_id, typ, kind, location }; | |
| self.get_function_context_mut().required_type_variables.push(var); | |
| } |
| /// The reason is that in a comptime context the type of a variable might change | ||
| /// across a loop's iterations, so a type can temporarily remain as `Type<_>` where | ||
| /// `_` is bound by the interpreter evaluating an expression's type being unified with | ||
| /// that type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this open us up to regular unbound type variables though? E.g. the case this was meant to originally catch may no longer be caught in comptime code?
| // Undo any bindings (if any) from the last time we unified this expression's | ||
| // type against the actual type | ||
| if let Some(bindings) = | ||
| self.elaborator.interner.macro_call_expression_bindings.remove(&id) | ||
| { | ||
| for (var, kind, _typ) in bindings.values() { | ||
| var.unbind(var.id(), kind.clone()); | ||
| } | ||
| } | ||
|
|
||
| let mut bindings = TypeBindings::default(); | ||
| match actual_type.try_unify(&expected_type, &mut bindings) { | ||
| Ok(()) => { | ||
| // Store the bindings so we can undo them next time | ||
| self.elaborator | ||
| .interner | ||
| .macro_call_expression_bindings | ||
| .insert(id, bindings.clone()); | ||
| Type::apply_type_bindings(bindings); | ||
| } | ||
| Err(UnificationError) => { | ||
| let error = TypeCheckError::TypeMismatch { | ||
| expected_typ: expected_type.to_string(), | ||
| expr_typ: actual_type.to_string(), | ||
| expr_location: location, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you factor out all or some of this code? It makes elaborate_call longer and more difficult to understand by getting very involved in a corner case.
Description
Problem
Resolves #11409
Summary
This is a follow-up to #6105
#6105 is good but because we don't unify types, some type variables end up unbound. That's why #11409 was failing.
The solution here is:
This allows a variable to change types across macro loop iterations.
For this I also had to relax the checking of unbound generics when a function context is popped, only in comptime code. The reason is that in the new test here, in
foo.len()we end up withfoowithout a knownN, but it's fine because it's thatNthat we want to infer later on. In this case, ifNends up being used when interpreting the block and it's not bound, we'll get an error anyway.Additional Context
User Documentation
Check one:
PR Checklist
cargo fmton default settings.