mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +00:00
[red-knot] Improve Type::is_disjoint_from()
for KnownInstanceType
s (#15261)
This commit is contained in:
parent
980ce941c7
commit
0743838438
1 changed files with 25 additions and 7 deletions
|
@ -1194,19 +1194,22 @@ impl<'db> Type<'db> {
|
|||
ty.bool(db).is_always_true()
|
||||
}
|
||||
|
||||
(Type::SubclassOf(_), _) | (_, Type::SubclassOf(_)) => {
|
||||
// TODO: Once we have support for final classes, we can determine disjointness in some cases
|
||||
(Type::SubclassOf(_), other) | (other, Type::SubclassOf(_)) => {
|
||||
// TODO: Once we have support for final classes, we can determine disjointness in more cases
|
||||
// here. However, note that it might be better to turn `Type::SubclassOf('FinalClass')` into
|
||||
// `Type::ClassLiteral('FinalClass')` during construction, instead of adding special cases for
|
||||
// final classes inside `Type::SubclassOf` everywhere.
|
||||
false
|
||||
other.is_disjoint_from(db, KnownClass::Type.to_instance(db))
|
||||
}
|
||||
|
||||
(Type::KnownInstance(left), right) => {
|
||||
left.instance_fallback(db).is_disjoint_from(db, right)
|
||||
(Type::KnownInstance(known_instance), Type::Instance(InstanceType { class }))
|
||||
| (Type::Instance(InstanceType { class }), Type::KnownInstance(known_instance)) => {
|
||||
!known_instance.is_instance_of(db, class)
|
||||
}
|
||||
(left, Type::KnownInstance(right)) => {
|
||||
left.is_disjoint_from(db, right.instance_fallback(db))
|
||||
|
||||
(known_instance_ty @ Type::KnownInstance(_), Type::Tuple(_))
|
||||
| (Type::Tuple(_), known_instance_ty @ Type::KnownInstance(_)) => {
|
||||
known_instance_ty.is_disjoint_from(db, KnownClass::Tuple.to_instance(db))
|
||||
}
|
||||
|
||||
(
|
||||
|
@ -2352,6 +2355,15 @@ impl<'db> KnownClass {
|
|||
.unwrap_or(Type::subclass_of_base(ClassBase::Unknown))
|
||||
}
|
||||
|
||||
/// Return `true` if this symbol can be resolved to a class definition `class` in typeshed,
|
||||
/// *and* `class` is a subclass of `other`.
|
||||
pub fn is_subclass_of(self, db: &'db dyn Db, other: Class<'db>) -> bool {
|
||||
known_module_symbol(db, self.canonical_module(db), self.as_str())
|
||||
.ignore_possibly_unbound()
|
||||
.and_then(Type::into_class_literal)
|
||||
.is_some_and(|ClassLiteralType { class }| class.is_subclass_of(db, other))
|
||||
}
|
||||
|
||||
/// Return the module in which we should look up the definition for this class
|
||||
pub(crate) fn canonical_module(self, db: &'db dyn Db) -> KnownModule {
|
||||
match self {
|
||||
|
@ -2738,6 +2750,10 @@ impl<'db> KnownInstanceType<'db> {
|
|||
self.class().to_instance(db)
|
||||
}
|
||||
|
||||
pub fn is_instance_of(self, db: &'db dyn Db, class: Class<'db>) -> bool {
|
||||
self.class().is_subclass_of(db, class)
|
||||
}
|
||||
|
||||
pub fn try_from_file_and_name(db: &'db dyn Db, file: File, symbol_name: &str) -> Option<Self> {
|
||||
let candidate = match symbol_name {
|
||||
"Any" => Self::Any,
|
||||
|
@ -4160,6 +4176,8 @@ pub(crate) mod tests {
|
|||
#[test_case(Ty::SubclassOfBuiltinClass("object"), Ty::None)]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::LiteralString)]
|
||||
#[test_case(Ty::AlwaysFalsy, Ty::AlwaysTruthy)]
|
||||
#[test_case(Ty::Tuple(vec![]), Ty::TypingLiteral)]
|
||||
#[test_case(Ty::TypingLiteral, Ty::SubclassOfBuiltinClass("object"))]
|
||||
fn is_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