Skip to content

Commit 8c26700

Browse files
Complete assoc. items on type parameters
1 parent 4ff3573 commit 8c26700

File tree

5 files changed

+408
-69
lines changed

5 files changed

+408
-69
lines changed

crates/ra_hir/src/code_model.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,16 @@ impl TypeParam {
953953
pub fn module(self, db: &dyn HirDatabase) -> Module {
954954
self.id.parent.module(db.upcast()).into()
955955
}
956+
957+
pub fn ty(self, db: &dyn HirDatabase) -> Type {
958+
let resolver = self.id.parent.resolver(db.upcast());
959+
let environment = TraitEnvironment::lower(db, &resolver);
960+
let ty = Ty::Placeholder(self.id);
961+
Type {
962+
krate: self.id.parent.module(db.upcast()).krate,
963+
ty: InEnvironment { value: ty, environment },
964+
}
965+
}
956966
}
957967

958968
// FIXME: rename from `ImplDef` to `Impl`

crates/ra_hir/src/semantics.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use hir_def::{
99
AsMacroCall, TraitId,
1010
};
1111
use hir_expand::ExpansionInfo;
12+
use hir_ty::associated_types;
1213
use itertools::Itertools;
1314
use ra_db::{FileId, FileRange};
1415
use ra_prof::profile;
@@ -24,8 +25,9 @@ use crate::{
2425
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
2526
source_analyzer::{resolve_hir_path, SourceAnalyzer},
2627
AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
27-
Name, Origin, Path, ScopeDef, Trait, Type, TypeParam,
28+
Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
2829
};
30+
use resolver::TypeNs;
2931

3032
#[derive(Debug, Clone, PartialEq, Eq)]
3133
pub enum PathResolution {
@@ -40,6 +42,49 @@ pub enum PathResolution {
4042
AssocItem(AssocItem),
4143
}
4244

45+
impl PathResolution {
46+
fn in_type_ns(self) -> Option<TypeNs> {
47+
match self {
48+
PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId(adt.into())),
49+
PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
50+
Some(TypeNs::BuiltinType(builtin))
51+
}
52+
PathResolution::Def(ModuleDef::Const(_)) => None,
53+
PathResolution::Def(ModuleDef::EnumVariant(_)) => None,
54+
PathResolution::Def(ModuleDef::Function(_)) => None,
55+
PathResolution::Def(ModuleDef::Module(_)) => None,
56+
PathResolution::Def(ModuleDef::Static(_)) => None,
57+
PathResolution::Def(ModuleDef::Trait(_)) => None,
58+
PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
59+
Some(TypeNs::TypeAliasId(alias.into()))
60+
}
61+
PathResolution::Local(_) => None,
62+
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam(param.into())),
63+
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType(impl_def.into())),
64+
PathResolution::Macro(_) => None,
65+
PathResolution::AssocItem(AssocItem::Const(_)) => None,
66+
PathResolution::AssocItem(AssocItem::Function(_)) => None,
67+
PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
68+
Some(TypeNs::TypeAliasId(alias.into()))
69+
}
70+
}
71+
}
72+
73+
/// Returns an iterator over associated types that may be specified after this path (using
74+
/// `Ty::Assoc` syntax).
75+
pub fn assoc_type_shorthand_candidates<R>(
76+
&self,
77+
db: &dyn HirDatabase,
78+
mut cb: impl FnMut(TypeAlias) -> Option<R>,
79+
) -> Option<R> {
80+
if let Some(res) = self.clone().in_type_ns() {
81+
associated_types(db, res, |_, _, id| cb(id.into()))
82+
} else {
83+
None
84+
}
85+
}
86+
}
87+
4388
/// Primary API to get semantic information, like types, from syntax trees.
4489
pub struct Semantics<'db, DB> {
4590
pub db: &'db DB,

crates/ra_hir_ty/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub use autoderef::autoderef;
6666
pub use infer::{InferTy, InferenceResult};
6767
pub use lower::CallableDef;
6868
pub use lower::{
69-
callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
69+
associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext,
70+
ValueTyDefId,
7071
};
7172
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
7273

crates/ra_hir_ty/src/lower.rs

Lines changed: 88 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use hir_def::{
1717
path::{GenericArg, Path, PathSegment, PathSegments},
1818
resolver::{HasResolver, Resolver, TypeNs},
1919
type_ref::{TypeBound, TypeRef},
20-
AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
21-
ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
22-
VariantId,
20+
AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
21+
HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
22+
UnionId, VariantId,
2323
};
2424
use ra_arena::map::ArenaMap;
2525
use ra_db::CrateId;
@@ -34,6 +34,7 @@ use crate::{
3434
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
3535
ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
3636
};
37+
use hir_expand::name::Name;
3738

3839
#[derive(Debug)]
3940
pub struct TyLoweringContext<'a> {
@@ -383,61 +384,37 @@ impl Ty {
383384
res: Option<TypeNs>,
384385
segment: PathSegment<'_>,
385386
) -> Ty {
386-
let traits_from_env: Vec<_> = match res {
387-
Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
388-
None => return Ty::Unknown,
389-
Some(trait_ref) => vec![trait_ref.value],
390-
},
391-
Some(TypeNs::GenericParam(param_id)) => {
392-
let predicates = ctx.db.generic_predicates_for_param(param_id);
393-
let mut traits_: Vec<_> = predicates
394-
.iter()
395-
.filter_map(|pred| match &pred.value {
396-
GenericPredicate::Implemented(tr) => Some(tr.clone()),
397-
_ => None,
398-
})
399-
.collect();
400-
// Handle `Self::Type` referring to own associated type in trait definitions
401-
if let GenericDefId::TraitId(trait_id) = param_id.parent {
402-
let generics = generics(ctx.db.upcast(), trait_id.into());
403-
if generics.params.types[param_id.local_id].provenance
404-
== TypeParamProvenance::TraitSelf
405-
{
406-
let trait_ref = TraitRef {
407-
trait_: trait_id,
408-
substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
409-
};
410-
traits_.push(trait_ref);
411-
}
387+
if let Some(res) = res {
388+
let ty = associated_types(ctx.db, res, move |name, t, associated_ty| {
389+
if name == segment.name {
390+
let substs = match ctx.type_param_mode {
391+
TypeParamLoweringMode::Placeholder => {
392+
// if we're lowering to placeholders, we have to put
393+
// them in now
394+
let s = Substs::type_params(
395+
ctx.db,
396+
ctx.resolver
397+
.generic_def()
398+
.expect("there should be generics if there's a generic param"),
399+
);
400+
t.substs.clone().subst_bound_vars(&s)
401+
}
402+
TypeParamLoweringMode::Variable => t.substs.clone(),
403+
};
404+
// FIXME handle type parameters on the segment
405+
return Some(Ty::Projection(ProjectionTy {
406+
associated_ty,
407+
parameters: substs,
408+
}));
412409
}
413-
traits_
414-
}
415-
_ => return Ty::Unknown,
416-
};
417-
let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t));
418-
for t in traits {
419-
if let Some(associated_ty) =
420-
ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
421-
{
422-
let substs = match ctx.type_param_mode {
423-
TypeParamLoweringMode::Placeholder => {
424-
// if we're lowering to placeholders, we have to put
425-
// them in now
426-
let s = Substs::type_params(
427-
ctx.db,
428-
ctx.resolver
429-
.generic_def()
430-
.expect("there should be generics if there's a generic param"),
431-
);
432-
t.substs.subst_bound_vars(&s)
433-
}
434-
TypeParamLoweringMode::Variable => t.substs,
435-
};
436-
// FIXME handle (forbid) type parameters on the segment
437-
return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
438-
}
410+
411+
None
412+
});
413+
414+
ty.unwrap_or(Ty::Unknown)
415+
} else {
416+
Ty::Unknown
439417
}
440-
Ty::Unknown
441418
}
442419

443420
fn from_hir_path_inner(
@@ -694,6 +671,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
694671
}
695672
}
696673

674+
pub fn associated_types<R>(
675+
db: &dyn HirDatabase,
676+
res: TypeNs,
677+
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
678+
) -> Option<R> {
679+
let traits_from_env: Vec<_> = match res {
680+
TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) {
681+
None => vec![],
682+
Some(trait_ref) => vec![trait_ref.value],
683+
},
684+
TypeNs::GenericParam(param_id) => {
685+
let predicates = db.generic_predicates_for_param(param_id);
686+
let mut traits_: Vec<_> = predicates
687+
.iter()
688+
.filter_map(|pred| match &pred.value {
689+
GenericPredicate::Implemented(tr) => Some(tr.clone()),
690+
_ => None,
691+
})
692+
.collect();
693+
// Handle `Self::Type` referring to own associated type in trait definitions
694+
if let GenericDefId::TraitId(trait_id) = param_id.parent {
695+
let generics = generics(db.upcast(), trait_id.into());
696+
if generics.params.types[param_id.local_id].provenance
697+
== TypeParamProvenance::TraitSelf
698+
{
699+
let trait_ref = TraitRef {
700+
trait_: trait_id,
701+
substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
702+
};
703+
traits_.push(trait_ref);
704+
}
705+
}
706+
traits_
707+
}
708+
_ => vec![],
709+
};
710+
711+
for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
712+
let data = db.trait_data(t.trait_);
713+
714+
for (name, assoc_id) in &data.items {
715+
match assoc_id {
716+
AssocItemId::TypeAliasId(alias) => {
717+
if let Some(result) = cb(name, &t, *alias) {
718+
return Some(result);
719+
}
720+
}
721+
AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
722+
}
723+
}
724+
}
725+
726+
None
727+
}
728+
697729
/// Build the type of all specific fields of a struct or enum variant.
698730
pub(crate) fn field_types_query(
699731
db: &dyn HirDatabase,

0 commit comments

Comments
 (0)