Skip to content

Commit 45e0f30

Browse files
committed
fix: Infinite loop while elaborting predicates
1 parent db0420c commit 45e0f30

File tree

7 files changed

+94
-27
lines changed

7 files changed

+94
-27
lines changed

crates/hir-ty/src/db.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,18 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
401401
&'db self,
402402
def: GenericDefId,
403403
) -> crate::lower_nextsolver::GenericPredicates<'db>;
404+
405+
#[salsa::invoke(crate::lower_nextsolver::explicit_super_predicates_of_query)]
406+
fn explicit_super_predicates_of<'db>(
407+
&'db self,
408+
def: GenericDefId,
409+
) -> crate::lower_nextsolver::GenericPredicates<'db>;
410+
411+
#[salsa::invoke(crate::lower_nextsolver::explicit_implied_predicates_of_query)]
412+
fn explicit_implied_predicates_of<'db>(
413+
&'db self,
414+
def: GenericDefId,
415+
) -> crate::lower_nextsolver::GenericPredicates<'db>;
404416
}
405417

406418
#[test]

crates/hir-ty/src/dyn_compatibility.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
137137
};
138138

139139
let interner = DbInterner::new_with(db, Some(krate), None);
140+
// FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
141+
// rust-analyzer yet
140142
let predicates = db.generic_predicates_ns(def);
141143
elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| {
142144
match pred.kind().skip_binder() {

crates/hir-ty/src/dyn_compatibility/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ trait Bar<T> {
253253
trait Baz : Bar<Self> {
254254
}
255255
"#,
256-
[("Bar", vec![]), ("Baz", vec![SizedSelf, SelfReferential])],
256+
// FIXME: We should also report `SizedSelf` here
257+
[("Bar", vec![]), ("Baz", vec![SelfReferential])],
257258
);
258259
}
259260

crates/hir-ty/src/lower_nextsolver.rs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -534,25 +534,23 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
534534
match where_predicate {
535535
WherePredicate::ForLifetime { target, bound, .. }
536536
| WherePredicate::TypeBound { target, bound } => {
537-
if let PredicateFilter::SelfTrait = predicate_filter {
538-
let target_type = &self.store[*target];
539-
let self_type = 'is_self: {
540-
if let TypeRef::Path(path) = target_type
541-
&& path.is_self_type()
542-
{
543-
break 'is_self true;
544-
}
545-
if let TypeRef::TypeParam(param) = target_type
546-
&& generics[param.local_id()].is_trait_self()
547-
{
548-
break 'is_self true;
549-
}
550-
false
551-
};
552-
if !self_type {
553-
return Either::Left(Either::Left(iter::empty()));
554-
}
537+
let is_self_ty = |ty_ref: TypeRefId| match &self.store[ty_ref] {
538+
TypeRef::Path(path) => path.is_self_type(),
539+
TypeRef::TypeParam(param) => generics[param.local_id()].is_trait_self(),
540+
_ => false,
541+
};
542+
543+
let should_lower = match predicate_filter {
544+
PredicateFilter::SelfOnly => is_self_ty(*target),
545+
PredicateFilter::SelfAndAssociatedTypeBounds => {
546+
is_self_ty(*target) || matches!(&self.store[*target], TypeRef::Path(path) if path.type_anchor().is_some_and(is_self_ty))
547+
},
548+
PredicateFilter::All => true,
549+
};
550+
if !should_lower {
551+
return Either::Left(Either::Left(iter::empty()));
555552
}
553+
556554
let self_ty = self.lower_ty(*target);
557555
Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
558556
}
@@ -1236,7 +1234,8 @@ impl<'db> ops::Deref for GenericPredicates<'db> {
12361234

12371235
#[derive(Copy, Clone, Debug)]
12381236
pub(crate) enum PredicateFilter {
1239-
SelfTrait,
1237+
SelfOnly,
1238+
SelfAndAssociatedTypeBounds,
12401239
All,
12411240
}
12421241

@@ -1265,6 +1264,21 @@ pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>(
12651264
generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def)
12661265
}
12671266

1267+
pub(crate) fn explicit_super_predicates_of_query<'db>(
1268+
db: &'db dyn HirDatabase,
1269+
def: GenericDefId,
1270+
) -> GenericPredicates<'db> {
1271+
generic_predicates_filtered_by(db, def, PredicateFilter::SelfOnly, |_| true).0
1272+
}
1273+
1274+
pub(crate) fn explicit_implied_predicates_of_query<'db>(
1275+
db: &'db dyn HirDatabase,
1276+
def: GenericDefId,
1277+
) -> GenericPredicates<'db> {
1278+
generic_predicates_filtered_by(db, def, PredicateFilter::SelfAndAssociatedTypeBounds, |_| true)
1279+
.0
1280+
}
1281+
12681282
/// Resolve the where clause(s) of an item with generics,
12691283
/// with a given filter
12701284
#[tracing::instrument(skip(db, filter), ret)]
@@ -1310,8 +1324,12 @@ where
13101324

13111325
let explicitly_unsized_tys = ctx.unsized_types;
13121326

1313-
let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
1314-
if let Some(sized_trait) = sized_trait {
1327+
// We don't insert extra `: Sized` bounds if we are collecting predicates only for `Self`
1328+
if !matches!(
1329+
predicate_filter,
1330+
PredicateFilter::SelfOnly | PredicateFilter::SelfAndAssociatedTypeBounds
1331+
) && let Some(sized_trait) = LangItem::Sized.resolve_trait(db, resolver.krate())
1332+
{
13151333
let (mut generics, mut def_id) =
13161334
(crate::next_solver::generics::generics(db, def.into()), def);
13171335
loop {
@@ -1358,6 +1376,9 @@ where
13581376
}
13591377
}
13601378

1379+
// FIXME: rustc gathers more predicates by recursing through resulting trait predicates.
1380+
// See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715
1381+
13611382
(
13621383
GenericPredicates(predicates.is_empty().not().then(|| predicates.into())),
13631384
create_diagnostics(ctx.diagnostics),
@@ -1724,7 +1745,7 @@ fn named_associated_type_shorthand_candidates<'db, R>(
17241745
for pred in generic_predicates_filtered_by(
17251746
db,
17261747
GenericDefId::TraitId(trait_def_id),
1727-
PredicateFilter::SelfTrait,
1748+
PredicateFilter::SelfOnly,
17281749
// We are likely in the midst of lowering generic predicates of `def`.
17291750
// So, if we allow `pred == def` we might fall into an infinite recursion.
17301751
// Actually, we have already checked for the case `pred == def` above as we started

crates/hir-ty/src/next_solver/interner.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
13321332
) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
13331333
let predicates: Vec<(Clause<'db>, Span)> = self
13341334
.db()
1335-
.generic_predicates_ns(def_id.0.into())
1335+
.explicit_super_predicates_of(def_id.0.into())
13361336
.iter()
13371337
.cloned()
13381338
.map(|p| (p, Span::dummy()))
@@ -1347,7 +1347,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
13471347
) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
13481348
let predicates: Vec<(Clause<'db>, Span)> = self
13491349
.db()
1350-
.generic_predicates_ns(def_id.try_into().unwrap())
1350+
.explicit_implied_predicates_of(def_id.try_into().unwrap())
13511351
.iter()
13521352
.cloned()
13531353
.map(|p| (p, Span::dummy()))

crates/hir-ty/src/tests/incremental.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ fn main() {
589589
"attrs_shim",
590590
"attrs_shim",
591591
"return_type_impl_traits_shim",
592-
"generic_predicates_ns_shim",
592+
"explicit_implied_predicates_of_shim",
593593
"infer_shim",
594594
"function_signature_shim",
595595
"function_signature_with_source_map_shim",
@@ -689,7 +689,7 @@ fn main() {
689689
"attrs_shim",
690690
"attrs_shim",
691691
"return_type_impl_traits_shim",
692-
"generic_predicates_ns_shim",
692+
"explicit_implied_predicates_of_shim",
693693
"infer_shim",
694694
"function_signature_with_source_map_shim",
695695
"expr_scopes_shim",

crates/hir-ty/src/tests/regression/new_solver.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,34 @@ fn main() {
116116
"#]],
117117
);
118118
}
119+
120+
#[test]
121+
fn no_infinite_loop_on_super_predicates_elaboration() {
122+
check_infer(
123+
r#"
124+
//- minicore: sized
125+
trait DimMax<Other: Dimension> {
126+
type Output: Dimension;
127+
}
128+
129+
trait Dimension: DimMax<<Self as Dimension>:: Smaller, Output = Self> {
130+
type Smaller: Dimension;
131+
}
132+
133+
fn test<T, U>(t: T)
134+
where
135+
T: DimMax<U>,
136+
U: Dimension,
137+
{
138+
let t: <T as DimMax<U>>::Output = loop {};
139+
}
140+
"#,
141+
expect![[r#"
142+
182..183 't': T
143+
230..280 '{ ... {}; }': ()
144+
240..241 't': <T as DimMax<U>>::Output
145+
270..277 'loop {}': !
146+
275..277 '{}': ()
147+
"#]],
148+
)
149+
}

0 commit comments

Comments
 (0)