Fix a bug with predicate lowering of associated items
The essence of the bug is that bounds on `impl Trait` got lowered with incorrect bound vars, as if we were lowering the parent.
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 6bf26b7..a0b0afb 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -464,10 +464,14 @@
self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
}
+ /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
+ /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
+ /// **parent**. This is important so we generate the correct bound var/placeholder.
pub(crate) fn lower_where_predicate<'b>(
&'b mut self,
where_predicate: &'b WherePredicate,
generics: &'b Generics,
+ predicate_owner: GenericDefId,
ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b> {
match where_predicate {
@@ -477,7 +481,7 @@
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let param_id =
- hir_def::TypeOrConstParamId { parent: generics.def(), local_id };
+ hir_def::TypeOrConstParamId { parent: predicate_owner, local_id };
match self.type_param_mode {
ParamLoweringMode::Placeholder => {
TyKind::Placeholder(to_placeholder_idx(self.db, param_id))
@@ -887,7 +891,7 @@
if invalid_target {
// If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
- ctx.lower_where_predicate(pred, generics, true).for_each(drop);
+ ctx.lower_where_predicate(pred, generics, generics.def(), true).for_each(drop);
}
return false;
}
@@ -924,7 +928,7 @@
for pred in maybe_parent_generics.where_predicates() {
if predicate(pred, maybe_parent_generics, &mut ctx) {
predicates.extend(
- ctx.lower_where_predicate(pred, maybe_parent_generics, true)
+ ctx.lower_where_predicate(pred, &generics, maybe_parent_generics.def(), true)
.map(|p| make_binders(db, &generics, p)),
);
}
@@ -987,7 +991,9 @@
{
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
- for pred in ctx.lower_where_predicate(pred, maybe_parent_generics, false) {
+ for pred in
+ ctx.lower_where_predicate(pred, &generics, maybe_parent_generics.def(), false)
+ {
if let WhereClause::Implemented(tr) = pred.skip_binders() {
traits_in_scope
.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
@@ -1085,8 +1091,10 @@
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
if filter(pred, maybe_parent_generics.def()) {
+ // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake!
+ // If we use the parent generics
predicates.extend(
- ctx.lower_where_predicate(pred, maybe_parent_generics, false)
+ ctx.lower_where_predicate(pred, &generics, maybe_parent_generics.def(), false)
.map(|p| make_binders(db, &generics, p)),
);
}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index a8a200a..8f9e62d 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1032,4 +1032,23 @@
"#,
);
}
+
+ #[test]
+ fn regression_19610() {
+ check(
+ r#"
+trait Trait {
+ type Assoc;
+}
+struct Foo<A>(A);
+impl<A: Trait<Assoc = impl Trait>> Foo<A> {
+ fn foo<'a, 'b>(_: &'a [i32], _: &'b [i32]) {}
+}
+
+fn bar() {
+ Foo::foo(&[1], &[2]);
+}
+"#,
+ );
+ }
}