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]]
|
# 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])))
|
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]]
|
# 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])))
|
reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[Any])))
|
||||||
# revealed: None
|
# revealed: None
|
||||||
reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.never()))
|
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
|
// but if a union is added to the intersection, we'll distribute ourselves over that union and
|
||||||
// create a union of intersections.
|
// create a union of intersections.
|
||||||
intersections: Vec<InnerIntersectionBuilder<'db>>,
|
intersections: Vec<InnerIntersectionBuilder<'db>>,
|
||||||
|
order_elements: bool,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -675,6 +676,7 @@ impl<'db> IntersectionBuilder<'db> {
|
||||||
pub(crate) fn new(db: &'db dyn Db) -> Self {
|
pub(crate) fn new(db: &'db dyn Db) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db,
|
db,
|
||||||
|
order_elements: false,
|
||||||
intersections: vec![InnerIntersectionBuilder::default()],
|
intersections: vec![InnerIntersectionBuilder::default()],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -682,14 +684,25 @@ impl<'db> IntersectionBuilder<'db> {
|
||||||
fn empty(db: &'db dyn Db) -> Self {
|
fn empty(db: &'db dyn Db) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db,
|
db,
|
||||||
|
order_elements: false,
|
||||||
intersections: vec![],
|
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 {
|
pub(crate) fn add_positive(self, ty: Type<'db>) -> Self {
|
||||||
self.add_positive_impl(ty, &mut vec![])
|
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(
|
pub(crate) fn add_positive_impl(
|
||||||
mut self,
|
mut self,
|
||||||
ty: Type<'db>,
|
ty: Type<'db>,
|
||||||
|
|
@ -898,13 +911,16 @@ impl<'db> IntersectionBuilder<'db> {
|
||||||
pub(crate) fn build(mut self) -> Type<'db> {
|
pub(crate) fn build(mut self) -> Type<'db> {
|
||||||
// Avoid allocating the UnionBuilder unnecessarily if we have just one intersection:
|
// Avoid allocating the UnionBuilder unnecessarily if we have just one intersection:
|
||||||
if self.intersections.len() == 1 {
|
if self.intersections.len() == 1 {
|
||||||
self.intersections.pop().unwrap().build(self.db)
|
self.intersections
|
||||||
|
.pop()
|
||||||
|
.unwrap()
|
||||||
|
.build(self.db, self.order_elements)
|
||||||
} else {
|
} else {
|
||||||
UnionType::from_elements(
|
UnionType::from_elements(
|
||||||
self.db,
|
self.db,
|
||||||
self.intersections
|
self.intersections
|
||||||
.into_iter()
|
.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);
|
self.simplify_constrained_typevars(db);
|
||||||
|
|
||||||
// If any typevars are in `self.positive`, speculatively solve all bounded type variables
|
// 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.positive.shrink_to_fit();
|
||||||
self.negative.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))
|
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::generics::{GenericContext, InferableTypeVars, Specialization};
|
||||||
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
|
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundTypeVarIdentity, BoundTypeVarInstance, IntersectionType, Type, TypeVarBoundOrConstraints,
|
BoundTypeVarIdentity, BoundTypeVarInstance, IntersectionBuilder, IntersectionType, Type,
|
||||||
UnionType, walk_bound_type_var_type,
|
TypeVarBoundOrConstraints, UnionBuilder, UnionType, walk_bound_type_var_type,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
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.
|
// do with that, so instead we just report the ambiguity as a specialization failure.
|
||||||
let mut satisfied = false;
|
let mut satisfied = false;
|
||||||
let mut unconstrained = false;
|
let mut unconstrained = false;
|
||||||
let mut greatest_lower_bound = Type::Never;
|
let mut greatest_lower_bound = UnionBuilder::new(db).order_elements(true);
|
||||||
let mut least_upper_bound = Type::object();
|
let mut least_upper_bound = IntersectionBuilder::new(db).order_elements(true);
|
||||||
let identity = bound_typevar.identity(db);
|
let identity = bound_typevar.identity(db);
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
||||||
|
|
@ -3400,10 +3400,8 @@ impl<'db> GenericContext<'db> {
|
||||||
upper_bound = %upper_bound.display(db),
|
upper_bound = %upper_bound.display(db),
|
||||||
"found representative type",
|
"found representative type",
|
||||||
);
|
);
|
||||||
greatest_lower_bound =
|
greatest_lower_bound.add_in_place(lower_bound);
|
||||||
UnionType::from_elements(db, [greatest_lower_bound, lower_bound]);
|
least_upper_bound.add_positive_in_place(upper_bound);
|
||||||
least_upper_bound =
|
|
||||||
IntersectionType::from_elements(db, [least_upper_bound, upper_bound]);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unconstrained = true;
|
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
|
// 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.
|
// 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) {
|
if !greatest_lower_bound.is_assignable_to(db, least_upper_bound) {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
target: "ty_python_semantic::types::constraints::specialize_constrained",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue