Skip to content

Commit d2a238d

Browse files
authored
[red-knot] Update call binding to return all matching overloads (#17618)
## Summary This PR updates the existing overload matching methods to return an iterator of all the matched overloads instead. This would be useful once the overload call evaluation algorithm is implemented which should provide an accurate picture of all the matched overloads. The return type would then be picked from either the only matched overload or the first overload from the ones that are matched. In an earlier version of this PR, it tried to check if using an intersection of return types from the matched overload would help reduce the false positives but that's not enough. [This comment](#17618 (comment)) keep the ecosystem analysis for that change for prosperity. > [!NOTE] > > The best way to review this PR is by hiding the whitespace changes because there are two instances where a large match expression is indented to be inside a loop over matching overlods > > <img width="1207" alt="Screenshot 2025-04-28 at 15 12 16" src="https://github.com/user-attachments/assets/e06cbfa4-04fa-435f-84ef-4e5c3c5626d1" /> ## Test Plan Make sure existing test cases are unaffected and no ecosystem changes.
1 parent 6e765b4 commit d2a238d

File tree

3 files changed

+813
-768
lines changed

3 files changed

+813
-768
lines changed

crates/red_knot_python_semantic/src/types.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4527,27 +4527,43 @@ impl<'db> Type<'db> {
45274527
new_call_outcome @ (None | Some(Ok(_))),
45284528
init_call_outcome @ (None | Some(Ok(_))),
45294529
) => {
4530+
fn combine_specializations<'db>(
4531+
db: &'db dyn Db,
4532+
s1: Option<Specialization<'db>>,
4533+
s2: Option<Specialization<'db>>,
4534+
) -> Option<Specialization<'db>> {
4535+
match (s1, s2) {
4536+
(None, None) => None,
4537+
(Some(s), None) | (None, Some(s)) => Some(s),
4538+
(Some(s1), Some(s2)) => Some(s1.combine(db, s2)),
4539+
}
4540+
}
4541+
4542+
fn combine_binding_specialization<'db>(
4543+
db: &'db dyn Db,
4544+
binding: &CallableBinding<'db>,
4545+
) -> Option<Specialization<'db>> {
4546+
binding
4547+
.matching_overloads()
4548+
.map(|(_, binding)| binding.inherited_specialization())
4549+
.reduce(|acc, specialization| {
4550+
combine_specializations(db, acc, specialization)
4551+
})
4552+
.flatten()
4553+
}
4554+
45304555
let new_specialization = new_call_outcome
45314556
.and_then(Result::ok)
45324557
.as_ref()
45334558
.and_then(Bindings::single_element)
4534-
.and_then(CallableBinding::matching_overload)
4535-
.and_then(|(_, binding)| binding.inherited_specialization());
4559+
.and_then(|binding| combine_binding_specialization(db, binding));
45364560
let init_specialization = init_call_outcome
45374561
.and_then(Result::ok)
45384562
.as_ref()
45394563
.and_then(Bindings::single_element)
4540-
.and_then(CallableBinding::matching_overload)
4541-
.and_then(|(_, binding)| binding.inherited_specialization());
4542-
let specialization = match (new_specialization, init_specialization) {
4543-
(None, None) => None,
4544-
(Some(specialization), None) | (None, Some(specialization)) => {
4545-
Some(specialization)
4546-
}
4547-
(Some(new_specialization), Some(init_specialization)) => {
4548-
Some(new_specialization.combine(db, init_specialization))
4549-
}
4550-
};
4564+
.and_then(|binding| combine_binding_specialization(db, binding));
4565+
let specialization =
4566+
combine_specializations(db, new_specialization, init_specialization);
45514567
let specialized = specialization
45524568
.map(|specialization| {
45534569
Type::instance(

0 commit comments

Comments
 (0)