Skip to content

Commit 6d28a79

Browse files
committed
fix: Infinite loop while elaborting predicates
1 parent db0420c commit 6d28a79

File tree

7 files changed

+93
-218
lines changed

7 files changed

+93
-218
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: 1 addition & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use base_db::SourceDatabase;
22
use expect_test::Expect;
3-
use hir_def::{DefWithBodyId, ModuleDefId};
3+
use hir_def::ModuleDefId;
44
use salsa::EventKind;
55
use test_fixture::WithFixture;
66

@@ -519,198 +519,6 @@ impl SomeStruct {
519519
);
520520
}
521521

522-
// FIXME(next-solver): does this test make sense with fast path?
523-
#[test]
524-
fn add_struct_invalidates_trait_solve() {
525-
let (mut db, file_id) = TestDB::with_single_file(
526-
"
527-
//- /main.rs crate:main
528-
struct SomeStruct;
529-
530-
trait Trait<T> {
531-
fn method(&self) -> T;
532-
}
533-
impl Trait<u32> for SomeStruct {}
534-
535-
fn main() {
536-
let s = SomeStruct;
537-
s.method();
538-
s.$0
539-
}",
540-
);
541-
542-
execute_assert_events(
543-
&db,
544-
|| {
545-
let module = db.module_for_file(file_id.file_id(&db));
546-
let crate_def_map = module.def_map(&db);
547-
let mut defs: Vec<DefWithBodyId> = vec![];
548-
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
549-
let def = match it {
550-
ModuleDefId::FunctionId(it) => it.into(),
551-
ModuleDefId::EnumVariantId(it) => it.into(),
552-
ModuleDefId::ConstId(it) => it.into(),
553-
ModuleDefId::StaticId(it) => it.into(),
554-
_ => return,
555-
};
556-
defs.push(def);
557-
});
558-
559-
for def in defs {
560-
let _inference_result = db.infer(def);
561-
}
562-
},
563-
&[("trait_solve_shim", 0)],
564-
expect_test::expect![[r#"
565-
[
566-
"source_root_crates_shim",
567-
"crate_local_def_map",
568-
"file_item_tree_query",
569-
"ast_id_map_shim",
570-
"parse_shim",
571-
"real_span_map_shim",
572-
"TraitItems::query_with_diagnostics_",
573-
"body_shim",
574-
"body_with_source_map_shim",
575-
"attrs_shim",
576-
"ImplItems::of_",
577-
"infer_shim",
578-
"trait_signature_shim",
579-
"trait_signature_with_source_map_shim",
580-
"attrs_shim",
581-
"function_signature_shim",
582-
"function_signature_with_source_map_shim",
583-
"attrs_shim",
584-
"body_shim",
585-
"body_with_source_map_shim",
586-
"trait_environment_shim",
587-
"lang_item",
588-
"crate_lang_items",
589-
"attrs_shim",
590-
"attrs_shim",
591-
"return_type_impl_traits_shim",
592-
"generic_predicates_ns_shim",
593-
"infer_shim",
594-
"function_signature_shim",
595-
"function_signature_with_source_map_shim",
596-
"trait_environment_shim",
597-
"expr_scopes_shim",
598-
"struct_signature_shim",
599-
"struct_signature_with_source_map_shim",
600-
"generic_predicates_shim",
601-
"value_ty_shim",
602-
"VariantFields::firewall_",
603-
"VariantFields::query_",
604-
"lang_item",
605-
"inherent_impls_in_crate_shim",
606-
"impl_signature_shim",
607-
"impl_signature_with_source_map_shim",
608-
"callable_item_signature_shim",
609-
"trait_impls_in_deps_shim",
610-
"trait_impls_in_crate_shim",
611-
"impl_trait_with_diagnostics_shim",
612-
"impl_self_ty_with_diagnostics_shim",
613-
"type_for_adt_tracked",
614-
"impl_trait_with_diagnostics_ns_shim",
615-
"impl_self_ty_with_diagnostics_ns_shim",
616-
"generic_predicates_ns_shim",
617-
"value_ty_shim",
618-
"generic_predicates_shim",
619-
"lang_item",
620-
]
621-
"#]],
622-
);
623-
624-
let new_text = "
625-
//- /main.rs crate:main
626-
struct AnotherStruct;
627-
628-
struct SomeStruct;
629-
630-
trait Trait<T> {
631-
fn method(&self) -> T;
632-
}
633-
impl Trait<u32> for SomeStruct {}
634-
635-
fn main() {
636-
let s = SomeStruct;
637-
s.method();
638-
s.$0
639-
}";
640-
641-
db.set_file_text(file_id.file_id(&db), new_text);
642-
643-
execute_assert_events(
644-
&db,
645-
|| {
646-
let module = db.module_for_file(file_id.file_id(&db));
647-
let crate_def_map = module.def_map(&db);
648-
let mut defs: Vec<DefWithBodyId> = vec![];
649-
650-
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
651-
let def = match it {
652-
ModuleDefId::FunctionId(it) => it.into(),
653-
ModuleDefId::EnumVariantId(it) => it.into(),
654-
ModuleDefId::ConstId(it) => it.into(),
655-
ModuleDefId::StaticId(it) => it.into(),
656-
_ => return,
657-
};
658-
defs.push(def);
659-
});
660-
661-
for def in defs {
662-
let _inference_result = db.infer(def);
663-
}
664-
},
665-
&[("trait_solve_shim", 0)],
666-
expect_test::expect![[r#"
667-
[
668-
"parse_shim",
669-
"ast_id_map_shim",
670-
"file_item_tree_query",
671-
"real_span_map_shim",
672-
"crate_local_def_map",
673-
"TraitItems::query_with_diagnostics_",
674-
"body_with_source_map_shim",
675-
"attrs_shim",
676-
"body_shim",
677-
"ImplItems::of_",
678-
"infer_shim",
679-
"attrs_shim",
680-
"trait_signature_with_source_map_shim",
681-
"attrs_shim",
682-
"function_signature_with_source_map_shim",
683-
"function_signature_shim",
684-
"body_with_source_map_shim",
685-
"body_shim",
686-
"trait_environment_shim",
687-
"crate_lang_items",
688-
"attrs_shim",
689-
"attrs_shim",
690-
"attrs_shim",
691-
"return_type_impl_traits_shim",
692-
"generic_predicates_ns_shim",
693-
"infer_shim",
694-
"function_signature_with_source_map_shim",
695-
"expr_scopes_shim",
696-
"struct_signature_with_source_map_shim",
697-
"VariantFields::query_",
698-
"inherent_impls_in_crate_shim",
699-
"impl_signature_with_source_map_shim",
700-
"impl_signature_shim",
701-
"callable_item_signature_shim",
702-
"trait_impls_in_crate_shim",
703-
"impl_trait_with_diagnostics_shim",
704-
"impl_self_ty_with_diagnostics_shim",
705-
"impl_trait_with_diagnostics_ns_shim",
706-
"impl_self_ty_with_diagnostics_ns_shim",
707-
"generic_predicates_ns_shim",
708-
"generic_predicates_shim",
709-
]
710-
"#]],
711-
);
712-
}
713-
714522
fn execute_assert_events(
715523
db: &TestDB,
716524
f: impl FnOnce(),

0 commit comments

Comments
 (0)