-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Retry parameter matching for argument type expansion #20153
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
Conversation
eb554de to
29832ec
Compare
Diagnostic diff on typing conformance testsNo changes detected when running ty on typing conformance tests ✅ |
|
52e6a51 to
648f6fa
Compare
|
(This isn't completely ready but I'd appreciate some initial feedback on the approach.) |
| // If the argument corresponding to this type is variadic, we need to | ||
| // update the tuple length because expanding could change the length. | ||
| // For example, in `tuple[int] | tuple[int, int]`, the length of the | ||
| // first type is 1, while the length of the second type is 2. | ||
| if let Some(expanded_type) = new_expanded_types[index] { | ||
| let length = expanded_type | ||
| .try_iterate(db) | ||
| .map(|tuple| tuple.len()) | ||
| .unwrap_or(TupleLength::unknown()); | ||
| new_arguments[index] = Argument::Variadic(length); |
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.
👍 Yep this looks like a good approach! It should pull out the more precise length of each union element during expansion
| #[derive(Default)] | ||
| struct ArgumentForms { |
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.
I like the cleanup from introducing this new type, too
| // The spec mentions that each expanded argument list should re-evaluate from step | ||
| // 2 which is the type checking step but we're re-evaluating from step 1. The tldr | ||
| // is that it allows ty to match the correct overload in case a variadic argument | ||
| // would expand into different number of arguments with each expansion. Refer to | ||
| // https://github.com/astral-sh/ty/issues/735 for more details. | ||
| for overload in &mut self.overloads { | ||
| // Clear the state of all overloads before re-evaluating from step 1 | ||
| overload.reset(); | ||
| overload.match_parameters(db, expanded_arguments, &mut argument_forms); | ||
| } |
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.
💯
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.
I don't know if we need to reflect this in our comments, but I think the spec is not wrong here -- the difference is that in the spec "step 1" means only "eliminate impossible overloads due to arity mismatch" whereas our step 1 is bigger than that, it also includes "match arguments to parameters", which in the spec is implicitly part of step 2, not part of step 1. This is why we need to "repeat step 1" and the spec does not. It may be clearer to say that we don't separate step 1 and 2 in the same way the spec does.
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.
That's a good point, I didn't realize this subtle difference, I'll update the comment to reflect this.
I'm not exactly sure what's wrong here. I've created a playground snippet which breaks the union into it's elements which is what the type expansion would retry with (https://play.ty.dev/1990e010-195f-4800-9e31-b77894e37dd3). It's only the |
63fe1a7 to
4184ce9
Compare
|
@dcreager I'm assuming this is in your review queue unless you request review from me. |
dcreager
left a comment
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.
This is great, thank you for tackling this!
| let argument_types = match argument_types.as_ref() { | ||
| Tuple::Fixed(_) => { | ||
| Cow::Owned(argument_types.concat(self.db, &Tuple::homogeneous(Type::unknown()))) | ||
| } | ||
| Tuple::Variable(_) => argument_types, | ||
| }; | ||
|
|
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.
❤️ Love that we can get rid of this workaround!
Summary
This PR addresses an issue for a variadic argument when involved in argument type expansion of overload call evaluation.
The issue is that the expansion of the variadic argument could result in argument list of different arity. For example, in
*args: tuple[int] | tuple[int, str], the expansion would lead to the variadic argument being unpacked into 1 and 2 element respectively. This means that the parameter matching that was performed initially isn't sufficient and each expanded argument list would need to redo the parameter matching again.This is currently done by redoing the parameter matching directly, maintaining the state of argument forms (and the conflicting forms), and updating the
Bindingsvalues if it changes.Closes: astral-sh/ty#735
Test Plan
Update existing mdtest.