Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir/src/semantics.rs32
-rw-r--r--crates/hir/src/source_analyzer.rs12
-rw-r--r--crates/hir_ty/src/db.rs1
-rw-r--r--crates/hir_ty/src/lower.rs99
-rw-r--r--crates/hir_ty/src/tests/traits.rs19
-rw-r--r--crates/hir_ty/src/utils.rs2
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs2
9 files changed, 107 insertions, 67 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 46815cff86..d94f55e326 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -239,7 +239,7 @@ impl HirDisplay for TypeParam {
return Ok(());
}
- let bounds = f.db.generic_predicates_for_param(self.id, None);
+ let bounds = f.db.generic_predicates_for_param(self.id.parent, self.id, None);
let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
let predicates: Vec<_> =
bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e091af4bf8..918cadc869 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2235,8 +2235,11 @@ impl TypeParam {
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
+ /// FIXME: this only lists trait bounds from the item defining the type
+ /// parameter, not additional bounds that might be added e.g. by a method if
+ /// the parameter comes from an impl!
pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
- db.generic_predicates_for_param(self.id, None)
+ db.generic_predicates_for_param(self.id.parent, self.id, None)
.iter()
.filter_map(|pred| match &pred.skip_binders().skip_binders() {
hir_ty::WhereClause::Implemented(trait_ref) => {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index e3ff05b49a..9ac88e260c 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -12,7 +12,7 @@ use hir_def::{
AsMacroCall, FunctionId, TraitId, VariantId,
};
use hir_expand::{name::AsName, ExpansionInfo, MacroCallId};
-use hir_ty::{associated_type_shorthand_candidates, Interner};
+use hir_ty::Interner;
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec};
@@ -50,7 +50,7 @@ pub enum PathResolution {
}
impl PathResolution {
- fn in_type_ns(&self) -> Option<TypeNs> {
+ pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
match self {
PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
@@ -80,18 +80,6 @@ impl PathResolution {
}
}
}
-
- /// Returns an iterator over associated types that may be specified after this path (using
- /// `Ty::Assoc` syntax).
- pub fn assoc_type_shorthand_candidates<R>(
- &self,
- db: &dyn HirDatabase,
- mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
- ) -> Option<R> {
- associated_type_shorthand_candidates(db, self.in_type_ns()?, |name, _, id| {
- cb(name, id.into())
- })
- }
}
#[derive(Debug)]
@@ -1314,4 +1302,20 @@ impl<'a> SemanticsScope<'a> {
let path = Path::from_src(path.clone(), &ctx)?;
resolve_hir_path(self.db, &self.resolver, &path)
}
+
+ /// Iterates over associated types that may be specified after the given path (using
+ /// `Ty::Assoc` syntax).
+ pub fn assoc_type_shorthand_candidates<R>(
+ &self,
+ resolution: &PathResolution,
+ mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
+ ) -> Option<R> {
+ let def = self.resolver.generic_def()?;
+ hir_ty::associated_type_shorthand_candidates(
+ self.db,
+ def,
+ resolution.in_type_ns()?,
+ |name, _, id| cb(name, id.into()),
+ )
+ }
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 869f4a10f8..03e4420985 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -619,9 +619,15 @@ fn resolve_hir_path_(
TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
};
match unresolved {
- Some(unresolved) => res
- .assoc_type_shorthand_candidates(db, |name, alias| {
- (name == unresolved.name).then(|| alias)
+ Some(unresolved) => resolver
+ .generic_def()
+ .and_then(|def| {
+ hir_ty::associated_type_shorthand_candidates(
+ db,
+ def,
+ res.in_type_ns()?,
+ |name, _, id| (name == unresolved.name).then(|| id),
+ )
})
.map(TypeAlias::from)
.map(Into::into)
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 2583227ff4..c3b9255baf 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -60,6 +60,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
fn generic_predicates_for_param(
&self,
+ def: GenericDefId,
param_id: TypeParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]>;
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index a450f6c75c..55b1a67ea7 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -530,49 +530,50 @@ impl<'a> TyLoweringContext<'a> {
}
fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
- if let Some(res) = res {
- let ty = named_associated_type_shorthand_candidates(
- self.db,
- res,
- Some(segment.name.clone()),
- move |name, t, associated_ty| {
- if name == segment.name {
- let substs = match self.type_param_mode {
- TypeParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put
- // them in now
- let generics = generics(
- self.db.upcast(),
- self.resolver.generic_def().expect(
- "there should be generics if there's a generic param",
- ),
- );
- let s = generics.type_params_subst(self.db);
- s.apply(t.substitution.clone(), Interner)
- }
- TypeParamLoweringMode::Variable => t.substitution.clone(),
- };
- // 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);
- // FIXME handle type parameters on the segment
- Some(
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: substs,
- }))
- .intern(Interner),
- )
- } else {
- None
- }
- },
- );
+ let (def, res) = match (self.resolver.generic_def(), res) {
+ (Some(def), Some(res)) => (def, res),
+ _ => return TyKind::Error.intern(Interner),
+ };
+ let ty = named_associated_type_shorthand_candidates(
+ self.db,
+ def,
+ res,
+ Some(segment.name.clone()),
+ move |name, t, associated_ty| {
+ if name == segment.name {
+ let substs = match self.type_param_mode {
+ TypeParamLoweringMode::Placeholder => {
+ // if we're lowering to placeholders, we have to put
+ // them in now
+ let generics = generics(
+ self.db.upcast(),
+ self.resolver
+ .generic_def()
+ .expect("there should be generics if there's a generic param"),
+ );
+ let s = generics.type_params_subst(self.db);
+ s.apply(t.substitution.clone(), Interner)
+ }
+ TypeParamLoweringMode::Variable => t.substitution.clone(),
+ };
+ // 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);
+ // FIXME handle type parameters on the segment
+ Some(
+ TyKind::Alias(AliasTy::Projection(ProjectionTy {
+ associated_ty_id: to_assoc_type_id(associated_ty),
+ substitution: substs,
+ }))
+ .intern(Interner),
+ )
+ } else {
+ None
+ }
+ },
+ );
- ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
- } else {
- TyKind::Error.intern(Interner)
- }
+ ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
}
fn lower_path_inner(
@@ -934,14 +935,18 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig
pub fn associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
+ def: GenericDefId,
res: TypeNs,
cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
- named_associated_type_shorthand_candidates(db, res, None, cb)
+ named_associated_type_shorthand_candidates(db, def, res, None, cb)
}
fn named_associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
+ // If the type parameter is defined in an impl and we're in a method, there
+ // might be additional where clauses to consider
+ def: GenericDefId,
res: TypeNs,
assoc_name: Option<Name>,
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
@@ -968,7 +973,7 @@ fn named_associated_type_shorthand_candidates<R>(
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
),
TypeNs::GenericParam(param_id) => {
- let predicates = db.generic_predicates_for_param(param_id, assoc_name);
+ let predicates = db.generic_predicates_for_param(def, param_id, assoc_name);
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => search(
@@ -1030,13 +1035,14 @@ pub(crate) fn field_types_query(
/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
pub(crate) fn generic_predicates_for_param_query(
db: &dyn HirDatabase,
+ def: GenericDefId,
param_id: TypeParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
- let resolver = param_id.parent.resolver(db.upcast());
+ let resolver = def.resolver(db.upcast());
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
- let generics = generics(db.upcast(), param_id.parent);
+ let generics = generics(db.upcast(), def);
let mut predicates: Vec<_> = resolver
.where_predicates_in_scope()
// we have to filter out all other predicates *first*, before attempting to lower them
@@ -1098,6 +1104,7 @@ pub(crate) fn generic_predicates_for_param_query(
pub(crate) fn generic_predicates_for_param_recover(
_db: &dyn HirDatabase,
_cycle: &[String],
+ _def: &GenericDefId,
_param_id: &TypeParamId,
_assoc_name: &Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 9531be760e..c2669646e2 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -393,6 +393,25 @@ fn test() {
}
#[test]
+fn associated_type_shorthand_from_method_bound() {
+ check_types(
+ r#"
+trait Iterable {
+ type Item;
+}
+struct S<T>;
+impl<T> S<T> {
+ fn foo(self) -> T::Item where T: Iterable { loop {} }
+}
+fn test<T: Iterable>() {
+ let s: S<T>;
+ s.foo();
+ // ^^^^^^^ Iterable::Item<T>
+}"#,
+ );
+}
+
+#[test]
fn infer_associated_type_bound() {
check_types(
r#"
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 4e16cabdfc..c5646e08e6 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -83,7 +83,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
None => return Vec::new(),
};
- db.generic_predicates_for_param(trait_self, None)
+ db.generic_predicates_for_param(trait_self.parent, trait_self, None)
.iter()
.filter_map(|pred| {
pred.as_ref().filter_map(|pred| match pred.skip_binders() {
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index cd1022b2e3..2c6899ff0c 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -119,7 +119,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
if !matches!(kind, Some(PathKind::Pat)) {
// Add associated types on type parameters and `Self`.
- resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
+ ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| {
acc.add_type_alias(ctx, alias);
None::<()>
});