[ty] remove the `visitor` parameter in the `recursive_type_normalized_impl` method (#21701)

This commit is contained in:
Shunsuke Shibayama 2025-12-01 16:48:43 +09:00 committed by GitHub
parent 846df40a6e
commit a6cbc138d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 148 additions and 233 deletions

View File

@ -52,6 +52,10 @@ def f(x: A):
JSONPrimitive = Union[str, int, float, bool, None] JSONPrimitive = Union[str, int, float, bool, None]
JSONValue = TypeAliasType("JSONValue", 'Union[JSONPrimitive, Sequence["JSONValue"], Mapping[str, "JSONValue"]]') JSONValue = TypeAliasType("JSONValue", 'Union[JSONPrimitive, Sequence["JSONValue"], Mapping[str, "JSONValue"]]')
def _(x: JSONValue):
# TODO: should be `JSONValue`
reveal_type(x) # revealed: Divergent
``` ```
## Self-referential legacy type variables ## Self-referential legacy type variables

View File

@ -573,20 +573,19 @@ impl<'db> PropertyInstanceType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let getter = match self.getter(db) { let getter = match self.getter(db) {
Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?), Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true)?),
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
}; };
let setter = match self.setter(db) { let setter = match self.setter(db) {
Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?), Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true)?),
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -1553,15 +1552,14 @@ impl<'db> Type<'db> {
#[must_use] #[must_use]
pub(crate) fn recursive_type_normalized(self, db: &'db dyn Db, cycle: &salsa::Cycle) -> Self { pub(crate) fn recursive_type_normalized(self, db: &'db dyn Db, cycle: &salsa::Cycle) -> Self {
cycle.head_ids().fold(self, |ty, id| { cycle.head_ids().fold(self, |ty, id| {
let visitor = NormalizedVisitor::new(Type::divergent(id)); ty.recursive_type_normalized_impl(db, Type::divergent(id), false)
ty.recursive_type_normalized_impl(db, Type::divergent(id), false, &visitor)
.unwrap_or(Type::divergent(id)) .unwrap_or(Type::divergent(id))
}) })
} }
/// Normalizes types including divergent types (recursive types), which is necessary for convergence of fixed-point iteration. /// Normalizes types including divergent types (recursive types), which is necessary for convergence of fixed-point iteration.
/// When nested is true, propagate `None`. That is, if the type contains a `Divergent` type, the return value of this method is `None`. /// When `nested` is true, propagate `None`. That is, if the type contains a `Divergent` type, the return value of this method is `None` (so we can use the `?` operator).
/// When nested is false, create a type containing `Divergent` types instead of propagating `None`. /// When `nested` is false, create a type containing `Divergent` types instead of propagating `None` (we should use `unwrap_or(Divergent)`).
/// This is to preserve the structure of the non-divergent parts of the type instead of completely collapsing the type containing a `Divergent` type into a `Divergent` type. /// This is to preserve the structure of the non-divergent parts of the type instead of completely collapsing the type containing a `Divergent` type into a `Divergent` type.
/// ```python /// ```python
/// tuple[tuple[Divergent, Literal[1]], Literal[1]].recursive_type_normalized(nested: false) /// tuple[tuple[Divergent, Literal[1]], Literal[1]].recursive_type_normalized(nested: false)
@ -1580,102 +1578,73 @@ impl<'db> Type<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
if nested && self == div { if nested && self == div {
return None; return None;
} }
match self { match self {
Type::Union(union) => visitor.try_visit(self, || { Type::Union(union) => union.recursive_type_normalized_impl(db, div, nested),
union.recursive_type_normalized_impl(db, div, nested, visitor) Type::Intersection(intersection) => intersection
}), .recursive_type_normalized_impl(db, div, nested)
Type::Intersection(intersection) => visitor.try_visit(self, || { .map(Type::Intersection),
intersection Type::Callable(callable) => callable
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.map(Type::Intersection) .map(Type::Callable),
}), Type::ProtocolInstance(protocol) => protocol
Type::Callable(callable) => visitor.try_visit(self, || { .recursive_type_normalized_impl(db, div, nested)
callable .map(Type::ProtocolInstance),
.recursive_type_normalized_impl(db, div, nested, visitor) Type::NominalInstance(instance) => instance
.map(Type::Callable) .recursive_type_normalized_impl(db, div, nested)
}), .map(Type::NominalInstance),
Type::ProtocolInstance(protocol) => visitor.try_visit(self, || { Type::FunctionLiteral(function) => function
protocol .recursive_type_normalized_impl(db, div, nested)
.recursive_type_normalized_impl(db, div, nested, visitor) .map(Type::FunctionLiteral),
.map(Type::ProtocolInstance) Type::PropertyInstance(property) => property
}), .recursive_type_normalized_impl(db, div, nested)
Type::NominalInstance(instance) => visitor.try_visit(self, || { .map(Type::PropertyInstance),
instance Type::KnownBoundMethod(method_kind) => method_kind
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.map(Type::NominalInstance) .map(Type::KnownBoundMethod),
}), Type::BoundMethod(method) => method
Type::FunctionLiteral(function) => visitor.try_visit(self, || { .recursive_type_normalized_impl(db, div, nested)
function .map(Type::BoundMethod),
.recursive_type_normalized_impl(db, div, nested, visitor) Type::BoundSuper(bound_super) => bound_super
.map(Type::FunctionLiteral) .recursive_type_normalized_impl(db, div, nested)
}), .map(Type::BoundSuper),
Type::PropertyInstance(property) => visitor.try_visit(self, || { Type::GenericAlias(generic) => generic
property .recursive_type_normalized_impl(db, div, nested)
.recursive_type_normalized_impl(db, div, nested, visitor) .map(Type::GenericAlias),
.map(Type::PropertyInstance) Type::SubclassOf(subclass_of) => subclass_of
}), .recursive_type_normalized_impl(db, div, nested)
Type::KnownBoundMethod(method_kind) => visitor.try_visit(self, || { .map(Type::SubclassOf),
method_kind
.recursive_type_normalized_impl(db, div, nested, visitor)
.map(Type::KnownBoundMethod)
}),
Type::BoundMethod(method) => visitor.try_visit(self, || {
method
.recursive_type_normalized_impl(db, div, nested, visitor)
.map(Type::BoundMethod)
}),
Type::BoundSuper(bound_super) => visitor.try_visit(self, || {
bound_super
.recursive_type_normalized_impl(db, div, nested, visitor)
.map(Type::BoundSuper)
}),
Type::GenericAlias(generic) => visitor.try_visit(self, || {
generic
.recursive_type_normalized_impl(db, div, nested, visitor)
.map(Type::GenericAlias)
}),
Type::SubclassOf(subclass_of) => visitor.try_visit(self, || {
subclass_of
.recursive_type_normalized_impl(db, div, nested, visitor)
.map(Type::SubclassOf)
}),
Type::TypeVar(_) => Some(self), Type::TypeVar(_) => Some(self),
Type::KnownInstance(known_instance) => visitor.try_visit(self, || { Type::KnownInstance(known_instance) => known_instance
known_instance .recursive_type_normalized_impl(db, div, nested)
.recursive_type_normalized_impl(db, div, nested, visitor) .map(Type::KnownInstance),
.map(Type::KnownInstance) Type::TypeIs(type_is) => {
}),
Type::TypeIs(type_is) => visitor.try_visit(self, || {
let ty = if nested { let ty = if nested {
type_is type_is
.return_type(db) .return_type(db)
.recursive_type_normalized_impl(db, div, true, visitor)? .recursive_type_normalized_impl(db, div, true)?
} else { } else {
type_is type_is
.return_type(db) .return_type(db)
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}; };
Some(type_is.with_type(db, ty)) Some(type_is.with_type(db, ty))
}), }
Type::Dynamic(dynamic) => Some(Type::Dynamic(dynamic.recursive_type_normalized())), Type::Dynamic(dynamic) => Some(Type::Dynamic(dynamic.recursive_type_normalized())),
Type::TypedDict(_) => { Type::TypedDict(_) => {
// TODO: Normalize TypedDicts // TODO: Normalize TypedDicts
Some(self) Some(self)
} }
Type::TypeAlias(_) => Some(self), Type::TypeAlias(_) => Some(self),
Type::NewTypeInstance(newtype) => visitor.try_visit(self, || { Type::NewTypeInstance(newtype) => newtype
newtype
.try_map_base_class_type(db, |class_type| { .try_map_base_class_type(db, |class_type| {
class_type.recursive_type_normalized_impl(db, div, nested, visitor) class_type.recursive_type_normalized_impl(db, div, nested)
}) })
.map(Type::NewTypeInstance) .map(Type::NewTypeInstance),
}),
Type::LiteralString Type::LiteralString
| Type::AlwaysFalsy | Type::AlwaysFalsy
| Type::AlwaysTruthy | Type::AlwaysTruthy
@ -8702,7 +8671,6 @@ impl<'db> KnownInstanceType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
// Nothing to normalize // Nothing to normalize
@ -8712,37 +8680,37 @@ impl<'db> KnownInstanceType<'db> {
Self::ConstraintSet(set) => Some(Self::ConstraintSet(set)), Self::ConstraintSet(set) => Some(Self::ConstraintSet(set)),
Self::TypeVar(typevar) => Some(Self::TypeVar(typevar)), Self::TypeVar(typevar) => Some(Self::TypeVar(typevar)),
Self::TypeAliasType(type_alias) => type_alias Self::TypeAliasType(type_alias) => type_alias
.recursive_type_normalized_impl(db, div, visitor) .recursive_type_normalized_impl(db, div)
.map(Self::TypeAliasType), .map(Self::TypeAliasType),
Self::Field(field) => field Self::Field(field) => field
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.map(Self::Field), .map(Self::Field),
Self::UnionType(union_type) => union_type Self::UnionType(union_type) => union_type
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.map(Self::UnionType), .map(Self::UnionType),
Self::Literal(ty) => ty Self::Literal(ty) => ty
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.map(Self::Literal), .map(Self::Literal),
Self::Annotated(ty) => ty Self::Annotated(ty) => ty
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.map(Self::Annotated), .map(Self::Annotated),
Self::TypeGenericAlias(ty) => ty Self::TypeGenericAlias(ty) => ty
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.map(Self::TypeGenericAlias), .map(Self::TypeGenericAlias),
Self::LiteralStringAlias(ty) => ty Self::LiteralStringAlias(ty) => ty
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.map(Self::LiteralStringAlias), .map(Self::LiteralStringAlias),
Self::Callable(callable) => callable Self::Callable(callable) => callable
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.map(Self::Callable), .map(Self::Callable),
Self::NewType(newtype) => newtype Self::NewType(newtype) => newtype
.try_map_base_class_type(db, |class_type| { .try_map_base_class_type(db, |class_type| {
class_type.recursive_type_normalized_impl(db, div, true, visitor) class_type.recursive_type_normalized_impl(db, div, true)
}) })
.map(Self::NewType), .map(Self::NewType),
Self::GenericContext(generic) => Some(Self::GenericContext(generic)), Self::GenericContext(generic) => Some(Self::GenericContext(generic)),
Self::Specialization(specialization) => specialization Self::Specialization(specialization) => specialization
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.map(Self::Specialization), .map(Self::Specialization),
} }
} }
@ -9231,15 +9199,12 @@ impl<'db> FieldInstance<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let default_type = match self.default_type(db) { let default_type = match self.default_type(db) {
Some(default) if nested => { Some(default) if nested => Some(default.recursive_type_normalized_impl(db, div, true)?),
Some(default.recursive_type_normalized_impl(db, div, true, visitor)?)
}
Some(default) => Some( Some(default) => Some(
default default
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -10184,7 +10149,6 @@ impl<'db> UnionTypeInstance<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
// The `Divergent` elimination rules are different within union types. // The `Divergent` elimination rules are different within union types.
// See `UnionType::recursive_type_normalized_impl` for details. // See `UnionType::recursive_type_normalized_impl` for details.
@ -10192,14 +10156,14 @@ impl<'db> UnionTypeInstance<'db> {
Some(types) if nested => Some( Some(types) if nested => Some(
types types
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, nested, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, nested))
.collect::<Option<Box<_>>>()?, .collect::<Option<Box<_>>>()?,
), ),
Some(types) => Some( Some(types) => Some(
types types
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, nested, visitor) ty.recursive_type_normalized_impl(db, div, nested)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect::<Box<_>>(), .collect::<Box<_>>(),
@ -10207,9 +10171,9 @@ impl<'db> UnionTypeInstance<'db> {
None => None, None => None,
}; };
let union_type = match self.union_type(db).clone() { let union_type = match self.union_type(db).clone() {
Ok(ty) if nested => Ok(ty.recursive_type_normalized_impl(db, div, nested, visitor)?), Ok(ty) if nested => Ok(ty.recursive_type_normalized_impl(db, div, nested)?),
Ok(ty) => Ok(ty Ok(ty) => Ok(ty
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.unwrap_or(div)), .unwrap_or(div)),
Err(err) => Err(err), Err(err) => Err(err),
}; };
@ -10241,14 +10205,13 @@ impl<'db> InternedType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let inner = if nested { let inner = if nested {
self.inner(db) self.inner(db)
.recursive_type_normalized_impl(db, div, nested, visitor)? .recursive_type_normalized_impl(db, div, nested)?
} else { } else {
self.inner(db) self.inner(db)
.recursive_type_normalized_impl(db, div, nested, visitor) .recursive_type_normalized_impl(db, div, nested)
.unwrap_or(div) .unwrap_or(div)
}; };
Some(InternedType::new(db, inner)) Some(InternedType::new(db, inner))
@ -11560,14 +11523,13 @@ impl<'db> BoundMethodType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self::new( Some(Self::new(
db, db,
self.function(db) self.function(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
self.self_instance(db) self.self_instance(db)
.recursive_type_normalized_impl(db, div, true, visitor)?, .recursive_type_normalized_impl(db, div, true)?,
)) ))
} }
@ -11732,12 +11694,11 @@ impl<'db> CallableType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(CallableType::new( Some(CallableType::new(
db, db,
self.signatures(db) self.signatures(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
self.is_function_like(db), self.is_function_like(db),
)) ))
} }
@ -12175,27 +12136,26 @@ impl<'db> KnownBoundMethodType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
KnownBoundMethodType::FunctionTypeDunderGet(function) => { KnownBoundMethodType::FunctionTypeDunderGet(function) => {
Some(KnownBoundMethodType::FunctionTypeDunderGet( Some(KnownBoundMethodType::FunctionTypeDunderGet(
function.recursive_type_normalized_impl(db, div, nested, visitor)?, function.recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
KnownBoundMethodType::FunctionTypeDunderCall(function) => { KnownBoundMethodType::FunctionTypeDunderCall(function) => {
Some(KnownBoundMethodType::FunctionTypeDunderCall( Some(KnownBoundMethodType::FunctionTypeDunderCall(
function.recursive_type_normalized_impl(db, div, nested, visitor)?, function.recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
KnownBoundMethodType::PropertyDunderGet(property) => { KnownBoundMethodType::PropertyDunderGet(property) => {
Some(KnownBoundMethodType::PropertyDunderGet( Some(KnownBoundMethodType::PropertyDunderGet(
property.recursive_type_normalized_impl(db, div, nested, visitor)?, property.recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
KnownBoundMethodType::PropertyDunderSet(property) => { KnownBoundMethodType::PropertyDunderSet(property) => {
Some(KnownBoundMethodType::PropertyDunderSet( Some(KnownBoundMethodType::PropertyDunderSet(
property.recursive_type_normalized_impl(db, div, nested, visitor)?, property.recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
KnownBoundMethodType::StrStartswith(_) KnownBoundMethodType::StrStartswith(_)
@ -12858,18 +12818,14 @@ impl<'db> ManualPEP695TypeAliasType<'db> {
) )
} }
fn recursive_type_normalized_impl( // TODO: with full support for manual PEP-695 style type aliases, this method should become unnecessary.
self, fn recursive_type_normalized_impl(self, db: &'db dyn Db, div: Type<'db>) -> Option<Self> {
db: &'db dyn Db,
div: Type<'db>,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> {
Some(Self::new( Some(Self::new(
db, db,
self.name(db), self.name(db),
self.definition(db), self.definition(db),
self.value(db) self.value(db)
.recursive_type_normalized_impl(db, div, true, visitor)?, .recursive_type_normalized_impl(db, div, true)?,
)) ))
} }
} }
@ -12914,16 +12870,11 @@ impl<'db> TypeAliasType<'db> {
} }
} }
fn recursive_type_normalized_impl( fn recursive_type_normalized_impl(self, db: &'db dyn Db, div: Type<'db>) -> Option<Self> {
self,
db: &'db dyn Db,
div: Type<'db>,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> {
match self { match self {
TypeAliasType::PEP695(type_alias) => Some(TypeAliasType::PEP695(type_alias)), TypeAliasType::PEP695(type_alias) => Some(TypeAliasType::PEP695(type_alias)),
TypeAliasType::ManualPEP695(type_alias) => Some(TypeAliasType::ManualPEP695( TypeAliasType::ManualPEP695(type_alias) => Some(TypeAliasType::ManualPEP695(
type_alias.recursive_type_normalized_impl(db, div, visitor)?, type_alias.recursive_type_normalized_impl(db, div)?,
)), )),
} }
} }
@ -13248,7 +13199,6 @@ impl<'db> UnionType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Type<'db>> { ) -> Option<Type<'db>> {
let mut builder = UnionBuilder::new(db) let mut builder = UnionBuilder::new(db)
.order_elements(false) .order_elements(false)
@ -13258,7 +13208,7 @@ impl<'db> UnionType<'db> {
for ty in self.elements(db) { for ty in self.elements(db) {
if nested { if nested {
// list[T | Divergent] => list[Divergent] // list[T | Divergent] => list[Divergent]
let ty = ty.recursive_type_normalized_impl(db, div, nested, visitor)?; let ty = ty.recursive_type_normalized_impl(db, div, nested)?;
if ty == div { if ty == div {
return Some(ty); return Some(ty);
} }
@ -13271,7 +13221,7 @@ impl<'db> UnionType<'db> {
continue; continue;
} }
builder = builder.add( builder = builder.add(
ty.recursive_type_normalized_impl(db, div, nested, visitor) ty.recursive_type_normalized_impl(db, div, nested)
.unwrap_or(div), .unwrap_or(div),
); );
empty = false; empty = false;
@ -13389,18 +13339,16 @@ impl<'db> IntersectionType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
fn opt_normalized_set<'db>( fn opt_normalized_set<'db>(
db: &'db dyn Db, db: &'db dyn Db,
elements: &FxOrderSet<Type<'db>>, elements: &FxOrderSet<Type<'db>>,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<FxOrderSet<Type<'db>>> { ) -> Option<FxOrderSet<Type<'db>>> {
elements elements
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, nested, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, nested))
.collect() .collect()
} }
@ -13409,26 +13357,25 @@ impl<'db> IntersectionType<'db> {
elements: &FxOrderSet<Type<'db>>, elements: &FxOrderSet<Type<'db>>,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> FxOrderSet<Type<'db>> { ) -> FxOrderSet<Type<'db>> {
elements elements
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, nested, visitor) ty.recursive_type_normalized_impl(db, div, nested)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect() .collect()
} }
let positive = if nested { let positive = if nested {
opt_normalized_set(db, self.positive(db), div, nested, visitor)? opt_normalized_set(db, self.positive(db), div, nested)?
} else { } else {
normalized_set(db, self.positive(db), div, nested, visitor) normalized_set(db, self.positive(db), div, nested)
}; };
let negative = if nested { let negative = if nested {
opt_normalized_set(db, self.negative(db), div, nested, visitor)? opt_normalized_set(db, self.negative(db), div, nested)?
} else { } else {
normalized_set(db, self.negative(db), div, nested, visitor) normalized_set(db, self.negative(db), div, nested)
}; };
Some(IntersectionType::new(db, positive, negative)) Some(IntersectionType::new(db, positive, negative))
@ -13911,16 +13858,15 @@ pub(crate) mod tests {
nested_rec.display(&db).to_string(), nested_rec.display(&db).to_string(),
"list[list[Divergent] | None]" "list[list[Divergent] | None]"
); );
let visitor = NormalizedVisitor::default();
let normalized = nested_rec let normalized = nested_rec
.recursive_type_normalized_impl(&db, div, false, &visitor) .recursive_type_normalized_impl(&db, div, false)
.unwrap(); .unwrap();
assert_eq!(normalized.display(&db).to_string(), "list[Divergent]"); assert_eq!(normalized.display(&db).to_string(), "list[Divergent]");
let union = UnionType::from_elements(&db, [div, KnownClass::Int.to_instance(&db)]); let union = UnionType::from_elements(&db, [div, KnownClass::Int.to_instance(&db)]);
assert_eq!(union.display(&db).to_string(), "Divergent | int"); assert_eq!(union.display(&db).to_string(), "Divergent | int");
let normalized = union let normalized = union
.recursive_type_normalized_impl(&db, div, false, &visitor) .recursive_type_normalized_impl(&db, div, false)
.unwrap(); .unwrap();
assert_eq!(normalized.display(&db).to_string(), "int"); assert_eq!(normalized.display(&db).to_string(), "int");

View File

@ -197,17 +197,16 @@ impl<'db> SuperOwnerKind<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
SuperOwnerKind::Dynamic(dynamic) => { SuperOwnerKind::Dynamic(dynamic) => {
Some(SuperOwnerKind::Dynamic(dynamic.recursive_type_normalized())) Some(SuperOwnerKind::Dynamic(dynamic.recursive_type_normalized()))
} }
SuperOwnerKind::Class(class) => Some(SuperOwnerKind::Class( SuperOwnerKind::Class(class) => Some(SuperOwnerKind::Class(
class.recursive_type_normalized_impl(db, div, nested, visitor)?, class.recursive_type_normalized_impl(db, div, nested)?,
)), )),
SuperOwnerKind::Instance(instance) => Some(SuperOwnerKind::Instance( SuperOwnerKind::Instance(instance) => Some(SuperOwnerKind::Instance(
instance.recursive_type_normalized_impl(db, div, nested, visitor)?, instance.recursive_type_normalized_impl(db, div, nested)?,
)), )),
} }
} }
@ -620,14 +619,13 @@ impl<'db> BoundSuperType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self::new( Some(Self::new(
db, db,
self.pivot_class(db) self.pivot_class(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
self.owner(db) self.owner(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
} }

View File

@ -284,13 +284,12 @@ impl<'db> GenericAlias<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self::new( Some(Self::new(
db, db,
self.origin(db), self.origin(db),
self.specialization(db) self.specialization(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
@ -443,12 +442,11 @@ impl<'db> ClassType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
Self::NonGeneric(_) => Some(self), Self::NonGeneric(_) => Some(self),
Self::Generic(generic) => Some(Self::Generic( Self::Generic(generic) => Some(Self::Generic(
generic.recursive_type_normalized_impl(db, div, nested, visitor)?, generic.recursive_type_normalized_impl(db, div, nested)?,
)), )),
} }
} }

View File

@ -48,12 +48,11 @@ impl<'db> ClassBase<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
Self::Dynamic(dynamic) => Some(Self::Dynamic(dynamic.recursive_type_normalized())), Self::Dynamic(dynamic) => Some(Self::Dynamic(dynamic.recursive_type_normalized())),
Self::Class(class) => Some(Self::Class( Self::Class(class) => Some(Self::Class(
class.recursive_type_normalized_impl(db, div, nested, visitor)?, class.recursive_type_normalized_impl(db, div, nested)?,
)), )),
Self::Protocol | Self::Generic | Self::TypedDict => Some(self), Self::Protocol | Self::Generic | Self::TypedDict => Some(self),
} }

View File

@ -1112,19 +1112,14 @@ impl<'db> FunctionType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let literal = self.literal(db); let literal = self.literal(db);
let updated_signature = match self.updated_signature(db) { let updated_signature = match self.updated_signature(db) {
Some(signature) => { Some(signature) => Some(signature.recursive_type_normalized_impl(db, div, nested)?),
Some(signature.recursive_type_normalized_impl(db, div, nested, visitor)?)
}
None => None, None => None,
}; };
let updated_last_definition_signature = match self.updated_last_definition_signature(db) { let updated_last_definition_signature = match self.updated_last_definition_signature(db) {
Some(signature) => { Some(signature) => Some(signature.recursive_type_normalized_impl(db, div, nested)?),
Some(signature.recursive_type_normalized_impl(db, div, nested, visitor)?)
}
None => None, None => None,
}; };
Some(Self::new( Some(Self::new(

View File

@ -1045,24 +1045,23 @@ impl<'db> Specialization<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let types = if nested { let types = if nested {
self.types(db) self.types(db)
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, true, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, true))
.collect::<Option<Box<[_]>>>()? .collect::<Option<Box<[_]>>>()?
} else { } else {
self.types(db) self.types(db)
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect::<Box<[_]>>() .collect::<Box<[_]>>()
}; };
let tuple_inner = match self.tuple_inner(db) { let tuple_inner = match self.tuple_inner(db) {
Some(tuple) => Some(tuple.recursive_type_normalized_impl(db, div, nested, visitor)?), Some(tuple) => Some(tuple.recursive_type_normalized_impl(db, div, nested)?),
None => None, None => None,
}; };
let context = self.generic_context(db); let context = self.generic_context(db);

View File

@ -379,16 +379,15 @@ impl<'db> NominalInstanceType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self.0 { match self.0 {
NominalInstanceInner::ExactTuple(tuple) => { NominalInstanceInner::ExactTuple(tuple) => {
Some(Self(NominalInstanceInner::ExactTuple( Some(Self(NominalInstanceInner::ExactTuple(
tuple.recursive_type_normalized_impl(db, div, nested, visitor)?, tuple.recursive_type_normalized_impl(db, div, nested)?,
))) )))
} }
NominalInstanceInner::NonTuple(class) => Some(Self(NominalInstanceInner::NonTuple( NominalInstanceInner::NonTuple(class) => Some(Self(NominalInstanceInner::NonTuple(
class.recursive_type_normalized_impl(db, div, nested, visitor)?, class.recursive_type_normalized_impl(db, div, nested)?,
))), ))),
NominalInstanceInner::Object => Some(Self(NominalInstanceInner::Object)), NominalInstanceInner::Object => Some(Self(NominalInstanceInner::Object)),
} }
@ -750,12 +749,9 @@ impl<'db> ProtocolInstanceType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self { Some(Self {
inner: self inner: self.inner.recursive_type_normalized_impl(db, div, nested)?,
.inner
.recursive_type_normalized_impl(db, div, nested, visitor)?,
_phantom: PhantomData, _phantom: PhantomData,
}) })
} }
@ -877,14 +873,13 @@ impl<'db> Protocol<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
Self::FromClass(class) => Some(Self::FromClass( Self::FromClass(class) => Some(Self::FromClass(
class.recursive_type_normalized_impl(db, div, nested, visitor)?, class.recursive_type_normalized_impl(db, div, nested)?,
)), )),
Self::Synthesized(synthesized) => Some(Self::Synthesized( Self::Synthesized(synthesized) => Some(Self::Synthesized(
synthesized.recursive_type_normalized_impl(db, div, nested, visitor)?, synthesized.recursive_type_normalized_impl(db, div, nested)?,
)), )),
} }
} }
@ -963,11 +958,9 @@ mod synthesized_protocol {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self( Some(Self(
self.0 self.0.recursive_type_normalized_impl(db, div, nested)?,
.recursive_type_normalized_impl(db, div, nested, visitor)?,
)) ))
} }
} }

