Skip to content

Commit 236e2db

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 27f1724 commit 236e2db

File tree

2 files changed

+78
-8
lines changed

2 files changed

+78
-8
lines changed

crates/hir-ty/src/lower.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use tracing::debug;
5353
use triomphe::{Arc, ThinArc};
5454

5555
use crate::{
56-
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
56+
FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, all_super_traits,
5757
consteval::intern_const_ref,
5858
db::{HirDatabase, InternedOpaqueTyId},
5959
generics::{Generics, generics, trait_self_param_idx},
@@ -1624,11 +1624,16 @@ pub(crate) fn field_types_with_diagnostics_query<'db>(
16241624
(res, create_diagnostics(ctx.diagnostics))
16251625
}
16261626

1627+
/// Predicates for `param_id` of the form `P: SomeTrait`. If
1628+
/// `assoc_name` is provided, only return predicates referencing traits
1629+
/// that have an associated type of that name.
1630+
///
16271631
/// This query exists only to be used when resolving short-hand associated types
16281632
/// like `T::Item`.
16291633
///
16301634
/// See the analogous query in rustc and its comment:
16311635
/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
1636+
///
16321637
/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
16331638
/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
16341639
/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
@@ -1652,7 +1657,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
16521657
);
16531658

16541659
// we have to filter out all other predicates *first*, before attempting to lower them
1655-
let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
1660+
let has_relevant_bound = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred {
16561661
WherePredicate::ForLifetime { target, bound, .. }
16571662
| WherePredicate::TypeBound { target, bound, .. } => {
16581663
let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
@@ -1700,11 +1705,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
17001705
return false;
17011706
};
17021707

1703-
rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| {
1704-
tr.0.trait_items(db).items.iter().any(|(name, item)| {
1705-
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
1706-
})
1707-
})
1708+
trait_or_supertrait_has_assoc_type(db, tr, assoc_name)
17081709
}
17091710
TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
17101711
}
@@ -1717,7 +1718,7 @@ pub(crate) fn generic_predicates_for_param<'db>(
17171718
{
17181719
ctx.store = maybe_parent_generics.store();
17191720
for pred in maybe_parent_generics.where_predicates() {
1720-
if predicate(pred, &mut ctx) {
1721+
if has_relevant_bound(pred, &mut ctx) {
17211722
predicates.extend(
17221723
ctx.lower_where_predicate(
17231724
pred,
@@ -1757,6 +1758,27 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
17571758
StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store())
17581759
}
17591760

1761+
/// Check if this trait or any of its supertraits define an associated
1762+
/// type with the given name.
1763+
fn trait_or_supertrait_has_assoc_type(
1764+
db: &dyn HirDatabase,
1765+
tr: TraitId,
1766+
assoc_name: &Name,
1767+
) -> bool {
1768+
for trait_id in all_super_traits(db, tr) {
1769+
if trait_id
1770+
.trait_items(db)
1771+
.items
1772+
.iter()
1773+
.any(|(name, item)| matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name)
1774+
{
1775+
return true;
1776+
}
1777+
}
1778+
1779+
false
1780+
}
1781+
17601782
#[inline]
17611783
pub(crate) fn type_alias_bounds<'db>(
17621784
db: &'db dyn HirDatabase,

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,3 +2598,51 @@ trait ColumnLike {
25982598
"#,
25992599
);
26002600
}
2601+
2602+
#[test]
2603+
fn issue_21006_generic_predicates_for_param_supertrait_cycle() {
2604+
check_no_mismatches(
2605+
r#"
2606+
trait VCipherSuite {}
2607+
2608+
trait CipherSuite
2609+
where
2610+
OprfHash<Self>: Hash,
2611+
{
2612+
}
2613+
2614+
type Bar<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2615+
2616+
type OprfHash<CS: CipherSuite> = <CS::Baz as VCipherSuite>::Hash;
2617+
2618+
impl<CS: CipherSuite> Foo<CS> {
2619+
fn seal() {}
2620+
}
2621+
"#,
2622+
);
2623+
}
2624+
2625+
#[test]
2626+
fn issue_21006_self_assoc_trait() {
2627+
check_types(
2628+
r#"
2629+
trait Baz {
2630+
fn baz(&self);
2631+
}
2632+
2633+
trait Foo {
2634+
type Assoc;
2635+
}
2636+
2637+
trait Bar: Foo
2638+
where
2639+
Self::Assoc: Baz,
2640+
{
2641+
fn bar(v: Self::Assoc) {
2642+
let _ = v.baz();
2643+
// ^ ()
2644+
}
2645+
}
2646+
"#,
2647+
);
2648+
}

0 commit comments

Comments
 (0)