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,
|
TypingExtensions,
|
||||||
Typing,
|
Typing,
|
||||||
Sys,
|
Sys,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Abc, // currently only used in tests
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoreStdlibModule {
|
impl CoreStdlibModule {
|
||||||
|
@ -26,6 +28,7 @@ impl CoreStdlibModule {
|
||||||
Self::Typeshed => "_typeshed",
|
Self::Typeshed => "_typeshed",
|
||||||
Self::TypingExtensions => "typing_extensions",
|
Self::TypingExtensions => "typing_extensions",
|
||||||
Self::Sys => "sys",
|
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::ClassLiteral(ClassLiteralType { class: self_class }),
|
||||||
Type::SubclassOf(target_class),
|
Type::SubclassOf(SubclassOfType {
|
||||||
) if self_class.is_known(db, KnownClass::Type) => {
|
base: ClassBase::Class(target_class),
|
||||||
self_class.is_subclass_of_base(db, target_class.base)
|
}),
|
||||||
|
) => 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 {
|
Type::SubclassOf(SubclassOfType {
|
||||||
|
@ -928,10 +933,18 @@ impl<'db> Type<'db> {
|
||||||
| Type::ClassLiteral(..)),
|
| Type::ClassLiteral(..)),
|
||||||
) => left != right,
|
) => left != right,
|
||||||
|
|
||||||
(Type::SubclassOf(type_class), Type::ClassLiteral(class_literal))
|
(
|
||||||
| (Type::ClassLiteral(class_literal), Type::SubclassOf(type_class)) => {
|
Type::SubclassOf(SubclassOfType {
|
||||||
!class_literal.class.is_subclass_of_base(db, type_class.base)
|
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::SubclassOf(_)) => false,
|
||||||
(Type::SubclassOf(_), Type::Instance(_)) | (Type::Instance(_), Type::SubclassOf(_)) => {
|
(Type::SubclassOf(_), Type::Instance(_)) | (Type::Instance(_), Type::SubclassOf(_)) => {
|
||||||
false
|
false
|
||||||
|
@ -2599,11 +2612,7 @@ impl<'db> Class<'db> {
|
||||||
pub fn is_subclass_of(self, db: &'db dyn Db, other: Class) -> bool {
|
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
|
// `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.
|
// participate, so we should not return `True` if we find `Any/Unknown` in the MRO.
|
||||||
self.is_subclass_of_base(db, other)
|
self.iter_mro(db).contains(&ClassBase::Class(other))
|
||||||
}
|
|
||||||
|
|
||||||
fn is_subclass_of_base(self, db: &'db dyn Db, other: impl Into<ClassBase<'db>>) -> bool {
|
|
||||||
self.iter_mro(db).contains(&other.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the explicit `metaclass` of this class, if one is defined.
|
/// 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("str") corresponds to an instance of the builtin `str` class
|
||||||
BuiltinInstance(&'static str),
|
BuiltinInstance(&'static str),
|
||||||
TypingInstance(&'static str),
|
TypingInstance(&'static str),
|
||||||
|
/// Members of the `abc` stdlib module
|
||||||
|
AbcInstance(&'static str),
|
||||||
|
AbcClassLiteral(&'static str),
|
||||||
TypingLiteral,
|
TypingLiteral,
|
||||||
// BuiltinClassLiteral("str") corresponds to the builtin `str` class object itself
|
// BuiltinClassLiteral("str") corresponds to the builtin `str` class object itself
|
||||||
BuiltinClassLiteral(&'static str),
|
BuiltinClassLiteral(&'static str),
|
||||||
KnownClassInstance(KnownClass),
|
KnownClassInstance(KnownClass),
|
||||||
Union(Vec<Ty>),
|
Union(Vec<Ty>),
|
||||||
Intersection { pos: Vec<Ty>, neg: Vec<Ty> },
|
Intersection {
|
||||||
|
pos: Vec<Ty>,
|
||||||
|
neg: Vec<Ty>,
|
||||||
|
},
|
||||||
Tuple(Vec<Ty>),
|
Tuple(Vec<Ty>),
|
||||||
SubclassOfAny,
|
SubclassOfAny,
|
||||||
SubclassOfBuiltinClass(&'static str),
|
SubclassOfBuiltinClass(&'static str),
|
||||||
|
@ -3063,6 +3078,12 @@ pub(crate) mod tests {
|
||||||
Ty::LiteralString => Type::LiteralString,
|
Ty::LiteralString => Type::LiteralString,
|
||||||
Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()),
|
Ty::BytesLiteral(s) => Type::bytes_literal(db, s.as_bytes()),
|
||||||
Ty::BuiltinInstance(s) => builtins_symbol(db, s).expect_type().to_instance(db),
|
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::TypingInstance(s) => typing_symbol(db, s).expect_type().to_instance(db),
|
||||||
Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal),
|
Ty::TypingLiteral => Type::KnownInstance(KnownInstanceType::Literal),
|
||||||
Ty::BuiltinClassLiteral(s) => builtins_symbol(db, s).expect_type(),
|
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::SubclassOfAny)]
|
||||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("object"))]
|
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("object"))]
|
||||||
#[test_case(Ty::BuiltinInstance("type"), Ty::BuiltinInstance("type"))]
|
#[test_case(Ty::BuiltinInstance("type"), Ty::BuiltinInstance("type"))]
|
||||||
|
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)]
|
||||||
fn is_assignable_to(from: Ty, to: Ty) {
|
fn is_assignable_to(from: Ty, to: Ty) {
|
||||||
let db = setup_db();
|
let db = setup_db();
|
||||||
assert!(from.into_type(&db).is_assignable_to(&db, to.into_type(&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::BuiltinClassLiteral("int"), Ty::BuiltinInstance("object"))]
|
||||||
#[test_case(Ty::TypingLiteral, Ty::TypingInstance("_SpecialForm"))]
|
#[test_case(Ty::TypingLiteral, Ty::TypingInstance("_SpecialForm"))]
|
||||||
#[test_case(Ty::TypingLiteral, Ty::BuiltinInstance("object"))]
|
#[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) {
|
fn is_subtype_of(from: Ty, to: Ty) {
|
||||||
let db = setup_db();
|
let db = setup_db();
|
||||||
assert!(from.into_type(&db).is_subtype_of(&db, to.into_type(&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::BuiltinClassLiteral("int"), Ty::BuiltinClassLiteral("object"))]
|
||||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinClassLiteral("int"))]
|
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinClassLiteral("int"))]
|
||||||
#[test_case(Ty::TypingInstance("_SpecialForm"), Ty::TypingLiteral)]
|
#[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) {
|
fn is_not_subtype_of(from: Ty, to: Ty) {
|
||||||
let db = setup_db();
|
let db = setup_db();
|
||||||
assert!(!from.into_type(&db).is_subtype_of(&db, to.into_type(&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::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::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::BuiltinInstance("type"))]
|
||||||
|
#[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)]
|
||||||
fn is_not_disjoint_from(a: Ty, b: Ty) {
|
fn is_not_disjoint_from(a: Ty, b: Ty) {
|
||||||
let db = setup_db();
|
let db = setup_db();
|
||||||
let a = a.into_type(&db);
|
let a = a.into_type(&db);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue