diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-04-29 23:24:17 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-29 23:24:17 +0100 |
commit | 913eff5ad73ffc95e9b48b4905b9d823e74017d6 (patch) | |
tree | 3f05c054c5c143862b9abde47bda2cd4fab2ded9 /crates/ra_hir_ty | |
parent | 4ff3573e18114e044ed74e785f099a023ebfbf5d (diff) | |
parent | 0cd6a88cf6f80d48669c6136f5fa814fcdafe8e2 (diff) |
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 <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 143 |
2 files changed, 90 insertions, 56 deletions
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index a8ef32ec5..a6f56c661 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_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, |
70 | TyLoweringContext, 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..9ad6dbe07 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,38 @@ 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 = |
388 | None => return Ty::Unknown, | 389 | associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| { |
389 | Some(trait_ref) => vec![trait_ref.value], | 390 | if name == segment.name { |
390 | }, | 391 | let substs = match ctx.type_param_mode { |
391 | Some(TypeNs::GenericParam(param_id)) => { | 392 | TypeParamLoweringMode::Placeholder => { |
392 | let predicates = ctx.db.generic_predicates_for_param(param_id); | 393 | // if we're lowering to placeholders, we have to put |
393 | let mut traits_: Vec<_> = predicates | 394 | // them in now |
394 | .iter() | 395 | let s = Substs::type_params( |
395 | .filter_map(|pred| match &pred.value { | 396 | ctx.db, |
396 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | 397 | ctx.resolver.generic_def().expect( |
397 | _ => None, | 398 | "there should be generics if there's a generic param", |
398 | }) | 399 | ), |
399 | .collect(); | 400 | ); |
400 | // Handle `Self::Type` referring to own associated type in trait definitions | 401 | t.substs.clone().subst_bound_vars(&s) |
401 | if let GenericDefId::TraitId(trait_id) = param_id.parent { | 402 | } |
402 | let generics = generics(ctx.db.upcast(), trait_id.into()); | 403 | TypeParamLoweringMode::Variable => t.substs.clone(), |
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 | }; | 404 | }; |
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 | })); | ||
411 | } | 410 | } |
412 | } | 411 | |
413 | traits_ | 412 | None |
414 | } | 413 | }); |
415 | _ => return Ty::Unknown, | 414 | |
416 | }; | 415 | ty.unwrap_or(Ty::Unknown) |
417 | let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t)); | 416 | } else { |
418 | for t in traits { | 417 | Ty::Unknown |
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 | } | ||
439 | } | 418 | } |
440 | Ty::Unknown | ||
441 | } | 419 | } |
442 | 420 | ||
443 | fn from_hir_path_inner( | 421 | fn from_hir_path_inner( |
@@ -694,6 +672,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | |||
694 | } | 672 | } |
695 | } | 673 | } |
696 | 674 | ||
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 | |||
697 | /// Build the type of all specific fields of a struct or enum variant. | 730 | /// Build the type of all specific fields of a struct or enum variant. |
698 | pub(crate) fn field_types_query( | 731 | pub(crate) fn field_types_query( |
699 | db: &dyn HirDatabase, | 732 | db: &dyn HirDatabase, |