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 | |
parent | 4ff3573e18114e044ed74e785f099a023ebfbf5d (diff) |
Complete assoc. items on type parameters
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 144 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_qualified_path.rs | 273 |
5 files changed, 408 insertions, 69 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 3fb419571..af59aa1b6 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -953,6 +953,16 @@ impl TypeParam { | |||
953 | pub fn module(self, db: &dyn HirDatabase) -> Module { | 953 | pub fn module(self, db: &dyn HirDatabase) -> Module { |
954 | self.id.parent.module(db.upcast()).into() | 954 | self.id.parent.module(db.upcast()).into() |
955 | } | 955 | } |
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 | } | ||
956 | } | 966 | } |
957 | 967 | ||
958 | // FIXME: rename from `ImplDef` to `Impl` | 968 | // FIXME: rename from `ImplDef` to `Impl` |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 86bfb416c..687f83f60 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -9,6 +9,7 @@ use hir_def::{ | |||
9 | AsMacroCall, TraitId, | 9 | AsMacroCall, TraitId, |
10 | }; | 10 | }; |
11 | use hir_expand::ExpansionInfo; | 11 | use hir_expand::ExpansionInfo; |
12 | use hir_ty::associated_types; | ||
12 | use itertools::Itertools; | 13 | use itertools::Itertools; |
13 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
14 | use ra_prof::profile; | 15 | use ra_prof::profile; |
@@ -24,8 +25,9 @@ use crate::{ | |||
24 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
25 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
26 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | 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, |
28 | }; | 29 | }; |
30 | use resolver::TypeNs; | ||
29 | 31 | ||
30 | #[derive(Debug, Clone, PartialEq, Eq)] | 32 | #[derive(Debug, Clone, PartialEq, Eq)] |
31 | pub enum PathResolution { | 33 | pub enum PathResolution { |
@@ -40,6 +42,49 @@ pub enum PathResolution { | |||
40 | AssocItem(AssocItem), | 42 | AssocItem(AssocItem), |
41 | } | 43 | } |
42 | 44 | ||
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(_)) => None, | ||
53 | PathResolution::Def(ModuleDef::EnumVariant(_)) => None, | ||
54 | PathResolution::Def(ModuleDef::Function(_)) => None, | ||
55 | PathResolution::Def(ModuleDef::Module(_)) => None, | ||
56 | PathResolution::Def(ModuleDef::Static(_)) => None, | ||
57 | PathResolution::Def(ModuleDef::Trait(_)) => None, | ||
58 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | ||
59 | Some(TypeNs::TypeAliasId(alias.into())) | ||
60 | } | ||
61 | PathResolution::Local(_) => None, | ||
62 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam(param.into())), | ||
63 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType(impl_def.into())), | ||
64 | PathResolution::Macro(_) => None, | ||
65 | PathResolution::AssocItem(AssocItem::Const(_)) => None, | ||
66 | PathResolution::AssocItem(AssocItem::Function(_)) => None, | ||
67 | PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => { | ||
68 | Some(TypeNs::TypeAliasId(alias.into())) | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | /// Returns an iterator over associated types that may be specified after this path (using | ||
74 | /// `Ty::Assoc` syntax). | ||
75 | pub fn assoc_type_shorthand_candidates<R>( | ||
76 | &self, | ||
77 | db: &dyn HirDatabase, | ||
78 | mut cb: impl FnMut(TypeAlias) -> Option<R>, | ||
79 | ) -> Option<R> { | ||
80 | if let Some(res) = self.clone().in_type_ns() { | ||
81 | associated_types(db, res, |_, _, id| cb(id.into())) | ||
82 | } else { | ||
83 | None | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
43 | /// Primary API to get semantic information, like types, from syntax trees. | 88 | /// Primary API to get semantic information, like types, from syntax trees. |
44 | pub struct Semantics<'db, DB> { | 89 | pub struct Semantics<'db, DB> { |
45 | pub db: &'db DB, | 90 | pub db: &'db DB, |
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, |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index dd10f74e6..69e789a49 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -5,19 +5,30 @@ use ra_syntax::AstNode; | |||
5 | use test_utils::tested_by; | 5 | use test_utils::tested_by; |
6 | 6 | ||
7 | use crate::completion::{CompletionContext, Completions}; | 7 | use crate::completion::{CompletionContext, Completions}; |
8 | use rustc_hash::FxHashSet; | ||
8 | 9 | ||
9 | pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | let path = match &ctx.path_prefix { | 11 | let path = match &ctx.path_prefix { |
11 | Some(path) => path.clone(), | 12 | Some(path) => path.clone(), |
12 | _ => return, | 13 | _ => return, |
13 | }; | 14 | }; |
14 | let def = match ctx.scope().resolve_hir_path(&path) { | 15 | let scope = ctx.scope(); |
15 | Some(PathResolution::Def(def)) => def, | 16 | let context_module = scope.module(); |
16 | _ => return, | 17 | |
18 | let res = if let Some(res) = scope.resolve_hir_path(&path) { | ||
19 | res | ||
20 | } else { | ||
21 | return; | ||
17 | }; | 22 | }; |
18 | let context_module = ctx.scope().module(); | 23 | |
19 | match def { | 24 | // Add associated types on type parameters and `Self`. |
20 | hir::ModuleDef::Module(module) => { | 25 | res.assoc_type_shorthand_candidates(ctx.db, |alias| { |
26 | acc.add_type_alias(ctx, alias); | ||
27 | None::<()> | ||
28 | }); | ||
29 | |||
30 | match res { | ||
31 | PathResolution::Def(hir::ModuleDef::Module(module)) => { | ||
21 | let module_scope = module.scope(ctx.db, context_module); | 32 | let module_scope = module.scope(ctx.db, context_module); |
22 | for (name, def) in module_scope { | 33 | for (name, def) in module_scope { |
23 | if ctx.use_item_syntax.is_some() { | 34 | if ctx.use_item_syntax.is_some() { |
@@ -35,7 +46,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
35 | acc.add_resolution(ctx, name.to_string(), &def); | 46 | acc.add_resolution(ctx, name.to_string(), &def); |
36 | } | 47 | } |
37 | } | 48 | } |
38 | hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { | 49 | PathResolution::Def(def @ hir::ModuleDef::Adt(_)) |
50 | | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) => { | ||
39 | if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { | 51 | if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { |
40 | for variant in e.variants(ctx.db) { | 52 | for variant in e.variants(ctx.db) { |
41 | acc.add_enum_variant(ctx, variant, None); | 53 | acc.add_enum_variant(ctx, variant, None); |
@@ -46,8 +58,10 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
46 | hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), | 58 | hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), |
47 | _ => unreachable!(), | 59 | _ => unreachable!(), |
48 | }; | 60 | }; |
49 | // Iterate assoc types separately | 61 | |
50 | // FIXME: complete T::AssocType | 62 | // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType. |
63 | // (where AssocType is defined on a trait, not an inherent impl) | ||
64 | |||
51 | let krate = ctx.krate; | 65 | let krate = ctx.krate; |
52 | if let Some(krate) = krate { | 66 | if let Some(krate) = krate { |
53 | let traits_in_scope = ctx.scope().traits_in_scope(); | 67 | let traits_in_scope = ctx.scope().traits_in_scope(); |
@@ -65,6 +79,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
65 | None::<()> | 79 | None::<()> |
66 | }); | 80 | }); |
67 | 81 | ||
82 | // Iterate assoc types separately | ||
68 | ty.iterate_impl_items(ctx.db, krate, |item| { | 83 | ty.iterate_impl_items(ctx.db, krate, |item| { |
69 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 84 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
70 | return None; | 85 | return None; |
@@ -77,7 +92,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
77 | }); | 92 | }); |
78 | } | 93 | } |
79 | } | 94 | } |
80 | hir::ModuleDef::Trait(t) => { | 95 | PathResolution::Def(hir::ModuleDef::Trait(t)) => { |
96 | // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`. | ||
81 | for item in t.items(ctx.db) { | 97 | for item in t.items(ctx.db) { |
82 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 98 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
83 | continue; | 99 | continue; |
@@ -91,8 +107,38 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
91 | } | 107 | } |
92 | } | 108 | } |
93 | } | 109 | } |
110 | PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { | ||
111 | if let Some(krate) = ctx.krate { | ||
112 | let ty = match res { | ||
113 | PathResolution::TypeParam(param) => param.ty(ctx.db), | ||
114 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), | ||
115 | _ => return, | ||
116 | }; | ||
117 | |||
118 | let traits_in_scope = ctx.scope().traits_in_scope(); | ||
119 | let mut seen = FxHashSet::default(); | ||
120 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | ||
121 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
122 | return None; | ||
123 | } | ||
124 | |||
125 | // We might iterate candidates of a trait multiple times here, so deduplicate | ||
126 | // them. | ||
127 | if seen.insert(item) { | ||
128 | match item { | ||
129 | hir::AssocItem::Function(func) => { | ||
130 | acc.add_function(ctx, func, None); | ||
131 | } | ||
132 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
133 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
134 | } | ||
135 | } | ||
136 | None::<()> | ||
137 | }); | ||
138 | } | ||
139 | } | ||
94 | _ => {} | 140 | _ => {} |
95 | }; | 141 | } |
96 | } | 142 | } |
97 | 143 | ||
98 | #[cfg(test)] | 144 | #[cfg(test)] |
@@ -844,6 +890,211 @@ mod tests { | |||
844 | } | 890 | } |
845 | 891 | ||
846 | #[test] | 892 | #[test] |
893 | fn completes_ty_param_assoc_ty() { | ||
894 | assert_debug_snapshot!( | ||
895 | do_reference_completion( | ||
896 | " | ||
897 | //- /lib.rs | ||
898 | trait Super { | ||
899 | type Ty; | ||
900 | const CONST: u8; | ||
901 | fn func() {} | ||
902 | fn method(&self) {} | ||
903 | } | ||
904 | |||
905 | trait Sub: Super { | ||
906 | type SubTy; | ||
907 | const C2: (); | ||
908 | fn subfunc() {} | ||
909 | fn submethod(&self) {} | ||
910 | } | ||
911 | |||
912 | fn foo<T: Sub>() { | ||
913 | T::<|> | ||
914 | } | ||
915 | " | ||
916 | ), | ||
917 | @r###" | ||
918 | [ | ||
919 | CompletionItem { | ||
920 | label: "C2", | ||
921 | source_range: 219..219, | ||
922 | delete: 219..219, | ||
923 | insert: "C2", | ||
924 | kind: Const, | ||
925 | detail: "const C2: ();", | ||
926 | }, | ||
927 | CompletionItem { | ||
928 | label: "CONST", | ||
929 | source_range: 219..219, | ||
930 | delete: 219..219, | ||
931 | insert: "CONST", | ||
932 | kind: Const, | ||
933 | detail: "const CONST: u8;", | ||
934 | }, | ||
935 | CompletionItem { | ||
936 | label: "SubTy", | ||
937 | source_range: 219..219, | ||
938 | delete: 219..219, | ||
939 | insert: "SubTy", | ||
940 | kind: TypeAlias, | ||
941 | detail: "type SubTy;", | ||
942 | }, | ||
943 | CompletionItem { | ||
944 | label: "Ty", | ||
945 | source_range: 219..219, | ||
946 | delete: 219..219, | ||
947 | insert: "Ty", | ||
948 | kind: TypeAlias, | ||
949 | detail: "type Ty;", | ||
950 | }, | ||
951 | CompletionItem { | ||
952 | label: "func()", | ||
953 | source_range: 219..219, | ||
954 | delete: 219..219, | ||
955 | insert: "func()$0", | ||
956 | kind: Function, | ||
957 | lookup: "func", | ||
958 | detail: "fn func()", | ||
959 | }, | ||
960 | CompletionItem { | ||
961 | label: "method()", | ||
962 | source_range: 219..219, | ||
963 | delete: 219..219, | ||
964 | insert: "method()$0", | ||
965 | kind: Method, | ||
966 | lookup: "method", | ||
967 | detail: "fn method(&self)", | ||
968 | }, | ||
969 | CompletionItem { | ||
970 | label: "subfunc()", | ||
971 | source_range: 219..219, | ||
972 | delete: 219..219, | ||
973 | insert: "subfunc()$0", | ||
974 | kind: Function, | ||
975 | lookup: "subfunc", | ||
976 | detail: "fn subfunc()", | ||
977 | }, | ||
978 | CompletionItem { | ||
979 | label: "submethod()", | ||
980 | source_range: 219..219, | ||
981 | delete: 219..219, | ||
982 | insert: "submethod()$0", | ||
983 | kind: Method, | ||
984 | lookup: "submethod", | ||
985 | detail: "fn submethod(&self)", | ||
986 | }, | ||
987 | ] | ||
988 | "### | ||
989 | ); | ||
990 | } | ||
991 | |||
992 | #[test] | ||
993 | fn completes_self_param_assoc_ty() { | ||
994 | assert_debug_snapshot!( | ||
995 | do_reference_completion( | ||
996 | " | ||
997 | //- /lib.rs | ||
998 | trait Super { | ||
999 | type Ty; | ||
1000 | const CONST: u8 = 0; | ||
1001 | fn func() {} | ||
1002 | fn method(&self) {} | ||
1003 | } | ||
1004 | |||
1005 | trait Sub: Super { | ||
1006 | type SubTy; | ||
1007 | const C2: () = (); | ||
1008 | fn subfunc() {} | ||
1009 | fn submethod(&self) {} | ||
1010 | } | ||
1011 | |||
1012 | struct Wrap<T>(T); | ||
1013 | impl<T> Super for Wrap<T> {} | ||
1014 | impl<T> Sub for Wrap<T> { | ||
1015 | fn subfunc() { | ||
1016 | // Should be able to assume `Self: Sub + Super` | ||
1017 | Self::<|> | ||
1018 | } | ||
1019 | } | ||
1020 | " | ||
1021 | ), | ||
1022 | @r###" | ||
1023 | [ | ||
1024 | CompletionItem { | ||
1025 | label: "C2", | ||
1026 | source_range: 365..365, | ||
1027 | delete: 365..365, | ||
1028 | insert: "C2", | ||
1029 | kind: Const, | ||
1030 | detail: "const C2: () = ();", | ||
1031 | }, | ||
1032 | CompletionItem { | ||
1033 | label: "CONST", | ||
1034 | source_range: 365..365, | ||
1035 | delete: 365..365, | ||
1036 | insert: "CONST", | ||
1037 | kind: Const, | ||
1038 | detail: "const CONST: u8 = 0;", | ||
1039 | }, | ||
1040 | CompletionItem { | ||
1041 | label: "SubTy", | ||
1042 | source_range: 365..365, | ||
1043 | delete: 365..365, | ||
1044 | insert: "SubTy", | ||
1045 | kind: TypeAlias, | ||
1046 | detail: "type SubTy;", | ||
1047 | }, | ||
1048 | CompletionItem { | ||
1049 | label: "Ty", | ||
1050 | source_range: 365..365, | ||
1051 | delete: 365..365, | ||
1052 | insert: "Ty", | ||
1053 | kind: TypeAlias, | ||
1054 | detail: "type Ty;", | ||
1055 | }, | ||
1056 | CompletionItem { | ||
1057 | label: "func()", | ||
1058 | source_range: 365..365, | ||
1059 | delete: 365..365, | ||
1060 | insert: "func()$0", | ||
1061 | kind: Function, | ||
1062 | lookup: "func", | ||
1063 | detail: "fn func()", | ||
1064 | }, | ||
1065 | CompletionItem { | ||
1066 | label: "method()", | ||
1067 | source_range: 365..365, | ||
1068 | delete: 365..365, | ||
1069 | insert: "method()$0", | ||
1070 | kind: Method, | ||
1071 | lookup: "method", | ||
1072 | detail: "fn method(&self)", | ||
1073 | }, | ||
1074 | CompletionItem { | ||
1075 | label: "subfunc()", | ||
1076 | source_range: 365..365, | ||
1077 | delete: 365..365, | ||
1078 | insert: "subfunc()$0", | ||
1079 | kind: Function, | ||
1080 | lookup: "subfunc", | ||
1081 | detail: "fn subfunc()", | ||
1082 | }, | ||
1083 | CompletionItem { | ||
1084 | label: "submethod()", | ||
1085 | source_range: 365..365, | ||
1086 | delete: 365..365, | ||
1087 | insert: "submethod()$0", | ||
1088 | kind: Method, | ||
1089 | lookup: "submethod", | ||
1090 | detail: "fn submethod(&self)", | ||
1091 | }, | ||
1092 | ] | ||
1093 | "### | ||
1094 | ); | ||
1095 | } | ||
1096 | |||
1097 | #[test] | ||
847 | fn completes_type_alias() { | 1098 | fn completes_type_alias() { |
848 | assert_debug_snapshot!( | 1099 | assert_debug_snapshot!( |
849 | do_reference_completion( | 1100 | do_reference_completion( |