Skip to content

Commit 6e4df21

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.
1 parent 58646b5 commit 6e4df21

File tree

3 files changed

+88
-7
lines changed

3 files changed

+88
-7
lines changed

crates/hir-def/src/hir/generics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
184184

185185
impl GenericParams {
186186
/// The index of the self param in the generic of the non-parent definition.
187-
pub(crate) const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
187+
pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
188188
LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
189189

190190
pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc<GenericParams> {

crates/hir-ty/src/lower.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use hir_def::{
2020
builtin_type::BuiltinType,
2121
expr_store::{ExpressionStore, HygieneId, path::Path},
2222
hir::generics::{
23-
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
23+
GenericParamDataRef, GenericParams, TypeOrConstParamData, TypeParamProvenance,
24+
WherePredicate,
2425
},
2526
item_tree::FieldsShape,
2627
lang_item::LangItems,
@@ -1637,11 +1638,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
16371638
return false;
16381639
};
16391640

1640-
rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
1641-
tr.0.trait_items(db).items.iter().any(|(name, item)| {
1642-
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
1643-
})
1644-
})
1641+
trait_or_supertrait_has_assoc_type(db, tr, assoc_name)
16451642
}
16461643
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
16471644
}
@@ -1691,6 +1688,50 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
16911688
StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store())
16921689
}
16931690

1691+
/// Check if a trait or any of its supertraits define an associated
1692+
/// type with the given name.
1693+
fn trait_or_supertrait_has_assoc_type(
1694+
db: &dyn HirDatabase,
1695+
tr: TraitId,
1696+
assoc_name: &Name,
1697+
) -> bool {
1698+
let mut visited = FxHashSet::default();
1699+
let mut stack = vec![tr];
1700+
1701+
// Associated traits can form a cycle, so handle that case
1702+
// defensively.
1703+
while let Some(trait_id) = stack.pop() {
1704+
if !visited.insert(trait_id) {
1705+
continue;
1706+
}
1707+
1708+
// Check if this trait has the associated type.
1709+
if trait_id
1710+
.trait_items(db)
1711+
.items
1712+
.iter()
1713+
.any(|(name, item)| matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name)
1714+
{
1715+
return true;
1716+
}
1717+
1718+
let self_param_id = TypeOrConstParamId {
1719+
parent: trait_id.into(),
1720+
local_id: GenericParams::SELF_PARAM_ID_IN_SELF,
1721+
};
1722+
1723+
// Walk supertraits.
1724+
let predicates = generic_predicates_for_param(db, trait_id.into(), self_param_id, None);
1725+
for pred in predicates.get().iter_identity() {
1726+
if let rustc_type_ir::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
1727+
stack.push(trait_pred.trait_ref.def_id.0);
1728+
}
1729+
}
1730+
}
1731+
1732+
false
1733+
}
1734+
16941735
#[inline]
16951736
pub(crate) fn type_alias_bounds<'db>(
16961737
db: &'db dyn HirDatabase,

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2563,3 +2563,43 @@ fn main() {
25632563
"#,
25642564
);
25652565
}
2566+
2567+
#[test]
2568+
fn issue_21006_generic_predicates_for_param_supertrait_cycle() {
2569+
check_no_mismatches(
2570+
r#"
2571+
trait VCipherSuite {}
2572+
2573+
trait CipherSuite
2574+
where
2575+
OprfHash<Self>: Hash,
2576+
{
2577+
}
2578+
2579+
type Bar<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2580+
2581+
type OprfHash<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2582+
2583+
impl<CS: CipherSuite> Foo<CS> {
2584+
fn seal() {}
2585+
}
2586+
"#,
2587+
);
2588+
}
2589+
2590+
#[test]
2591+
fn issue_21006_self_assoc_trait() {
2592+
check_no_mismatches(
2593+
r#"
2594+
trait Foo {
2595+
type Assoc;
2596+
}
2597+
2598+
trait Bar: Foo
2599+
where
2600+
Self::Assoc: Send,
2601+
{
2602+
}
2603+
"#,
2604+
);
2605+
}

0 commit comments

Comments
 (0)