From 93be3237509877e71c4e207f9ca4b8c7d483febb Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 19 May 2025 13:47:41 -0400 Subject: [PATCH 1/2] add tests --- .../resources/mdtest/generics/legacy/classes.md | 9 ++++++++- .../resources/mdtest/generics/pep695/classes.md | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md index 186139e1c37f2b..13bfaec5f8441a 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md @@ -354,11 +354,14 @@ class C(Generic[T]): @overload def __init__(self: "C[bytes]", x: bytes) -> None: ... @overload + def __init__(self: "C[int]", x: bytes) -> None: ... + @overload def __init__(self, x: int) -> None: ... def __init__(self, x: str | bytes | int) -> None: ... reveal_type(C("string")) # revealed: C[str] -reveal_type(C(b"bytes")) # revealed: C[bytes] +# TODO: revealed: C[bytes] +reveal_type(C(b"bytes")) # revealed: C[bytes | int] reveal_type(C(12)) # revealed: C[Unknown] C[str]("string") @@ -369,6 +372,10 @@ C[bytes]("string") # error: [no-matching-overload] C[bytes](b"bytes") C[bytes](12) +C[int]("string") # error: [no-matching-overload] +C[int](b"bytes") +C[int](12) + C[None]("string") # error: [no-matching-overload] C[None](b"bytes") # error: [no-matching-overload] C[None](12) diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md index 9d4c0a429d93c2..8fb50312f44484 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md @@ -290,11 +290,14 @@ class C[T]: @overload def __init__(self: C[bytes], x: bytes) -> None: ... @overload + def __init__(self: C[int], x: bytes) -> None: ... + @overload def __init__(self, x: int) -> None: ... def __init__(self, x: str | bytes | int) -> None: ... reveal_type(C("string")) # revealed: C[str] -reveal_type(C(b"bytes")) # revealed: C[bytes] +# TODO: revealed: C[bytes] +reveal_type(C(b"bytes")) # revealed: C[bytes | int] reveal_type(C(12)) # revealed: C[Unknown] C[str]("string") @@ -305,6 +308,10 @@ C[bytes]("string") # error: [no-matching-overload] C[bytes](b"bytes") C[bytes](12) +C[int]("string") # error: [no-matching-overload] +C[int](b"bytes") +C[int](12) + C[None]("string") # error: [no-matching-overload] C[None](b"bytes") # error: [no-matching-overload] C[None](12) From b6750d91561715d2abbfa4451c11c141db14590a Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 19 May 2025 13:49:35 -0400 Subject: [PATCH 2/2] Only use first matching constructor --- .../mdtest/generics/legacy/classes.md | 3 +-- .../mdtest/generics/pep695/classes.md | 3 +-- crates/ty_python_semantic/src/types.rs | 23 +++++++------------ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md index 13bfaec5f8441a..88718bd914cdc8 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md @@ -360,8 +360,7 @@ class C(Generic[T]): def __init__(self, x: str | bytes | int) -> None: ... reveal_type(C("string")) # revealed: C[str] -# TODO: revealed: C[bytes] -reveal_type(C(b"bytes")) # revealed: C[bytes | int] +reveal_type(C(b"bytes")) # revealed: C[bytes] reveal_type(C(12)) # revealed: C[Unknown] C[str]("string") diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md index 8fb50312f44484..2bf153b9699101 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md @@ -296,8 +296,7 @@ class C[T]: def __init__(self, x: str | bytes | int) -> None: ... reveal_type(C("string")) # revealed: C[str] -# TODO: revealed: C[bytes] -reveal_type(C(b"bytes")) # revealed: C[bytes | int] +reveal_type(C(b"bytes")) # revealed: C[bytes] reveal_type(C(12)) # revealed: C[Unknown] C[str]("string") diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index ede72034753bd5..2e65524a941173 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -4649,24 +4649,14 @@ impl<'db> Type<'db> { } } - fn combine_binding_specialization<'db>( - db: &'db dyn Db, - binding: &CallableBinding<'db>, - ) -> Option> { - binding - .matching_overloads() - .map(|(_, binding)| binding.inherited_specialization()) - .reduce(|acc, specialization| { - combine_specializations(db, acc, specialization) - }) - .flatten() - } - let new_specialization = new_call_outcome .and_then(Result::ok) .as_ref() .and_then(Bindings::single_element) - .and_then(|binding| combine_binding_specialization(db, binding)) + .into_iter() + .flat_map(CallableBinding::matching_overloads) + .next() + .and_then(|(_, binding)| binding.inherited_specialization()) .filter(|specialization| { Some(specialization.generic_context(db)) == generic_context }); @@ -4674,7 +4664,10 @@ impl<'db> Type<'db> { .and_then(Result::ok) .as_ref() .and_then(Bindings::single_element) - .and_then(|binding| combine_binding_specialization(db, binding)) + .into_iter() + .flat_map(CallableBinding::matching_overloads) + .next() + .and_then(|(_, binding)| binding.inherited_specialization()) .filter(|specialization| { Some(specialization.generic_context(db)) == generic_context });