mirror of https://github.com/astral-sh/ruff
order specialized types consistently
This commit is contained in:
parent
7d5b1e59d2
commit
0d90fe7a72
|
|
@ -316,7 +316,7 @@ def constrained_by_gradual_list_reverse[T: (list[Any], list[Base])]():
|
|||
# revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[object]]
|
||||
reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[object])))
|
||||
# TODO: revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Any]]
|
||||
# revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Any] & list[Base]]
|
||||
# revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Base] & list[Any]]
|
||||
reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[Any])))
|
||||
# revealed: None
|
||||
reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.never()))
|
||||
|
|
|
|||
|
|
@ -668,6 +668,7 @@ pub(crate) struct IntersectionBuilder<'db> {
|
|||
// but if a union is added to the intersection, we'll distribute ourselves over that union and
|
||||
// create a union of intersections.
|
||||
intersections: Vec<InnerIntersectionBuilder<'db>>,
|
||||
order_elements: bool,
|
||||
db: &'db dyn Db,
|
||||
}
|
||||
|
||||
|
|
@ -675,6 +676,7 @@ impl<'db> IntersectionBuilder<'db> {
|
|||
pub(crate) fn new(db: &'db dyn Db) -> Self {
|
||||
Self {
|
||||
db,
|
||||
order_elements: false,
|
||||
intersections: vec![InnerIntersectionBuilder::default()],
|
||||
}
|
||||
}
|
||||
|
|
@ -682,14 +684,25 @@ impl<'db> IntersectionBuilder<'db> {
|
|||
fn empty(db: &'db dyn Db) -> Self {
|
||||
Self {
|
||||
db,
|
||||
order_elements: false,
|
||||
intersections: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn order_elements(mut self, val: bool) -> Self {
|
||||
self.order_elements = val;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn add_positive(self, ty: Type<'db>) -> Self {
|
||||
self.add_positive_impl(ty, &mut vec![])
|
||||
}
|
||||
|
||||
pub(crate) fn add_positive_in_place(&mut self, ty: Type<'db>) {
|
||||
let updated = std::mem::replace(self, Self::empty(self.db)).add_positive(ty);
|
||||
*self = updated;
|
||||
}
|
||||
|
||||
pub(crate) fn add_positive_impl(
|
||||
mut self,
|
||||
ty: Type<'db>,
|
||||
|
|
@ -898,13 +911,16 @@ impl<'db> IntersectionBuilder<'db> {
|
|||
pub(crate) fn build(mut self) -> Type<'db> {
|
||||
// Avoid allocating the UnionBuilder unnecessarily if we have just one intersection:
|
||||
if self.intersections.len() == 1 {
|
||||
self.intersections.pop().unwrap().build(self.db)
|
||||
self.intersections
|
||||
.pop()
|
||||
.unwrap()
|
||||
.build(self.db, self.order_elements)
|
||||
} else {
|
||||
UnionType::from_elements(
|
||||
self.db,
|
||||
self.intersections
|
||||
.into_iter()
|
||||
.map(|inner| inner.build(self.db)),
|
||||
.map(|inner| inner.build(self.db, self.order_elements)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1238,7 +1254,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn build(mut self, db: &'db dyn Db) -> Type<'db> {
|
||||
fn build(mut self, db: &'db dyn Db, order_elements: bool) -> Type<'db> {
|
||||
self.simplify_constrained_typevars(db);
|
||||
|
||||
// If any typevars are in `self.positive`, speculatively solve all bounded type variables
|
||||
|
|
@ -1279,6 +1295,12 @@ impl<'db> InnerIntersectionBuilder<'db> {
|
|||
_ => {
|
||||
self.positive.shrink_to_fit();
|
||||
self.negative.shrink_to_fit();
|
||||
if order_elements {
|
||||
self.positive
|
||||
.sort_unstable_by(|l, r| union_or_intersection_elements_ordering(db, l, r));
|
||||
self.negative
|
||||
.sort_unstable_by(|l, r| union_or_intersection_elements_ordering(db, l, r));
|
||||
}
|
||||
Type::Intersection(IntersectionType::new(db, self.positive, self.negative))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ use salsa::plumbing::AsId;
|
|||
use crate::types::generics::{GenericContext, InferableTypeVars, Specialization};
|
||||
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
|
||||
use crate::types::{
|
||||
BoundTypeVarIdentity, BoundTypeVarInstance, IntersectionType, Type, TypeVarBoundOrConstraints,
|
||||
UnionType, walk_bound_type_var_type,
|
||||
BoundTypeVarIdentity, BoundTypeVarInstance, IntersectionBuilder, IntersectionType, Type,
|
||||
TypeVarBoundOrConstraints, UnionBuilder, UnionType, walk_bound_type_var_type,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
|
@ -3380,8 +3380,8 @@ impl<'db> GenericContext<'db> {
|
|||
// do with that, so instead we just report the ambiguity as a specialization failure.
|
||||
let mut satisfied = false;
|
||||
let mut unconstrained = false;
|
||||
let mut greatest_lower_bound = Type::Never;
|
||||
let mut least_upper_bound = Type::object();
|
||||
let mut greatest_lower_bound = UnionBuilder::new(db).order_elements(true);
|
||||
let mut least_upper_bound = IntersectionBuilder::new(db).order_elements(true);
|
||||
let identity = bound_typevar.identity(db);
|
||||
tracing::trace!(
|
||||
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
||||
|
|
@ -3400,10 +3400,8 @@ impl<'db> GenericContext<'db> {
|
|||
upper_bound = %upper_bound.display(db),
|
||||
"found representative type",
|
||||
);
|
||||
greatest_lower_bound =
|
||||
UnionType::from_elements(db, [greatest_lower_bound, lower_bound]);
|
||||
least_upper_bound =
|
||||
IntersectionType::from_elements(db, [least_upper_bound, upper_bound]);
|
||||
greatest_lower_bound.add_in_place(lower_bound);
|
||||
least_upper_bound.add_positive_in_place(upper_bound);
|
||||
}
|
||||
None => {
|
||||
unconstrained = true;
|
||||
|
|
@ -3437,6 +3435,8 @@ impl<'db> GenericContext<'db> {
|
|||
|
||||
// If `lower ≰ upper`, then there is no type that satisfies all of the paths in the
|
||||
// BDD. That's an ambiguous specialization, as described above.
|
||||
let greatest_lower_bound = greatest_lower_bound.build();
|
||||
let least_upper_bound = least_upper_bound.build();
|
||||
if !greatest_lower_bound.is_assignable_to(db, least_upper_bound) {
|
||||
tracing::debug!(
|
||||
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
||||
|
|
|
|||
Loading…
Reference in New Issue