aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/lower.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-04-29 23:24:17 +0100
committerGitHub <[email protected]>2020-04-29 23:24:17 +0100
commit913eff5ad73ffc95e9b48b4905b9d823e74017d6 (patch)
tree3f05c054c5c143862b9abde47bda2cd4fab2ded9 /crates/ra_hir_ty/src/lower.rs
parent4ff3573e18114e044ed74e785f099a023ebfbf5d (diff)
parent0cd6a88cf6f80d48669c6136f5fa814fcdafe8e2 (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/src/lower.rs')
-rw-r--r--crates/ra_hir_ty/src/lower.rs143
1 files changed, 88 insertions, 55 deletions
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};
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,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
675pub 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.
698pub(crate) fn field_types_query( 731pub(crate) fn field_types_query(
699 db: &dyn HirDatabase, 732 db: &dyn HirDatabase,