Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #13742 - lowr:fix/assoc-type-shorthand-with-gats, r=flodiebold
fix: only shift `BoundVar`s that come from outside lowering context Fixes #13734 There are some free functions `TyLoweringContext` methods call, which do not know anything about current binders in scope. We need to shift in the `BoundVar`s in substitutions that we get from them (#4952), but not those we get from `TyLoweringContext` methods.
bors 2022-12-10
parent 1449204 · parent 19e3085 · commit 518e39b
-rw-r--r--crates/hir-ty/src/lower.rs42
-rw-r--r--crates/hir-ty/src/tests/regression.rs21
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs2
4 files changed, 46 insertions, 21 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index baf9842d5f..e8466a7eda 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -603,9 +603,8 @@ impl<'a> TyLoweringContext<'a> {
}
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
- let (def, res) = match (self.resolver.generic_def(), res) {
- (Some(def), Some(res)) => (def, res),
- _ => return TyKind::Error.intern(Interner),
+ let Some((def, res)) = self.resolver.generic_def().zip(res) else {
+ return TyKind::Error.intern(Interner);
};
let ty = named_associated_type_shorthand_candidates(
self.db,
@@ -617,6 +616,21 @@ impl<'a> TyLoweringContext<'a> {
return None;
}
+ let parent_subst = t.substitution.clone();
+ let parent_subst = match self.type_param_mode {
+ ParamLoweringMode::Placeholder => {
+ // if we're lowering to placeholders, we have to put them in now.
+ let generics = generics(self.db.upcast(), def);
+ let s = generics.placeholder_subst(self.db);
+ s.apply(parent_subst, Interner)
+ }
+ ParamLoweringMode::Variable => {
+ // We need to shift in the bound vars, since
+ // `named_associated_type_shorthand_candidates` does not do that.
+ parent_subst.shifted_in_from(Interner, self.in_binders)
+ }
+ };
+
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
// generic params. It's inefficient to splice the `Substitution`s, so we may want
// that method to optionally take parent `Substitution` as we already know them at
@@ -632,22 +646,9 @@ impl<'a> TyLoweringContext<'a> {
let substs = Substitution::from_iter(
Interner,
- substs.iter(Interner).take(len_self).chain(t.substitution.iter(Interner)),
+ substs.iter(Interner).take(len_self).chain(parent_subst.iter(Interner)),
);
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put
- // them in now
- let generics = generics(self.db.upcast(), def);
- let s = generics.placeholder_subst(self.db);
- s.apply(substs, Interner)
- }
- ParamLoweringMode::Variable => substs,
- };
- // We need to shift in the bound vars, since
- // associated_type_shorthand_candidates does not do that
- let substs = substs.shifted_in_from(Interner, self.in_binders);
Some(
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
@@ -1190,9 +1191,9 @@ pub fn associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
def: GenericDefId,
res: TypeNs,
- cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
+ mut cb: impl FnMut(&Name, TypeAliasId) -> Option<R>,
) -> Option<R> {
- named_associated_type_shorthand_candidates(db, def, res, None, cb)
+ named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
}
fn named_associated_type_shorthand_candidates<R>(
@@ -1202,6 +1203,9 @@ fn named_associated_type_shorthand_candidates<R>(
def: GenericDefId,
res: TypeNs,
assoc_name: Option<Name>,
+ // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains
+ // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that
+ // properly (see `TyLoweringContext::select_associated_type()`).
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
let mut search = |t| {
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 4e46397459..de6ae7fff8 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1723,3 +1723,24 @@ fn bar() -> ControlFlow<(), ()> {
"#,
);
}
+
+#[test]
+fn assoc_type_shorthand_with_gats_in_binders() {
+ // c.f. test `issue_4885()`
+ check_no_mismatches(
+ r#"
+trait Gats {
+ type Assoc<T>;
+}
+trait Foo<T> {}
+
+struct Bar<'a, B: Gats, A> {
+ field: &'a dyn Foo<B::Assoc<A>>,
+}
+
+fn foo(b: Bar) {
+ let _ = b.field;
+}
+"#,
+ );
+}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2e1f88ba09..f887c75984 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1600,7 +1600,7 @@ impl<'a> SemanticsScope<'a> {
self.db,
def,
resolution.in_type_ns()?,
- |name, _, id| cb(name, id.into()),
+ |name, id| cb(name, id.into()),
)
}
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 91ea1c24d1..38950b12a1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -967,7 +967,7 @@ fn resolve_hir_path_(
db,
def,
res.in_type_ns()?,
- |name, _, id| (name == unresolved.name).then(|| id),
+ |name, id| (name == unresolved.name).then(|| id),
)
})
.map(TypeAlias::from)