mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 21:05:08 +00:00
[red-knot] Fixup a few edge cases regarding type[]
(#14918)
This commit is contained in:
parent
53f2d72e02
commit
58930905eb
2 changed files with 48 additions and 17 deletions
|
@ -15,6 +15,8 @@ pub(crate) enum CoreStdlibModule {
|
|||
TypingExtensions,
|
||||
Typing,
|
||||
Sys,
|
||||
#[allow(dead_code)]
|
||||
Abc, // currently only used in tests
|
||||
}
|
||||
|
||||
impl CoreStdlibModule {
|
||||
|
@ -26,6 +28,7 @@ impl CoreStdlibModule {
|
|||
Self::Typeshed => "_typeshed",
|
||||
Self::TypingExtensions => "typing_extensions",
|
||||
Self::Sys => "sys",
|
||||
Self::Abc => "abc",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -654,14 +654,19 @@ impl<'db> Type<'db> {
|
|||
},
|
||||
)
|
||||
}
|
||||
(Type::ClassLiteral(self_class), Type::SubclassOf(target_class)) => {
|
||||
self_class.class.is_subclass_of_base(db, target_class.base)
|
||||
}
|
||||
(
|
||||
Type::Instance(InstanceType { class: self_class }),
|
||||
Type::SubclassOf(target_class),
|
||||
) if self_class.is_known(db, KnownClass::Type) => {
|
||||
self_class.is_subclass_of_base(db, target_class.base)
|
||||
Type::ClassLiteral(ClassLiteralType { class: self_class }),
|
||||
Type::SubclassOf(SubclassOfType {
|
||||
base: ClassBase::Class(target_class),
|
||||
}),
|
||||
) => self_class.is_subclass_of(db, target_class),
|
||||
(
|
||||
Type::Instance(_),
|
||||
Type::SubclassOf(SubclassOfType {
|
||||
base: ClassBase::Class(target_class),
|
||||
}),
|
||||
) if target_class.is_known(db, KnownClass::Object) => {
|
||||
self.is_subtype_of(db, KnownClass::Type.to_instance(db))
|
||||
}
|
||||
(
|
||||
Type::SubclassOf(SubclassOfType {
|
||||
|
@ -928,10 +933,18 @@ impl<'db> Type<'db> {
|
|||
| Type::ClassLiteral(..)),
|
||||
) => left != right,
|
||||
|
||||
(Type::SubclassOf(type_class), Type::ClassLiteral(class_literal))
|
||||
| (Type::ClassLiteral(class_literal), Type::SubclassOf(type_class)) => {
|
||||
!class_literal.class.is_subclass_of_base(db, type_class.base)
|
||||
}
|
||||
(
|
||||
Type::SubclassOf(SubclassOfType {
|
||||
base: ClassBase::Class(class_a),
|
||||
}),
|
||||
Type::ClassLiteral(ClassLiteralType { class: class_b }),
|
||||
)
|
||||
| (
|
||||
Type::ClassLiteral(ClassLiteralType { class: class_b }),
|
||||
Type::SubclassOf(SubclassOfType {
|
||||
base: ClassBase::Class(class_a),
|
||||
}),
|
||||
) => !class_b.is_subclass_of(db, class_a),
|
||||
(Type::SubclassOf(_), Type::SubclassOf(_)) => false,
|
||||
(Type::SubclassOf(_), Type::Instance(_)) | (Type::Instance(_), Type::SubclassOf(_)) => {
|
||||
false
|
||||
|
@ -2599,11 +2612,7 @@ impl<'db> Class<'db> {
|
|||
pub fn is_subclass_of(self, db: &'db dyn Db, other: Class) -> bool {
|
||||
// `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 MRO.
|
||||
self.is_subclass_of_base(db, other)
|
||||
}
|
||||
|
||||
fn is_subclass_of_base(self, db: &'db dyn Db, other: impl Into<ClassBase<'db>>) -> bool {
|
||||
self.iter_mro(db).contains(&other.into())
|
||||
self.iter_mro(db).contains(&ClassBase::Class(other))
|
||||
}
|
||||
|
||||
/// Return the explicit `metaclass` of this class, if one is defined.
|
||||
|
@ -3038,12 +3047,18 @@ pub(crate) mod tests {
|
|||
// BuiltinInstance("str") corresponds to an instance of the builtin `str` class
|
||||
BuiltinInstance(&'static str),
|
||||
TypingInstance(&'static str),
|
||||
/// Members of the `abc` stdlib module
|
||||
AbcInstance(&'static str),
|
||||
AbcClassLiteral(&'static str),
|
||||
TypingLiteral,
|
||||
// BuiltinClassLiteral("str") corresponds to the builtin `str` class object itself
|
||||
BuiltinClassLiteral(&'static str),
|
||||
KnownClassInstance(KnownClass),
|
||||
Union(Vec<Ty>),
|
||||
Intersection { pos: Vec<Ty>, neg: Vec<Ty> },
|
||||
Intersection {
|
||||
pos: Vec<Ty>,
|
||||
neg: Vec<Ty>,
|
||||
},
|
||||
Tuple(Vec<Ty>),
|
||||
SubclassOfAny,
|
||||
SubclassOfBuiltinClass(&'static str),
|
||||
|
@ -3063,6 +3078,12 @@ pub(crate) mod tests {
|
|||
Ty::LiteralString => Type::LiteralString,
|
||||
Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()),
|
||||
Ty::BuiltinInstance(s) => builtins_symbol(db, s).expect_type().to_instance(db),
|
||||
Ty::AbcInstance(s) => core_module_symbol(db, CoreStdlibModule::Abc, s)
|
||||
.expect_type()
|
||||
.to_instance(db),
|
||||
Ty::AbcClassLiteral(s) => {
|
||||
core_module_symbol(db, CoreStdlibModule::Abc, s).expect_type()
|
||||
}
|
||||
Ty::TypingInstance(s) => typing_symbol(db, s).expect_type().to_instance(db),
|
||||
Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal),
|
||||
Ty::BuiltinClassLiteral(s) => builtins_symbol(db, s).expect_type(),
|
||||
|
@ -3148,6 +3169,7 @@ pub(crate) mod tests {
|
|||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfAny)]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::BuiltinInstance("type"))]
|
||||
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)]
|
||||
fn is_assignable_to(from: Ty, to: Ty) {
|
||||
let db = setup_db();
|
||||
assert!(from.into_type(&db).is_assignable_to(&db, to.into_type(&db)));
|
||||
|
@ -3214,6 +3236,8 @@ pub(crate) mod tests {
|
|||
#[test_case(Ty::BuiltinClassLiteral("int"), Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::TypingLiteral, Ty::TypingInstance("_SpecialForm"))]
|
||||
#[test_case(Ty::TypingLiteral, Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::AbcClassLiteral("ABC"), Ty::AbcInstance("ABCMeta"))]
|
||||
#[test_case(Ty::AbcInstance("ABCMeta"), Ty::SubclassOfBuiltinClass("object"))]
|
||||
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)));
|
||||
|
@ -3244,6 +3268,9 @@ pub(crate) mod tests {
|
|||
#[test_case(Ty::BuiltinClassLiteral("int"), Ty::BuiltinClassLiteral("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinClassLiteral("int"))]
|
||||
#[test_case(Ty::TypingInstance("_SpecialForm"), Ty::TypingLiteral)]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("str"))]
|
||||
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)]
|
||||
#[test_case(Ty::AbcInstance("ABCMeta"), Ty::SubclassOfBuiltinClass("type"))]
|
||||
fn is_not_subtype_of(from: Ty, to: Ty) {
|
||||
let db = setup_db();
|
||||
assert!(!from.into_type(&db).is_subtype_of(&db, to.into_type(&db)));
|
||||
|
@ -3403,6 +3430,7 @@ pub(crate) mod tests {
|
|||
#[test_case(Ty::Intersection{pos: vec![Ty::BuiltinInstance("int"), Ty::IntLiteral(2)], neg: vec![]}, Ty::IntLiteral(2))]
|
||||
#[test_case(Ty::Tuple(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Tuple(vec![Ty::IntLiteral(1), Ty::BuiltinInstance("int")]))]
|
||||
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::BuiltinInstance("type"))]
|
||||
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)]
|
||||
fn is_not_disjoint_from(a: Ty, b: Ty) {
|
||||
let db = setup_db();
|
||||
let a = a.into_type(&db);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue