Skip to content

Commit

Permalink
unittest for is_subclass_of improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexWaygood committed Nov 1, 2024
1 parent 21808e2 commit d1ccf88
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 6 deletions.
13 changes: 8 additions & 5 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1844,10 +1844,9 @@ impl<'db> ClassType<'db> {
}

pub fn is_subclass_of(self, db: &'db dyn Db, other: ClassType) -> bool {
// TODO: we need to iterate over the *MRO* here, not the bases
(other == self)
|| self.mro(db).iter().any(|base| match base {
ClassBase::Class(base_class) => *base_class == other,
|| self.mro(db).elements().any(|superclass| match superclass {
ClassBase::Class(superclass) => superclass == other,
// `is_subclass_of` is checking the subtype relation, in which gradual types do not
// participate, so we should not return `True` if we find `Any/Unknown` in the
// bases.
Expand Down Expand Up @@ -1881,10 +1880,10 @@ impl<'db> ClassType<'db> {
}

pub(crate) fn inherited_class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
for superclass in self.mro(db).iter().skip(1) {
for superclass in self.mro(db).elements().skip(1) {
match superclass {
ClassBase::Any | ClassBase::Unknown | ClassBase::Todo => {
return Type::from(*superclass).member(db, name)
return Type::from(superclass).member(db, name)
}
ClassBase::Class(class) => {
let member = class.own_class_member(db, name);
Expand Down Expand Up @@ -2139,6 +2138,10 @@ mod tests {
#[test_case(Ty::Tuple(vec![Ty::IntLiteral(42), Ty::StringLiteral("foo")]), Ty::Tuple(vec![Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str")]))]
#[test_case(Ty::Tuple(vec![Ty::BuiltinInstance("int"), Ty::StringLiteral("foo")]), Ty::Tuple(vec![Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str")]))]
#[test_case(Ty::Tuple(vec![Ty::IntLiteral(42), Ty::BuiltinInstance("str")]), Ty::Tuple(vec![Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str")]))]
#[test_case(
Ty::BuiltinInstance("FloatingPointError"),
Ty::BuiltinInstance("Exception")
)]
fn is_subtype_of(from: Ty, to: Ty) {
let db = setup_db();
assert!(from.into_type(&db).is_subtype_of(&db, to.into_type(&db)));
Expand Down
2 changes: 1 addition & 1 deletion crates/red_knot_python_semantic/src/types/mro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<'db> Mro<'db> {

// All other classes in Python have an MRO with length >=2.
// Even if a class has no explicit base classes,
// it will implicitly inherit from `objet` at runtime;
// it will implicitly inherit from `object` at runtime;
// `object` will appear in the class's `__bases__` list and `__mro__`:
//
// ```pycon
Expand Down

0 comments on commit d1ccf88

Please sign in to comment.