aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-04-27 23:40:32 +0100
committerJonas Schievink <[email protected]>2020-04-29 23:10:30 +0100
commit8c2670026a4c864a67a06bab654e203ed068f021 (patch)
tree95ed082f04067bcacfb40b1b871b64df3eb4be61 /crates/ra_hir_ty
parent4ff3573e18114e044ed74e785f099a023ebfbf5d (diff)
Complete assoc. items on type parameters
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/lib.rs3
-rw-r--r--crates/ra_hir_ty/src/lower.rs144
2 files changed, 90 insertions, 57 deletions
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a8ef32ec5..341a18683 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -66,7 +66,8 @@ pub use autoderef::autoderef;
66pub use infer::{InferTy, InferenceResult}; 66pub use infer::{InferTy, InferenceResult};
67pub use lower::CallableDef; 67pub use lower::CallableDef;
68pub use lower::{ 68pub use lower::{
69 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, 69 associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext,
70 ValueTyDefId,
70}; 71};
71pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 72pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
72 73
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index a6f893037..67e5c1ccd 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -17,9 +17,9 @@ use hir_def::{
17 path::{GenericArg, Path, PathSegment, PathSegments}, 17 path::{GenericArg, Path, PathSegment, PathSegments},
18 resolver::{HasResolver, Resolver, TypeNs}, 18 resolver::{HasResolver, Resolver, TypeNs},
19 type_ref::{TypeBound, TypeRef}, 19 type_ref::{TypeBound, TypeRef},
20 AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, 20 AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
21 ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 21 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
22 VariantId, 22 UnionId, VariantId,
23}; 23};
24use ra_arena::map::ArenaMap; 24use ra_arena::map::ArenaMap;
25use ra_db::CrateId; 25use ra_db::CrateId;
@@ -34,6 +34,7 @@ use crate::{
34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, 34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
36}; 36};
37use hir_expand::name::Name;
37 38
38#[derive(Debug)] 39#[derive(Debug)]
39pub struct TyLoweringContext<'a> { 40pub struct TyLoweringContext<'a> {
@@ -383,61 +384,37 @@ impl Ty {
383 res: Option<TypeNs>, 384 res: Option<TypeNs>,
384 segment: PathSegment<'_>, 385 segment: PathSegment<'_>,
385 ) -> Ty { 386 ) -> Ty {
386 let traits_from_env: Vec<_> = match res { 387 if let Some(res) = res {
387 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { 388 let ty = associated_types(ctx.db, res, move |name, t, associated_ty| {
388 None => return Ty::Unknown, 389 if name == segment.name {
389 Some(trait_ref) => vec![trait_ref.value], 390 let substs = match ctx.type_param_mode {
390 }, 391 TypeParamLoweringMode::Placeholder => {
391 Some(TypeNs::GenericParam(param_id)) => { 392 // if we're lowering to placeholders, we have to put
392 let predicates = ctx.db.generic_predicates_for_param(param_id); 393 // them in now
393 let mut traits_: Vec<_> = predicates 394 let s = Substs::type_params(
394 .iter() 395 ctx.db,
395 .filter_map(|pred| match &pred.value { 396 ctx.resolver
396 GenericPredicate::Implemented(tr) => Some(tr.clone()), 397 .generic_def()
397 _ => None, 398 .expect("there should be generics if there's a generic param"),
398 }) 399 );
399 .collect(); 400 t.substs.clone().subst_bound_vars(&s)
400 // Handle `Self::Type` referring to own associated type in trait definitions 401 }
401 if let GenericDefId::TraitId(trait_id) = param_id.parent { 402 TypeParamLoweringMode::Variable => t.substs.clone(),
402 let generics = generics(ctx.db.upcast(), trait_id.into()); 403 };
403 if generics.params.types[param_id.local_id].provenance 404 // FIXME handle type parameters on the segment
404 == TypeParamProvenance::TraitSelf 405 return Some(Ty::Projection(ProjectionTy {
405 { 406 associated_ty,
406 let trait_ref = TraitRef { 407 parameters: substs,
407 trait_: trait_id, 408 }));
408 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
409 };
410 traits_.push(trait_ref);
411 }
412 } 409 }
413 traits_ 410
414 } 411 None
415 _ => return Ty::Unknown, 412 });
416 }; 413
417 let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t)); 414 ty.unwrap_or(Ty::Unknown)
418 for t in traits { 415 } else {
419 if let Some(associated_ty) = 416 Ty::Unknown
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 }
439 } 417 }
440 Ty::Unknown
441 } 418 }
442 419
443 fn from_hir_path_inner( 420 fn from_hir_path_inner(
@@ -694,6 +671,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
694 } 671 }
695} 672}
696 673
674pub 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
697/// Build the type of all specific fields of a struct or enum variant. 729/// Build the type of all specific fields of a struct or enum variant.
698pub(crate) fn field_types_query( 730pub(crate) fn field_types_query(
699 db: &dyn HirDatabase, 731 db: &dyn HirDatabase,