diff options
author | Jonas Schievink <[email protected]> | 2020-04-27 23:40:32 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-04-29 23:10:30 +0100 |
commit | 8c2670026a4c864a67a06bab654e203ed068f021 (patch) | |
tree | 95ed082f04067bcacfb40b1b871b64df3eb4be61 /crates/ra_hir_ty/src | |
parent | 4ff3573e18114e044ed74e785f099a023ebfbf5d (diff) |
Complete assoc. items on type parameters
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 144 |
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; | |||
66 | pub use infer::{InferTy, InferenceResult}; | 66 | pub use infer::{InferTy, InferenceResult}; |
67 | pub use lower::CallableDef; | 67 | pub use lower::CallableDef; |
68 | pub use lower::{ | 68 | pub use lower::{ |
69 | callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, | 69 | associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, |
70 | ValueTyDefId, | ||
70 | }; | 71 | }; |
71 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 72 | pub 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 | }; |
24 | use ra_arena::map::ArenaMap; | 24 | use ra_arena::map::ArenaMap; |
25 | use ra_db::CrateId; | 25 | use 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 | }; |
37 | use hir_expand::name::Name; | ||
37 | 38 | ||
38 | #[derive(Debug)] | 39 | #[derive(Debug)] |
39 | pub struct TyLoweringContext<'a> { | 40 | pub 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 | ||
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 | |||
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. |
698 | pub(crate) fn field_types_query( | 730 | pub(crate) fn field_types_query( |
699 | db: &dyn HirDatabase, | 731 | db: &dyn HirDatabase, |