This commit is contained in:
Ibraheem Ahmed 2025-12-17 21:05:54 -05:00
parent 58160c3d67
commit 14f554b453
3 changed files with 27 additions and 57 deletions

View File

@ -3921,82 +3921,54 @@ impl<'db> Type<'db> {
where
F: FnMut(BoundTypeVarInstance<'db>, Type<'db>, TypeVarVariance, TypeContext<'db>),
{
let try_visit = &mut |type_var, ty, variance, tcx| -> Result<(), ()> {
f(type_var, ty, variance, tcx);
Ok(())
};
let _ = self.try_visit_specialization(db, tcx, try_visit);
}
pub(crate) fn try_visit_specialization<F, E>(
self,
db: &'db dyn Db,
tcx: TypeContext<'db>,
mut f: F,
) -> Result<(), E>
where
F: FnMut(
BoundTypeVarInstance<'db>,
Type<'db>,
TypeVarVariance,
TypeContext<'db>,
) -> Result<(), E>,
{
self.try_visit_specialization_impl(
self.visit_specialization_impl(
db,
tcx,
TypeVarVariance::Covariant,
&mut f,
&SpecializationVisitor::default(),
)
);
}
fn try_visit_specialization_impl<E>(
fn visit_specialization_impl(
self,
db: &'db dyn Db,
tcx: TypeContext<'db>,
polarity: TypeVarVariance,
f: &mut dyn FnMut(
BoundTypeVarInstance<'db>,
Type<'db>,
TypeVarVariance,
TypeContext<'db>,
) -> Result<(), E>,
f: &mut dyn FnMut(BoundTypeVarInstance<'db>, Type<'db>, TypeVarVariance, TypeContext<'db>),
visitor: &SpecializationVisitor<'db>,
) -> Result<(), E> {
) {
let instance = match self {
Type::Union(union) => {
for element in union.elements(db) {
element.try_visit_specialization_impl(db, tcx, polarity, f, visitor)?;
element.visit_specialization_impl(db, tcx, polarity, f, visitor);
}
return Ok(());
return;
}
Type::Intersection(intersection) => {
for element in intersection.positive(db) {
element.try_visit_specialization_impl(db, tcx, polarity, f, visitor)?;
element.visit_specialization_impl(db, tcx, polarity, f, visitor);
}
return Ok(());
return;
}
Type::TypeAlias(alias) => {
visitor.try_visit(self, || {
visitor.visit(self, || {
alias
.value_type(db)
.try_visit_specialization_impl(db, tcx, polarity, f, visitor)
})?;
return Ok(());
.visit_specialization_impl(db, tcx, polarity, f, visitor);
});
return;
}
Type::NominalInstance(instance) => instance,
Type::ProtocolInstance(protocol) => match protocol.to_nominal_instance() {
Some(instance) => instance,
None => return Ok(()),
None => return,
},
_ => return Ok(()),
_ => return,
};
let (class_literal, Some(specialization)) = instance.class(db).class_literal(db) else {
return Ok(());
return;
};
let generic_context = specialization.generic_context(db);
@ -4017,14 +3989,12 @@ impl<'db> Type<'db> {
let variance = type_var.variance_with_polarity(db, polarity);
let narrowed_tcx = TypeContext::new(tcx_mappings.get(&type_var.identity(db)).copied());
f(type_var, *ty, variance, narrowed_tcx)?;
f(type_var, *ty, variance, narrowed_tcx);
visitor.try_visit(*ty, || {
ty.try_visit_specialization_impl(db, narrowed_tcx, variance, f, visitor)
})?;
visitor.visit(*ty, || {
ty.visit_specialization_impl(db, narrowed_tcx, variance, f, visitor);
});
}
Ok(())
}
/// Return true if there is just a single inhabitant for this type.

View File

@ -122,14 +122,14 @@ impl<Tag, T: Hash + Eq + Clone, R: Clone> CycleDetector<Tag, T, R> {
ret
}
pub fn try_visit<E>(&self, item: T, func: impl FnOnce() -> Result<R, E>) -> Result<R, E> {
pub fn try_visit(&self, item: T, func: impl FnOnce() -> Option<R>) -> Option<R> {
if let Some(val) = self.cache.borrow().get(&item) {
return Ok(val.clone());
return Some(val.clone());
}
// We hit a cycle
if !self.seen.borrow_mut().insert(item.clone()) {
return Ok(self.fallback.clone());
return Some(self.fallback.clone());
}
// Check depth limit to prevent stack overflow from recursive generic protocols
@ -137,7 +137,7 @@ impl<Tag, T: Hash + Eq + Clone, R: Clone> CycleDetector<Tag, T, R> {
let current_depth = self.depth.get();
if current_depth >= MAX_RECURSION_DEPTH {
self.seen.borrow_mut().pop();
return Ok(self.fallback.clone());
return Some(self.fallback.clone());
}
self.depth.set(current_depth + 1);
@ -147,7 +147,7 @@ impl<Tag, T: Hash + Eq + Clone, R: Clone> CycleDetector<Tag, T, R> {
self.seen.borrow_mut().pop();
self.cache.borrow_mut().insert(item, ret.clone());
Ok(ret)
Some(ret)
}
}

View File

@ -1926,14 +1926,14 @@ impl<'db> SpecializationBuilder<'db> {
builder.infer(formal_identity, formal)?;
}
builder.type_mappings().clone()
builder.into_type_mappings()
};
// Collect the actual type to which each formal type variable is mapped.
let forward_type_mappings = {
let mut builder = SpecializationBuilder::new(self.db, inferable);
builder.infer(formal_identity, actual)?;
builder.type_mappings().clone()
builder.into_type_mappings()
};
// If there are no forward type mappings, try the other direction.