[ty] Don't add incorrect subdiagnostic for unresolved reference (#18487)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
Matthew Mckee 2025-06-27 13:40:33 +01:00 committed by GitHub
parent 57bd7d055d
commit a3c79d8170
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 422 additions and 73 deletions

View file

@ -946,9 +946,9 @@ def _(flag1: bool, flag2: bool):
<!-- snapshot-diagnostics -->
If a non-declared variable is used and an attribute with the same name is defined and accessible,
then we emit a subdiagnostic suggesting the use of `self.`.
(`An attribute with the same name as 'x' is defined, consider using 'self.x'` in these cases)
If an undefined variable is used in a method, and an attribute with the same name is defined and
accessible, then we emit a subdiagnostic suggesting the use of `self.`. (These don't appear inline
here; see the diagnostic snapshots.)
```py
class Foo:
@ -978,6 +978,107 @@ class Foo:
y = x
```
In a staticmethod, we don't suggest that it might be an attribute.
```py
class Foo:
def __init__(self):
self.x = 42
@staticmethod
def static_method():
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
In a classmethod, if the name matches a class attribute, we suggest `cls.`.
```py
from typing import ClassVar
class Foo:
x: ClassVar[int] = 42
@classmethod
def class_method(cls):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
In a classmethod, if the name matches an instance-only attribute, we don't suggest anything.
```py
class Foo:
def __init__(self):
self.x = 42
@classmethod
def class_method(cls):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
We also don't suggest anything if the method is (invalidly) decorated with both `@classmethod` and
`@staticmethod`:
```py
class Foo:
x: ClassVar[int]
@classmethod
@staticmethod
def class_method(cls):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
In an instance method that uses some other parameter name in place of `self`, we use that parameter
name in the sub-diagnostic.
```py
class Foo:
def __init__(self):
self.x = 42
def method(other):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
In a classmethod that uses some other parameter name in place of `cls`, we use that parameter name
in the sub-diagnostic.
```py
from typing import ClassVar
class Foo:
x: ClassVar[int] = 42
@classmethod
def class_method(c_other):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
We don't suggest anything if an instance method or a classmethod only has variadic arguments, or if
the first parameter is keyword-only:
```py
from typing import ClassVar
class Foo:
x: ClassVar[int] = 42
def instance_method(*args, **kwargs):
# error: [unresolved-reference] "Name `x` used when not defined"
print(x)
@classmethod
def class_method(*, cls):
# error: [unresolved-reference] "Name `x` used when not defined"
y = x
```
## Unions of attributes
If the (meta)class is a union type or if the attribute on the (meta) class has a union type, we