mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 21:34:57 +00:00
[ty] Do not consider a type T
to satisfy a method member on a protocol unless the method is available on the meta-type of T
(#19187)
This commit is contained in:
parent
b124e182ca
commit
f722bfa9e6
5 changed files with 132 additions and 19 deletions
|
@ -68,7 +68,7 @@ macro_rules! type_property_test {
|
|||
|
||||
mod stable {
|
||||
use super::union;
|
||||
use crate::types::{CallableType, Type};
|
||||
use crate::types::{CallableType, KnownClass, Type};
|
||||
|
||||
// Reflexivity: `T` is equivalent to itself.
|
||||
type_property_test!(
|
||||
|
@ -205,6 +205,16 @@ mod stable {
|
|||
all_fully_static_type_pairs_are_subtype_of_their_union, db,
|
||||
forall fully_static_types s, t. s.is_subtype_of(db, union(db, [s, t])) && t.is_subtype_of(db, union(db, [s, t]))
|
||||
);
|
||||
|
||||
// Any type assignable to `Iterable[object]` should be considered iterable.
|
||||
//
|
||||
// Note that the inverse is not true, due to the fact that we recognize the old-style
|
||||
// iteration protocol as well as the new-style iteration protocol: not all objects that
|
||||
// we consider iterable are assignable to `Iterable[object]`.
|
||||
type_property_test!(
|
||||
all_type_assignable_to_iterable_are_iterable, db,
|
||||
forall types t. t.is_assignable_to(db, KnownClass::Iterable.to_specialized_instance(db, [Type::object(db)])) => t.try_iterate(db).is_ok()
|
||||
);
|
||||
}
|
||||
|
||||
/// This module contains property tests that currently lead to many false positives.
|
||||
|
@ -218,7 +228,6 @@ mod flaky {
|
|||
use itertools::Itertools;
|
||||
|
||||
use super::{intersection, union};
|
||||
use crate::types::{KnownClass, Type};
|
||||
|
||||
// Negating `T` twice is equivalent to `T`.
|
||||
type_property_test!(
|
||||
|
@ -312,14 +321,4 @@ mod flaky {
|
|||
bottom_materialization_of_type_is_assigneble_to_type, db,
|
||||
forall types t. t.bottom_materialization(db).is_assignable_to(db, t)
|
||||
);
|
||||
|
||||
// Any type assignable to `Iterable[object]` should be considered iterable.
|
||||
//
|
||||
// Note that the inverse is not true, due to the fact that we recognize the old-style
|
||||
// iteration protocol as well as the new-style iteration protocol: not all objects that
|
||||
// we consider iterable are assignable to `Iterable[object]`.
|
||||
type_property_test!(
|
||||
all_type_assignable_to_iterable_are_iterable, db,
|
||||
forall types t. t.is_assignable_to(db, KnownClass::Iterable.to_specialized_instance(db, [Type::object(db)])) => t.try_iterate(db).is_ok()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -383,15 +383,23 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
|
|||
other: Type<'db>,
|
||||
relation: TypeRelation,
|
||||
) -> bool {
|
||||
let Place::Type(attribute_type, Boundness::Bound) = other.member(db, self.name).place
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match &self.kind {
|
||||
// TODO: consider the types of the attribute on `other` for property/method members
|
||||
ProtocolMemberKind::Method(_) | ProtocolMemberKind::Property(_) => true,
|
||||
// TODO: consider the types of the attribute on `other` for method members
|
||||
ProtocolMemberKind::Method(_) => matches!(
|
||||
other.to_meta_type(db).member(db, self.name).place,
|
||||
Place::Type(_, Boundness::Bound)
|
||||
),
|
||||
// TODO: consider the types of the attribute on `other` for property members
|
||||
ProtocolMemberKind::Property(_) => matches!(
|
||||
other.member(db, self.name).place,
|
||||
Place::Type(_, Boundness::Bound)
|
||||
),
|
||||
ProtocolMemberKind::Other(member_type) => {
|
||||
let Place::Type(attribute_type, Boundness::Bound) =
|
||||
other.member(db, self.name).place
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
member_type.has_relation_to(db, attribute_type, relation)
|
||||
&& attribute_type.has_relation_to(db, *member_type, relation)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue