about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRyo Yoshida <low.ryoshida@gmail.com>2022-10-05 00:20:01 +0900
committerRyo Yoshida <low.ryoshida@gmail.com>2022-10-05 00:49:00 +0900
commitded3326a64c2ef220f3cec9af863f738749d6ce2 (patch)
tree0950673df7197aae5b8ccfb8c90162b099a0d04d
parente0a161b2e3a9345fd92fd3617e49648ee43ada86 (diff)
downloadrust-ded3326a64c2ef220f3cec9af863f738749d6ce2.tar.gz
rust-ded3326a64c2ef220f3cec9af863f738749d6ce2.zip
fix: use `BoundVar`s from current generic scope
-rw-r--r--crates/hir-ty/src/lower.rs23
-rw-r--r--crates/hir-ty/src/tests/regression.rs13
2 files changed, 33 insertions, 3 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index a77dd910ff7..223d705b157 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1158,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
     };
 
     match res {
-        TypeNs::SelfType(impl_id) => search(
+        TypeNs::SelfType(impl_id) => {
             // we're _in_ the impl -- the binders get added back later. Correct,
             // but it would be nice to make this more explicit
-            db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
-        ),
+            let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+
+            let impl_id_as_generic_def: GenericDefId = impl_id.into();
+            if impl_id_as_generic_def != def {
+                // `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
+                // `BoundVar`s from `def`'s point of view.
+                // FIXME: A `HirDatabase` query may be handy if this process is needed in more
+                // places. It'd be almost identical as `impl_trait_query` where `resolver` would be
+                // of `def` instead of `impl_id`.
+                let starting_idx = generics(db.upcast(), def).len_self();
+                let subst = TyBuilder::subst_for_def(db, impl_id, None)
+                    .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
+                    .build();
+                let trait_ref = subst.apply(trait_ref, Interner);
+                search(trait_ref)
+            } else {
+                search(trait_ref)
+            }
+        }
         TypeNs::GenericParam(param_id) => {
             let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
             let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 16ba3dd6e3c..a155adcec6c 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1694,3 +1694,16 @@ fn foo(a: &dyn DoesNotExist) {
         "#,
     );
 }
+
+#[test]
+fn self_assoc_with_const_generics_crash() {
+    check_no_mismatches(
+        r#"
+trait Trait { type Item; }
+impl<T, const N: usize> Trait for [T; N] {
+    type Item = ();
+    fn f<U>(_: Self::Item) {}
+}
+        "#,
+    );
+}