View File

@ -150,11 +150,9 @@ impl<'db> ProtocolClass<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self( Some(Self(
self.0 self.0.recursive_type_normalized_impl(db, div, nested)?,
.recursive_type_normalized_impl(db, div, nested, visitor)?,
)) ))
} }
} }
@ -386,7 +384,6 @@ impl<'db> ProtocolInterface<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self::new( Some(Self::new(
db, db,
@ -395,7 +392,7 @@ impl<'db> ProtocolInterface<'db> {
.map(|(name, data)| { .map(|(name, data)| {
Some(( Some((
name.clone(), name.clone(),
data.recursive_type_normalized_impl(db, div, nested, visitor)?, data.recursive_type_normalized_impl(db, div, nested)?,
)) ))
}) })
.collect::<Option<BTreeMap<_, _>>>()?, .collect::<Option<BTreeMap<_, _>>>()?,
@ -498,21 +495,20 @@ impl<'db> ProtocolMemberData<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self { Some(Self {
kind: match &self.kind { kind: match &self.kind {
ProtocolMemberKind::Method(callable) => ProtocolMemberKind::Method( ProtocolMemberKind::Method(callable) => ProtocolMemberKind::Method(
callable.recursive_type_normalized_impl(db, div, nested, visitor)?, callable.recursive_type_normalized_impl(db, div, nested)?,
), ),
ProtocolMemberKind::Property(property) => ProtocolMemberKind::Property( ProtocolMemberKind::Property(property) => ProtocolMemberKind::Property(
property.recursive_type_normalized_impl(db, div, nested, visitor)?, property.recursive_type_normalized_impl(db, div, nested)?,
),
ProtocolMemberKind::Other(ty) if nested => ProtocolMemberKind::Other(
ty.recursive_type_normalized_impl(db, div, true, visitor)?,
), ),
ProtocolMemberKind::Other(ty) if nested => {
ProtocolMemberKind::Other(ty.recursive_type_normalized_impl(db, div, true)?)
}
ProtocolMemberKind::Other(ty) => ProtocolMemberKind::Other( ProtocolMemberKind::Other(ty) => ProtocolMemberKind::Other(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
}, },

View File

@ -179,13 +179,12 @@ impl<'db> CallableSignature<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self { Some(Self {
overloads: self overloads: self
.overloads .overloads
.iter() .iter()
.map(|signature| signature.recursive_type_normalized_impl(db, div, nested, visitor)) .map(|signature| signature.recursive_type_normalized_impl(db, div, nested))
.collect::<Option<SmallVec<_>>>()?, .collect::<Option<SmallVec<_>>>()?,
}) })
} }
@ -575,15 +574,14 @@ impl<'db> Signature<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let return_ty = match self.return_ty { let return_ty = match self.return_ty {
Some(return_ty) if nested => { Some(return_ty) if nested => {
Some(return_ty.recursive_type_normalized_impl(db, div, true, visitor)?) Some(return_ty.recursive_type_normalized_impl(db, div, true)?)
} }
Some(return_ty) => Some( Some(return_ty) => Some(
return_ty return_ty
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -591,7 +589,7 @@ impl<'db> Signature<'db> {
let parameters = { let parameters = {
let mut parameters = Vec::with_capacity(self.parameters.len()); let mut parameters = Vec::with_capacity(self.parameters.len());
for param in &self.parameters { for param in &self.parameters {
parameters.push(param.recursive_type_normalized_impl(db, div, nested, visitor)?); parameters.push(param.recursive_type_normalized_impl(db, div, nested)?);
} }
Parameters::new(db, parameters) Parameters::new(db, parameters)
}; };
@ -1906,7 +1904,6 @@ impl<'db> Parameter<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let Parameter { let Parameter {
annotated_type, annotated_type,
@ -1916,9 +1913,9 @@ impl<'db> Parameter<'db> {
} = self; } = self;
let annotated_type = match annotated_type { let annotated_type = match annotated_type {
Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?), Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true)?),
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -1928,11 +1925,9 @@ impl<'db> Parameter<'db> {
ParameterKind::PositionalOnly { name, default_type } => ParameterKind::PositionalOnly { ParameterKind::PositionalOnly { name, default_type } => ParameterKind::PositionalOnly {
name: name.clone(), name: name.clone(),
default_type: match default_type { default_type: match default_type {
Some(ty) if nested => { Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true)?),
Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?)
}
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -1943,10 +1938,10 @@ impl<'db> Parameter<'db> {
name: name.clone(), name: name.clone(),
default_type: match default_type { default_type: match default_type {
Some(ty) if nested => { Some(ty) if nested => {
Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?) Some(ty.recursive_type_normalized_impl(db, div, true)?)
} }
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,
@ -1956,11 +1951,9 @@ impl<'db> Parameter<'db> {
ParameterKind::KeywordOnly { name, default_type } => ParameterKind::KeywordOnly { ParameterKind::KeywordOnly { name, default_type } => ParameterKind::KeywordOnly {
name: name.clone(), name: name.clone(),
default_type: match default_type { default_type: match default_type {
Some(ty) if nested => { Some(ty) if nested => Some(ty.recursive_type_normalized_impl(db, div, true)?),
Some(ty.recursive_type_normalized_impl(db, div, true, visitor)?)
}
Some(ty) => Some( Some(ty) => Some(
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div), .unwrap_or(div),
), ),
None => None, None => None,

View File

@ -272,12 +272,11 @@ impl<'db> SubclassOfType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self { Some(Self {
subclass_of: self subclass_of: self
.subclass_of .subclass_of
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
}) })
} }
@ -449,11 +448,10 @@ impl<'db> SubclassOfInner<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
Self::Class(class) => Some(Self::Class( Self::Class(class) => Some(Self::Class(
class.recursive_type_normalized_impl(db, div, nested, visitor)?, class.recursive_type_normalized_impl(db, div, nested)?,
)), )),
Self::Dynamic(dynamic) => Some(Self::Dynamic(dynamic.recursive_type_normalized())), Self::Dynamic(dynamic) => Some(Self::Dynamic(dynamic.recursive_type_normalized())),
Self::TypeVar(_) => Some(self), Self::TypeVar(_) => Some(self),

View File

@ -234,12 +234,11 @@ impl<'db> TupleType<'db> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
Some(Self::new_internal( Some(Self::new_internal(
db, db,
self.tuple(db) self.tuple(db)
.recursive_type_normalized_impl(db, div, nested, visitor)?, .recursive_type_normalized_impl(db, div, nested)?,
)) ))
} }
@ -411,13 +410,12 @@ impl<'db> FixedLengthTuple<Type<'db>> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
if nested { if nested {
Some(Self::from_elements( Some(Self::from_elements(
self.0 self.0
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, true, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, true))
.collect::<Option<Box<[_]>>>()?, .collect::<Option<Box<[_]>>>()?,
)) ))
} else { } else {
@ -425,7 +423,7 @@ impl<'db> FixedLengthTuple<Type<'db>> {
self.0 self.0
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect::<Box<[_]>>(), .collect::<Box<[_]>>(),
@ -804,18 +802,17 @@ impl<'db> VariableLengthTuple<Type<'db>> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
let prefix = if nested { let prefix = if nested {
self.prefix self.prefix
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, true, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, true))
.collect::<Option<Box<_>>>()? .collect::<Option<Box<_>>>()?
} else { } else {
self.prefix self.prefix
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect::<Box<_>>() .collect::<Box<_>>()
@ -823,23 +820,23 @@ impl<'db> VariableLengthTuple<Type<'db>> {
let suffix = if nested { let suffix = if nested {
self.suffix self.suffix
.iter() .iter()
.map(|ty| ty.recursive_type_normalized_impl(db, div, true, visitor)) .map(|ty| ty.recursive_type_normalized_impl(db, div, true))
.collect::<Option<Box<_>>>()? .collect::<Option<Box<_>>>()?
} else { } else {
self.suffix self.suffix
.iter() .iter()
.map(|ty| { .map(|ty| {
ty.recursive_type_normalized_impl(db, div, true, visitor) ty.recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}) })
.collect::<Box<_>>() .collect::<Box<_>>()
}; };
let variable = if nested { let variable = if nested {
self.variable self.variable
.recursive_type_normalized_impl(db, div, true, visitor)? .recursive_type_normalized_impl(db, div, true)?
} else { } else {
self.variable self.variable
.recursive_type_normalized_impl(db, div, true, visitor) .recursive_type_normalized_impl(db, div, true)
.unwrap_or(div) .unwrap_or(div)
}; };
Some(Self { Some(Self {
@ -1250,14 +1247,13 @@ impl<'db> Tuple<Type<'db>> {
db: &'db dyn Db, db: &'db dyn Db,
div: Type<'db>, div: Type<'db>,
nested: bool, nested: bool,
visitor: &NormalizedVisitor<'db>,
) -> Option<Self> { ) -> Option<Self> {
match self { match self {
Tuple::Fixed(tuple) => Some(Tuple::Fixed( Tuple::Fixed(tuple) => Some(Tuple::Fixed(
tuple.recursive_type_normalized_impl(db, div, nested, visitor)?, tuple.recursive_type_normalized_impl(db, div, nested)?,
)), )),
Tuple::Variable(tuple) => Some(Tuple::Variable( Tuple::Variable(tuple) => Some(Tuple::Variable(
tuple.recursive_type_normalized_impl(db, div, nested, visitor)?, tuple.recursive_type_normalized_impl(db, div, nested)?,
)), )),
} }
} }