mirror of https://github.com/astral-sh/ruff
intersection of atomic types
This commit is contained in:
parent
5e163e2a5e
commit
78e1df037c
|
|
@ -10,7 +10,9 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use crate::types::visitor::TypeVisitor;
|
use crate::types::visitor::TypeVisitor;
|
||||||
use crate::types::{IntersectionBuilder, IntersectionType, Type, TypeVarInstance, UnionType};
|
use crate::types::{
|
||||||
|
IntersectionBuilder, IntersectionType, Type, TypeVarInstance, UnionBuilder, UnionType,
|
||||||
|
};
|
||||||
|
|
||||||
/// A constraint that the type `s` must be a subtype of the type `t`. Tallying will find all
|
/// A constraint that the type `s` must be a subtype of the type `t`. Tallying will find all
|
||||||
/// substitutions of any type variables in `s` and `t` that ensure that this subtyping holds.
|
/// substitutions of any type variables in `s` and `t` that ensure that this subtyping holds.
|
||||||
|
|
@ -182,6 +184,7 @@ impl<'db> ConstraintSetSet<'db> {
|
||||||
|
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
// Figure 3, step 6
|
// Figure 3, step 6
|
||||||
|
// A union is a subtype of Never only if every element is.
|
||||||
self.visit_union_type(db, union);
|
self.visit_union_type(db, union);
|
||||||
let result = (union.iter(db))
|
let result = (union.iter(db))
|
||||||
.fold(ConstraintSetSet::always(), |sets, element| {
|
.fold(ConstraintSetSet::always(), |sets, element| {
|
||||||
|
|
@ -192,6 +195,9 @@ impl<'db> ConstraintSetSet<'db> {
|
||||||
|
|
||||||
Type::Intersection(intersection) => {
|
Type::Intersection(intersection) => {
|
||||||
// Figure 3, step 2
|
// Figure 3, step 2
|
||||||
|
// If an intersection contains any (positive or negative) top-level type
|
||||||
|
// variables, extract out and isolate the smallest one (according to our
|
||||||
|
// arbitrary ordering).
|
||||||
let smallest_positive =
|
let smallest_positive =
|
||||||
find_smallest_typevar(intersection.iter_positive(db));
|
find_smallest_typevar(intersection.iter_positive(db));
|
||||||
let smallest_negative =
|
let smallest_negative =
|
||||||
|
|
@ -226,6 +232,47 @@ impl<'db> ConstraintSetSet<'db> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Figure 3, step 3
|
||||||
|
// If all (positive and negative) elements of the intersection are atomic
|
||||||
|
// types (and therefore cannot contain any typevars), fall back on an
|
||||||
|
// assignability check: if the intersection of the positive elements is
|
||||||
|
// assignable to the union of the negative elements, then the overall
|
||||||
|
// intersection is empty.
|
||||||
|
let mut all_atomic = true;
|
||||||
|
let mut positive_atomic = IntersectionBuilder::new(db);
|
||||||
|
let mut negative_atomic = UnionBuilder::new(db);
|
||||||
|
for positive in intersection.iter_positive(db) {
|
||||||
|
if !all_atomic {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !positive.is_atomic() {
|
||||||
|
all_atomic = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
positive_atomic = positive_atomic.add_positive(positive);
|
||||||
|
}
|
||||||
|
for negative in intersection.iter_negative(db) {
|
||||||
|
if !all_atomic {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !negative.is_atomic() {
|
||||||
|
all_atomic = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
negative_atomic = negative_atomic.add(negative);
|
||||||
|
}
|
||||||
|
if all_atomic {
|
||||||
|
let positive_atomic = positive_atomic.build();
|
||||||
|
let negative_atomic = negative_atomic.build();
|
||||||
|
let result = if positive_atomic.is_assignable_to(db, negative_atomic) {
|
||||||
|
ConstraintSetSet::always()
|
||||||
|
} else {
|
||||||
|
ConstraintSetSet::never()
|
||||||
|
};
|
||||||
|
self.results.insert(ty, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: other intersection clauses
|
// TODO: other intersection clauses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,12 @@ impl<'db> From<Type<'db>> for TypeKind<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'db> Type<'db> {
|
||||||
|
pub(crate) fn is_atomic(self) -> bool {
|
||||||
|
matches!(TypeKind::from(self), TypeKind::Atomic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
non_atomic_type: NonAtomicType<'db>,
|
non_atomic_type: NonAtomicType<'db>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue