[ty] Use fully qualified names to distinguish ambiguous protocols in diagnostics (#20627)

This commit is contained in:
Alex Waygood 2025-09-29 13:02:07 +01:00 committed by GitHub
parent 803d61e21f
commit 1cf19732b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 2 deletions

View file

@ -170,6 +170,36 @@ class Container(Generic[T]):
## Protocols
### Differing members
`bad.py`:
```py
from typing import Protocol, TypeVar
T_co = TypeVar("T_co", covariant=True)
class Iterator(Protocol[T_co]):
def __nexxt__(self) -> T_co: ...
def bad() -> Iterator[str]:
raise NotImplementedError
```
`main.py`:
```py
from typing import Iterator
def f() -> Iterator[str]:
import bad
# error: [invalid-return-type] "Return type does not match returned value: expected `typing.Iterator[str]`, found `bad.Iterator[str]"
return bad.bad()
```
### Same members but with different types
```py
from typing import Protocol
import proto_a

View file

@ -22,8 +22,8 @@ use crate::types::tuple::TupleSpec;
use crate::types::visitor::TypeVisitor;
use crate::types::{
BoundTypeVarInstance, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
MaterializationKind, Protocol, StringLiteralType, SubclassOfInner, Type, UnionType,
WrapperDescriptorKind, visitor,
MaterializationKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
UnionType, WrapperDescriptorKind, visitor,
};
use ruff_db::parsed::parsed_module;
@ -128,6 +128,13 @@ impl<'db> super::visitor::TypeVisitor<'db> for AmbiguousClassCollector<'db> {
Type::ClassLiteral(class) => self.record_class(db, class),
Type::EnumLiteral(literal) => self.record_class(db, literal.enum_class(db)),
Type::GenericAlias(alias) => self.record_class(db, alias.origin(db)),
// Visit the class (as if it were a nominal-instance type)
// rather than the protocol members, if it is a class-based protocol.
// (For the purposes of displaying the type, we'll use the class name.)
Type::ProtocolInstance(ProtocolInstanceType {
inner: Protocol::FromClass(class),
..
}) => return self.visit_type(db, Type::from(class)),
_ => {}
}