mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-16 07:03:57 +00:00
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.
This commit is contained in:
commit
518e39bfe6
4 changed files with 46 additions and 21 deletions
|
@ -603,9 +603,8 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
|
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
|
||||||
let (def, res) = match (self.resolver.generic_def(), res) {
|
let Some((def, res)) = self.resolver.generic_def().zip(res) else {
|
||||||
(Some(def), Some(res)) => (def, res),
|
return TyKind::Error.intern(Interner);
|
||||||
_ => return TyKind::Error.intern(Interner),
|
|
||||||
};
|
};
|
||||||
let ty = named_associated_type_shorthand_candidates(
|
let ty = named_associated_type_shorthand_candidates(
|
||||||
self.db,
|
self.db,
|
||||||
|
@ -617,6 +616,21 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
return None;
|
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
|
// 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
|
// 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
|
// 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(
|
let substs = Substitution::from_iter(
|
||||||
Interner,
|
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(
|
Some(
|
||||||
TyKind::Alias(AliasTy::Projection(ProjectionTy {
|
TyKind::Alias(AliasTy::Projection(ProjectionTy {
|
||||||
associated_ty_id: to_assoc_type_id(associated_ty),
|
associated_ty_id: to_assoc_type_id(associated_ty),
|
||||||
|
@ -1190,9 +1191,9 @@ pub fn associated_type_shorthand_candidates<R>(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
def: GenericDefId,
|
def: GenericDefId,
|
||||||
res: TypeNs,
|
res: TypeNs,
|
||||||
cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
|
mut cb: impl FnMut(&Name, TypeAliasId) -> Option<R>,
|
||||||
) -> 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>(
|
fn named_associated_type_shorthand_candidates<R>(
|
||||||
|
@ -1202,6 +1203,9 @@ fn named_associated_type_shorthand_candidates<R>(
|
||||||
def: GenericDefId,
|
def: GenericDefId,
|
||||||
res: TypeNs,
|
res: TypeNs,
|
||||||
assoc_name: Option<Name>,
|
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>,
|
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
|
||||||
) -> Option<R> {
|
) -> Option<R> {
|
||||||
let mut search = |t| {
|
let mut search = |t| {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1600,7 +1600,7 @@ impl<'a> SemanticsScope<'a> {
|
||||||
self.db,
|
self.db,
|
||||||
def,
|
def,
|
||||||
resolution.in_type_ns()?,
|
resolution.in_type_ns()?,
|
||||||
|name, _, id| cb(name, id.into()),
|
|name, id| cb(name, id.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -967,7 +967,7 @@ fn resolve_hir_path_(
|
||||||
db,
|
db,
|
||||||
def,
|
def,
|
||||||
res.in_type_ns()?,
|
res.in_type_ns()?,
|
||||||
|name, _, id| (name == unresolved.name).then(|| id),
|
|name, id| (name == unresolved.name).then(|| id),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(TypeAlias::from)
|
.map(TypeAlias::from)
|
||||||
|
|
Loading…
Reference in a new issue