mirror of https://github.com/astral-sh/ruff
add ConstraintSetAssignability relation
This commit is contained in:
parent
8ec6673230
commit
b9691b8a07
|
|
@ -1955,6 +1955,33 @@ impl<'db> Type<'db> {
|
||||||
return constraints.implies_subtype_of(db, self, target);
|
return constraints.implies_subtype_of(db, self, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the new constraint-set-based assignability relation next. Comparisons with a
|
||||||
|
// typevar are translated directly into a constraint set.
|
||||||
|
if relation.is_constraint_set_assignability() {
|
||||||
|
// A typevar satisfies a relation when...it satisfies the relation. Yes that's a
|
||||||
|
// tautology! We're moving the caller's subtyping/assignability requirement into a
|
||||||
|
// constraint set. If the typevar has an upper bound or constraints, then the relation
|
||||||
|
// only has to hold when the typevar has a valid specialization (i.e., one that
|
||||||
|
// satisfies the upper bound/constraints).
|
||||||
|
if let Type::TypeVar(bound_typevar) = self {
|
||||||
|
return ConstraintSet::constrain_typevar(
|
||||||
|
db,
|
||||||
|
bound_typevar,
|
||||||
|
Type::Never,
|
||||||
|
target,
|
||||||
|
relation,
|
||||||
|
);
|
||||||
|
} else if let Type::TypeVar(bound_typevar) = target {
|
||||||
|
return ConstraintSet::constrain_typevar(
|
||||||
|
db,
|
||||||
|
bound_typevar,
|
||||||
|
self,
|
||||||
|
Type::object(),
|
||||||
|
relation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match (self, target) {
|
match (self, target) {
|
||||||
// Everything is a subtype of `object`.
|
// Everything is a subtype of `object`.
|
||||||
(_, Type::NominalInstance(instance)) if instance.is_object() => {
|
(_, Type::NominalInstance(instance)) if instance.is_object() => {
|
||||||
|
|
@ -2035,7 +2062,7 @@ impl<'db> Type<'db> {
|
||||||
);
|
);
|
||||||
ConstraintSet::from(match relation {
|
ConstraintSet::from(match relation {
|
||||||
TypeRelation::Subtyping | TypeRelation::SubtypingAssuming(_) => false,
|
TypeRelation::Subtyping | TypeRelation::SubtypingAssuming(_) => false,
|
||||||
TypeRelation::Assignability => true,
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability => true,
|
||||||
TypeRelation::Redundancy => match target {
|
TypeRelation::Redundancy => match target {
|
||||||
Type::Dynamic(_) => true,
|
Type::Dynamic(_) => true,
|
||||||
Type::Union(union) => union.elements(db).iter().any(Type::is_dynamic),
|
Type::Union(union) => union.elements(db).iter().any(Type::is_dynamic),
|
||||||
|
|
@ -2045,7 +2072,7 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
(_, Type::Dynamic(_)) => ConstraintSet::from(match relation {
|
(_, Type::Dynamic(_)) => ConstraintSet::from(match relation {
|
||||||
TypeRelation::Subtyping | TypeRelation::SubtypingAssuming(_) => false,
|
TypeRelation::Subtyping | TypeRelation::SubtypingAssuming(_) => false,
|
||||||
TypeRelation::Assignability => true,
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability => true,
|
||||||
TypeRelation::Redundancy => match self {
|
TypeRelation::Redundancy => match self {
|
||||||
Type::Dynamic(_) => true,
|
Type::Dynamic(_) => true,
|
||||||
Type::Intersection(intersection) => {
|
Type::Intersection(intersection) => {
|
||||||
|
|
@ -2309,14 +2336,19 @@ impl<'db> Type<'db> {
|
||||||
TypeRelation::Subtyping
|
TypeRelation::Subtyping
|
||||||
| TypeRelation::Redundancy
|
| TypeRelation::Redundancy
|
||||||
| TypeRelation::SubtypingAssuming(_) => self,
|
| TypeRelation::SubtypingAssuming(_) => self,
|
||||||
TypeRelation::Assignability => self.bottom_materialization(db),
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability => {
|
||||||
|
self.bottom_materialization(db)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
intersection.negative(db).iter().when_all(db, |&neg_ty| {
|
intersection.negative(db).iter().when_all(db, |&neg_ty| {
|
||||||
let neg_ty = match relation {
|
let neg_ty = match relation {
|
||||||
TypeRelation::Subtyping
|
TypeRelation::Subtyping
|
||||||
| TypeRelation::Redundancy
|
| TypeRelation::Redundancy
|
||||||
| TypeRelation::SubtypingAssuming(_) => neg_ty,
|
| TypeRelation::SubtypingAssuming(_) => neg_ty,
|
||||||
TypeRelation::Assignability => neg_ty.bottom_materialization(db),
|
TypeRelation::Assignability
|
||||||
|
| TypeRelation::ConstraintSetAssignability => {
|
||||||
|
neg_ty.bottom_materialization(db)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self_ty.is_disjoint_from_impl(
|
self_ty.is_disjoint_from_impl(
|
||||||
db,
|
db,
|
||||||
|
|
@ -11860,6 +11892,11 @@ pub(crate) enum TypeRelation<'db> {
|
||||||
/// are not actually subtypes of each other. (That is, `implies_subtype_of(false, int, str)`
|
/// are not actually subtypes of each other. (That is, `implies_subtype_of(false, int, str)`
|
||||||
/// will return true!)
|
/// will return true!)
|
||||||
SubtypingAssuming(ConstraintSet<'db>),
|
SubtypingAssuming(ConstraintSet<'db>),
|
||||||
|
|
||||||
|
/// A placeholder for the new assignability relation that uses constraint sets to encode
|
||||||
|
/// relationships with a typevar. This will eventually replace `Assignability`, but allows us
|
||||||
|
/// to start using the new relation in a controlled manner in some places.
|
||||||
|
ConstraintSetAssignability,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRelation<'_> {
|
impl TypeRelation<'_> {
|
||||||
|
|
@ -11867,6 +11904,10 @@ impl TypeRelation<'_> {
|
||||||
matches!(self, TypeRelation::Assignability)
|
matches!(self, TypeRelation::Assignability)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn is_constraint_set_assignability(self) -> bool {
|
||||||
|
matches!(self, TypeRelation::ConstraintSetAssignability)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) const fn is_subtyping(self) -> bool {
|
pub(crate) const fn is_subtyping(self) -> bool {
|
||||||
matches!(self, TypeRelation::Subtyping)
|
matches!(self, TypeRelation::Subtyping)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -637,7 +637,9 @@ impl<'db> ClassType<'db> {
|
||||||
| TypeRelation::SubtypingAssuming(_) => {
|
| TypeRelation::SubtypingAssuming(_) => {
|
||||||
ConstraintSet::from(other.is_object(db))
|
ConstraintSet::from(other.is_object(db))
|
||||||
}
|
}
|
||||||
TypeRelation::Assignability => ConstraintSet::from(!other.is_final(db)),
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability => {
|
||||||
|
ConstraintSet::from(!other.is_final(db))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Protocol, Generic, and TypedDict are not represented by a ClassType.
|
// Protocol, Generic, and TypedDict are not represented by a ClassType.
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ impl<'db> ConstraintSet<'db> {
|
||||||
lower.top_materialization(db),
|
lower.top_materialization(db),
|
||||||
upper.bottom_materialization(db),
|
upper.bottom_materialization(db),
|
||||||
),
|
),
|
||||||
TypeRelation::Assignability => (
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability => (
|
||||||
lower.bottom_materialization(db),
|
lower.bottom_materialization(db),
|
||||||
upper.top_materialization(db),
|
upper.top_materialization(db),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -903,7 +903,11 @@ fn has_relation_in_invariant_position<'db>(
|
||||||
disjointness_visitor,
|
disjointness_visitor,
|
||||||
),
|
),
|
||||||
// And A <~ B (assignability) is Bottom[A] <: Top[B]
|
// And A <~ B (assignability) is Bottom[A] <: Top[B]
|
||||||
(None, Some(base_mat), TypeRelation::Assignability) => is_subtype_in_invariant_position(
|
(
|
||||||
|
None,
|
||||||
|
Some(base_mat),
|
||||||
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability,
|
||||||
|
) => is_subtype_in_invariant_position(
|
||||||
db,
|
db,
|
||||||
derived_type,
|
derived_type,
|
||||||
MaterializationKind::Bottom,
|
MaterializationKind::Bottom,
|
||||||
|
|
@ -913,7 +917,11 @@ fn has_relation_in_invariant_position<'db>(
|
||||||
relation_visitor,
|
relation_visitor,
|
||||||
disjointness_visitor,
|
disjointness_visitor,
|
||||||
),
|
),
|
||||||
(Some(derived_mat), None, TypeRelation::Assignability) => is_subtype_in_invariant_position(
|
(
|
||||||
|
Some(derived_mat),
|
||||||
|
None,
|
||||||
|
TypeRelation::Assignability | TypeRelation::ConstraintSetAssignability,
|
||||||
|
) => is_subtype_in_invariant_position(
|
||||||
db,
|
db,
|
||||||
derived_type,
|
derived_type,
|
||||||
derived_mat,
|
derived_mat,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue