Skip to content

Commit 913eff5

Browse files
Merge #4162
4162: Complete assoc. items on type parameters r=jonas-schievink a=jonas-schievink This is fairly messy and seems to leak a lot through the `ra_hir` abstraction (`TypeNs`, `AssocItemId`, ...), so I'd be glad for any advise for how to improve this. Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
2 parents 4ff3573 + 0cd6a88 commit 913eff5

File tree

5 files changed

+402
-68
lines changed

5 files changed

+402
-68
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: 41 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_type_shorthand_candidates;
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,44 @@ 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(_))
53+
| PathResolution::Def(ModuleDef::EnumVariant(_))
54+
| PathResolution::Def(ModuleDef::Function(_))
55+
| PathResolution::Def(ModuleDef::Module(_))
56+
| PathResolution::Def(ModuleDef::Static(_))
57+
| PathResolution::Def(ModuleDef::Trait(_)) => None,
58+
PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
59+
Some(TypeNs::TypeAliasId((*alias).into()))
60+
}
61+
PathResolution::Local(_) | PathResolution::Macro(_) => None,
62+
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
63+
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
64+
PathResolution::AssocItem(AssocItem::Const(_))
65+
| PathResolution::AssocItem(AssocItem::Function(_)) => None,
66+
PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
67+
Some(TypeNs::TypeAliasId((*alias).into()))
68+
}
69+
}
70+
}
71+
72+
/// Returns an iterator over associated types that may be specified after this path (using
73+
/// `Ty::Assoc` syntax).
74+
pub fn assoc_type_shorthand_candidates<R>(
75+
&self,
76+
db: &dyn HirDatabase,
77+
mut cb: impl FnMut(TypeAlias) -> Option<R>,
78+
) -> Option<R> {
79+
associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into()))
80+
}
81+
}
82+
4383
/// Primary API to get semantic information, like types, from syntax trees.
4484
pub struct Semantics<'db, DB> {
4585
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_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId,
70+
TyLoweringContext, ValueTyDefId,
7071
};
7172
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
7273

crates/ra_hir_ty/src/lower.rs

Lines changed: 88 additions & 55 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,38 @@ 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),
387+
if let Some(res) = res {
388+
let ty =
389+
associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| {
390+
if name == segment.name {
391+
let substs = match ctx.type_param_mode {
392+
TypeParamLoweringMode::Placeholder => {
393+
// if we're lowering to placeholders, we have to put
394+
// them in now
395+
let s = Substs::type_params(
396+
ctx.db,
397+
ctx.resolver.generic_def().expect(
398+
"there should be generics if there's a generic param",
399+
),
400+
);
401+
t.substs.clone().subst_bound_vars(&s)
402+
}
403+
TypeParamLoweringMode::Variable => t.substs.clone(),
409404
};
410-
traits_.push(trait_ref);
405+
// FIXME handle type parameters on the segment
406+
return Some(Ty::Projection(ProjectionTy {
407+
associated_ty,
408+
parameters: substs,
409+
}));
411410
}
412-
}
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-
}
411+
412+
None
413+
});
414+
415+
ty.unwrap_or(Ty::Unknown)
416+
} else {
417+
Ty::Unknown
439418
}
440-
Ty::Unknown
441419
}
442420

443421
fn from_hir_path_inner(
@@ -694,6 +672,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
694672
}
695673
}
696674

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

0 commit comments

Comments
 (0)