From 26b8b794fb5bdc1fede16ca580a6f93dbf274aef Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 12 Sep 2025 01:59:39 +0900 Subject: [PATCH] fix: Infinite loop while elaborting predicates --- crates/hir-ty/src/dyn_compatibility.rs | 3 ++ crates/hir-ty/src/dyn_compatibility/tests.rs | 3 +- crates/hir-ty/src/lower_nextsolver.rs | 3 ++ crates/hir-ty/src/next_solver/interner.rs | 23 +++++++++++++- .../hir-ty/src/tests/regression/new_solver.rs | 31 +++++++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index d4b3751cf5..b87c998217 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -138,6 +138,9 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b let interner = DbInterner::new_with(db, Some(krate), None); let predicates = db.generic_predicates_ns(def); + // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to + // rust-analyzer yet + // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490 elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| { match pred.kind().skip_binder() { ClauseKind::Trait(trait_pred) => { diff --git a/crates/hir-ty/src/dyn_compatibility/tests.rs b/crates/hir-ty/src/dyn_compatibility/tests.rs index 4ffa455084..04a9ba7992 100644 --- a/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -253,7 +253,8 @@ trait Bar { trait Baz : Bar { } "#, - [("Bar", vec![]), ("Baz", vec![SizedSelf, SelfReferential])], + // FIXME: We should also report `SizedSelf` here + [("Bar", vec![]), ("Baz", vec![SelfReferential])], ); } diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs index c6a8fa81ed..5c29befe12 100644 --- a/crates/hir-ty/src/lower_nextsolver.rs +++ b/crates/hir-ty/src/lower_nextsolver.rs @@ -1358,6 +1358,9 @@ where } } + // FIXME: rustc gathers more predicates by recursing through resulting trait predicates. + // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715 + ( GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), create_diagnostics(ctx.diagnostics), diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 0f512fdaf8..7b6e8a1073 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -5,7 +5,7 @@ use base_db::Crate; use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; use hir_def::lang_item::LangItem; use hir_def::signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}; -use hir_def::{AdtId, BlockId, TypeAliasId, VariantId}; +use hir_def::{AdtId, BlockId, GenericDefId, TypeAliasId, VariantId}; use hir_def::{AttrDefId, Lookup}; use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId}; use intern::sym::non_exhaustive; @@ -1334,6 +1334,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .db() .generic_predicates_ns(def_id.0.into()) .iter() + .filter(|p| match p.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(tr) => match tr.self_ty().kind() { + rustc_type_ir::TyKind::Param(param) => param.index == 0, + _ => false, + }, + _ => true, + }) .cloned() .map(|p| (p, Span::dummy())) .collect(); @@ -1345,10 +1352,24 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { + fn is_self_or_assoc(ty: Ty<'_>) -> bool { + match ty.kind() { + rustc_type_ir::TyKind::Param(param) => param.index == 0, + rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => { + is_self_or_assoc(alias.self_ty()) + } + _ => false, + } + } + let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) .iter() + .filter(|p| match p.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(tr) => is_self_or_assoc(tr.self_ty()), + _ => true, + }) .cloned() .map(|p| (p, Span::dummy())) .collect(); diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs index 4df788638a..595f285bd9 100644 --- a/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/crates/hir-ty/src/tests/regression/new_solver.rs @@ -116,3 +116,34 @@ fn main() { "#]], ); } + +#[test] +fn no_infinite_loop_on_super_predicates_elaboration() { + check_infer( + r#" +//- minicore: sized +trait DimMax { + type Output: Dimension; +} + +trait Dimension: DimMax<:: Smaller, Output = Self> { + type Smaller: Dimension; +} + +fn test(t: T) +where + T: DimMax, + U: Dimension, +{ + let t: >::Output = loop {}; +} +"#, + expect![[r#" + 182..183 't': T + 230..280 '{ ... {}; }': () + 240..241 't': >::Output + 270..277 'loop {}': ! + 275..277 '{}': () + "#]], + ) +}