Skip to content

Commit 823abe7

Browse files
committed
Fix lowering with supertrait predicates
Previously both valid and invalid Rust code could crash r-a due to a cyclic query during lowering. Closes #21006
1 parent 11d6212 commit 823abe7

File tree

2 files changed

+63
-5
lines changed

2 files changed

+63
-5
lines changed

crates/hir-ty/src/lower.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,11 +1649,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
16491649
return false;
16501650
};
16511651

1652-
rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
1653-
tr.0.trait_items(db).items.iter().any(|(name, item)| {
1654-
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
1655-
})
1656-
})
1652+
trait_or_supertrait_has_assoc_type(db, tr, assoc_name)
16571653
}
16581654
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
16591655
}
@@ -1703,6 +1699,45 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
17031699
StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store())
17041700
}
17051701

1702+
/// Check if a trait or any of its supertraits define an associated
1703+
/// type with the given name.
1704+
fn trait_or_supertrait_has_assoc_type(db: &dyn HirDatabase, tr: TraitId, assoc_name: &Name) -> bool {
1705+
let mut visited = FxHashSet::default();
1706+
let mut stack = vec![tr];
1707+
1708+
// In valid Rust code, there should never be a cycle. However, the
1709+
// user may write erroneous code that contains a cycle, so be
1710+
// defensive against that.
1711+
while let Some(trait_id) = stack.pop() {
1712+
if !visited.insert(trait_id) {
1713+
continue;
1714+
}
1715+
1716+
// Check if this trait has the associated type.
1717+
if trait_id.trait_items(db).items.iter().any(|(name, item)| {
1718+
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
1719+
}) {
1720+
return true;
1721+
}
1722+
1723+
// Walk supertraits.
1724+
let params = db.generic_params(trait_id.into());
1725+
if let Some(self_param) = params.trait_self_param() {
1726+
let self_param_id =
1727+
TypeOrConstParamId { parent: trait_id.into(), local_id: self_param };
1728+
1729+
let predicates = generic_predicates_for_param(db, trait_id.into(), self_param_id, None);
1730+
for pred in predicates.get().iter_identity() {
1731+
if let rustc_type_ir::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
1732+
stack.push(trait_pred.trait_ref.def_id.0);
1733+
}
1734+
}
1735+
}
1736+
}
1737+
1738+
false
1739+
}
1740+
17061741
#[inline]
17071742
pub(crate) fn type_alias_bounds<'db>(
17081743
db: &'db dyn HirDatabase,

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,3 +2562,26 @@ fn main() {
25622562
"#,
25632563
);
25642564
}
2565+
2566+
#[test]
2567+
fn issue_21006_generic_predicates_for_param_supertrait_cycle() {
2568+
check_no_mismatches(
2569+
r#"
2570+
trait VCipherSuite {}
2571+
2572+
trait CipherSuite
2573+
where
2574+
OprfHash<Self>: Hash,
2575+
{
2576+
}
2577+
2578+
type Bar<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2579+
2580+
type OprfHash<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2581+
2582+
impl<CS: CipherSuite> Foo<CS> {
2583+
fn seal() {}
2584+
}
2585+
"#,
2586+
);
2587+
}

0 commit comments

Comments
 (0)