From 048cf419a42f5704a928f577a0e28b4429160b9f Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Sun, 7 Dec 2025 16:27:22 -0500 Subject: [PATCH] Revert "break recursion cycle" This reverts commit ee682514078f02d1a7b77e1038cb34dafd7a6777. --- crates/ty_python_semantic/src/types.rs | 35 ++++++++----------- .../src/types/infer/builder.rs | 6 ++-- .../src/types/signatures.rs | 12 ++++--- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 0f89a63a91..23f7a53f79 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -7595,15 +7595,11 @@ impl<'db> Type<'db> { tcx: TypeContext<'db>, visitor: &ApplyTypeMappingVisitor<'db>, ) -> Type<'db> { + // If we are binding `typing.Self`, and this type is what we are binding `Self` to, return + // early. This is not just an optimization, it also prevents us from infinitely expanding + // the type, if it's something that can contain a `Self` reference. match type_mapping { - // If we are binding `typing.Self`, and this type is what we are binding `Self` to, return - // early. This is not just an optimization, it also prevents us from infinitely expanding - // the type, if it's something that can contain a `Self` reference. TypeMapping::BindSelf { self_type, .. } if self == *self_type => return self, - - // If we are breaking a recursive type, look for that before expanding this type. - TypeMapping::BreakRecursionCycle(target) if self == *target => return Type::unknown(), - _ => {} } @@ -7622,7 +7618,7 @@ impl<'db> Type<'db> { TypeMapping::BindSelf { .. } | TypeMapping::ReplaceSelf { .. } | TypeMapping::Materialize(_) | - TypeMapping::BreakRecursionCycle(_) | + TypeMapping::ReplaceParameterDefaults | TypeMapping::EagerExpansion => self, } } @@ -7798,7 +7794,7 @@ impl<'db> Type<'db> { TypeMapping::BindSelf { .. } | TypeMapping::ReplaceSelf { .. } | TypeMapping::Materialize(_) | - TypeMapping::BreakRecursionCycle(_) | + TypeMapping::ReplaceParameterDefaults | TypeMapping::EagerExpansion | TypeMapping::PromoteLiterals(PromoteLiteralsMode::Off) => self, TypeMapping::PromoteLiterals(PromoteLiteralsMode::On) => self.promote_literals_impl(db, tcx) @@ -7811,7 +7807,7 @@ impl<'db> Type<'db> { TypeMapping::BindSelf { .. } | TypeMapping::ReplaceSelf { .. } | TypeMapping::PromoteLiterals(_) | - TypeMapping::BreakRecursionCycle(_) | + TypeMapping::ReplaceParameterDefaults | TypeMapping::EagerExpansion => self, TypeMapping::Materialize(materialization_kind) => match materialization_kind { MaterializationKind::Top => Type::object(), @@ -8088,12 +8084,11 @@ impl<'db> Type<'db> { .find_legacy_typevars(db, None, variables); } - /// Looks for any recursive references to this type inside of itself, replacing them with - /// `Unknown`. - pub(crate) fn break_recursion_cycle(self, db: &'db dyn Db) -> Type<'db> { + /// Replace default types in parameters of callables with `Unknown`. + pub(crate) fn replace_parameter_defaults(self, db: &'db dyn Db) -> Type<'db> { self.apply_type_mapping( db, - &TypeMapping::BreakRecursionCycle(self), + &TypeMapping::ReplaceParameterDefaults, TypeContext::default(), ) } @@ -8533,9 +8528,9 @@ pub enum TypeMapping<'a, 'db> { ReplaceSelf { new_upper_bound: Type<'db> }, /// Create the top or bottom materialization of a type. Materialize(MaterializationKind), - /// Looks for any recursive references to a type inside of itself, replacing them with - /// `Unknown`. - BreakRecursionCycle(Type<'db>), + /// Replace default types in parameters of callables with `Unknown`. This is used to avoid infinite + /// recursion when the type of the default value of a parameter depends on the callable itself. + ReplaceParameterDefaults, /// Apply eager expansion to the type. /// In the case of recursive type aliases, this will diverge, so that part will be replaced with `Divergent`. EagerExpansion, @@ -8554,7 +8549,7 @@ impl<'db> TypeMapping<'_, 'db> { | TypeMapping::PromoteLiterals(_) | TypeMapping::BindLegacyTypevars(_) | TypeMapping::Materialize(_) - | TypeMapping::BreakRecursionCycle(_) + | TypeMapping::ReplaceParameterDefaults | TypeMapping::EagerExpansion => context, TypeMapping::BindSelf { binding_context, .. @@ -8588,7 +8583,7 @@ impl<'db> TypeMapping<'_, 'db> { | TypeMapping::BindLegacyTypevars(_) | TypeMapping::BindSelf { .. } | TypeMapping::ReplaceSelf { .. } - | TypeMapping::BreakRecursionCycle(_) + | TypeMapping::ReplaceParameterDefaults | TypeMapping::EagerExpansion => self.clone(), } } @@ -10185,7 +10180,7 @@ impl<'db> BoundTypeVarInstance<'db> { } } TypeMapping::PromoteLiterals(_) - | TypeMapping::BreakRecursionCycle(_) + | TypeMapping::ReplaceParameterDefaults | TypeMapping::BindLegacyTypevars(_) | TypeMapping::EagerExpansion => Type::TypeVar(self), TypeMapping::Materialize(materialization_kind) => { diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 3d7135bfa9..103c159538 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -8248,7 +8248,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { if let Some(default) = param.default() { parameter = parameter.with_default_type( self.infer_expression(default, TypeContext::default()) - .break_recursion_cycle(self.db()), + .replace_parameter_defaults(self.db()), ); } parameter @@ -8262,7 +8262,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { if let Some(default) = param.default() { parameter = parameter.with_default_type( self.infer_expression(default, TypeContext::default()) - .break_recursion_cycle(self.db()), + .replace_parameter_defaults(self.db()), ); } parameter @@ -8280,7 +8280,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { if let Some(default) = param.default() { parameter = parameter.with_default_type( self.infer_expression(default, TypeContext::default()) - .break_recursion_cycle(self.db()), + .replace_parameter_defaults(self.db()), ); } parameter diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 54e4d630d8..fe1f9e41b2 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -544,7 +544,7 @@ impl<'db> Signature<'db> { defaults .next() .expect("should have optional default for each non-variadic parameter") - .map(|ty| ty.break_recursion_cycle(db)) + .map(|ty| ty.replace_parameter_defaults(db)) }); } let mut parameters = Parameters::new(db, inferred_signature.parameters); @@ -2202,9 +2202,13 @@ impl<'db> ParameterKind<'db> { visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { let apply_to_default_type = |default_type: &Option>| { - default_type - .as_ref() - .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, tcx, visitor)) + if type_mapping == &TypeMapping::ReplaceParameterDefaults && default_type.is_some() { + Some(Type::unknown()) + } else { + default_type + .as_ref() + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, tcx, visitor)) + } }; match self {