From ebf7d0cd2f3248e0601492a35d8907d0a4f9f5fb Mon Sep 17 00:00:00 2001 From: Matthew Mckee Date: Sat, 17 Jan 2026 12:41:37 +0000 Subject: [PATCH] [ty] Don't add a subdiagnostic pointing to the TypeVar definition if the TypeVar is `Self` (#22646) --- .../mdtest/diagnostics/union_call.md | 22 +++++ ..._Attribute_access_on_…_(7bdb97302c27c412).snap | 88 +++++++++++++++++++ .../ty_python_semantic/src/types/call/bind.rs | 4 +- 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_f…_-_Try_to_cover_all_pos…_-_Attribute_access_on_…_(7bdb97302c27c412).snap diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md index a5e9b9370e..92423187a7 100644 --- a/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md @@ -162,3 +162,25 @@ def _(n: int): # error: [invalid-argument-type] f1(x) ``` + +### Attribute access on a typevar with multiple bounds + +```py +from typing import TypeVar, Self + +class A: + def foo(self, x: int) -> Self: + return self + +class B: + def foo(self, x: str) -> Self: + return self + +T = TypeVar("T", A, B) + +def _(x: T, y: int) -> T: + # error: [invalid-argument-type] + # error: [invalid-argument-type] + # error: [invalid-argument-type] + return x.foo(y) +``` diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_f…_-_Try_to_cover_all_pos…_-_Attribute_access_on_…_(7bdb97302c27c412).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_f…_-_Try_to_cover_all_pos…_-_Attribute_access_on_…_(7bdb97302c27c412).snap new file mode 100644 index 0000000000..685242ee2e --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_f…_-_Try_to_cover_all_pos…_-_Attribute_access_on_…_(7bdb97302c27c412).snap @@ -0,0 +1,88 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- + +--- +mdtest name: union_call.md - Calling a union of function types - Try to cover all possible reasons - Attribute access on a typevar with multiple bounds +mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +--- + +# Python source files + +## mdtest_snippet.py + +``` + 1 | from typing import TypeVar, Self + 2 | + 3 | class A: + 4 | def foo(self, x: int) -> Self: + 5 | return self + 6 | + 7 | class B: + 8 | def foo(self, x: str) -> Self: + 9 | return self +10 | +11 | T = TypeVar("T", A, B) +12 | +13 | def _(x: T, y: int) -> T: +14 | # error: [invalid-argument-type] +15 | # error: [invalid-argument-type] +16 | # error: [invalid-argument-type] +17 | return x.foo(y) +``` + +# Diagnostics + +``` +error[invalid-argument-type]: Argument to bound method `foo` is incorrect + --> src/mdtest_snippet.py:17:12 + | +15 | # error: [invalid-argument-type] +16 | # error: [invalid-argument-type] +17 | return x.foo(y) + | ^^^^^^^^ Argument type `T@_` does not satisfy upper bound `A` of type variable `Self` + | +info: Union variant `bound method T@_.foo(x: int) -> T@_` is incompatible with this call site +info: Attempted to call union type `(bound method T@_.foo(x: int) -> T@_) | (bound method T@_.foo(x: str) -> T@_)` +info: rule `invalid-argument-type` is enabled by default + +``` + +``` +error[invalid-argument-type]: Argument to bound method `foo` is incorrect + --> src/mdtest_snippet.py:17:12 + | +15 | # error: [invalid-argument-type] +16 | # error: [invalid-argument-type] +17 | return x.foo(y) + | ^^^^^^^^ Argument type `T@_` does not satisfy upper bound `B` of type variable `Self` + | +info: Union variant `bound method T@_.foo(x: str) -> T@_` is incompatible with this call site +info: Attempted to call union type `(bound method T@_.foo(x: int) -> T@_) | (bound method T@_.foo(x: str) -> T@_)` +info: rule `invalid-argument-type` is enabled by default + +``` + +``` +error[invalid-argument-type]: Argument to bound method `foo` is incorrect + --> src/mdtest_snippet.py:17:18 + | +15 | # error: [invalid-argument-type] +16 | # error: [invalid-argument-type] +17 | return x.foo(y) + | ^ Expected `str`, found `int` + | +info: Method defined here + --> src/mdtest_snippet.py:8:9 + | +7 | class B: +8 | def foo(self, x: str) -> Self: + | ^^^ ------ Parameter declared here +9 | return self + | +info: Union variant `bound method T@_.foo(x: str) -> T@_` is incompatible with this call site +info: Attempted to call union type `(bound method T@_.foo(x: int) -> T@_) | (bound method T@_.foo(x: str) -> T@_)` +info: rule `invalid-argument-type` is enabled by default + +``` diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 340b86c8d3..c504004bc5 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -4578,7 +4578,9 @@ impl<'db> BindingError<'db> { } } - if let Some(typevar_definition) = typevar.definition(context.db()) { + if !typevar.is_self(context.db()) + && let Some(typevar_definition) = typevar.definition(context.db()) + { let module = parsed_module(context.db(), typevar_definition.file(context.db())) .load(context.db()); let typevar_range = typevar_definition.full_range(context.db(), &module);