ide_completion/completions/
type.rs1use hir::{HirDisplay, ScopeDef};
4use syntax::{AstNode, ast};
5
6use crate::{
7 CompletionContext, Completions,
8 context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
9 render::render_type_inference,
10};
11
12pub(crate) fn complete_type_path(
13 acc: &mut Completions,
14 ctx: &CompletionContext<'_>,
15 path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
16 location: &TypeLocation,
17) {
18 let _p = tracing::info_span!("complete_type_path").entered();
19
20 let scope_def_applicable = |def| {
21 use hir::{GenericParam::*, ModuleDef::*};
22 match def {
23 ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(),
24 ScopeDef::Label(_) => false,
25 ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false,
27 ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
29 location.complete_consts()
30 }
31 ScopeDef::ImplSelfType(_) => location.complete_self_type(),
32 ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
34 ScopeDef::ModuleDef(Trait(_) | Module(_))
35 if matches!(location, TypeLocation::ImplTrait) =>
36 {
37 true
38 }
39 ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_))
41 | ScopeDef::AdtSelfType(_)
42 | ScopeDef::Unknown
43 | ScopeDef::GenericParam(TypeParam(_)) => location.complete_types(),
44 }
45 };
46
47 let add_assoc_item = |acc: &mut Completions, item| match item {
48 hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArg { .. }) => {
49 acc.add_const(ctx, ct)
50 }
51 hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
52 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
53 };
54
55 match qualified {
56 Qualified::TypeAnchor { ty: None, trait_: None } => ctx
57 .traits_in_scope()
58 .iter()
59 .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
60 .for_each(|item| add_assoc_item(acc, item)),
61 Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
62 trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
63 }
64 Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
65 ctx.iterate_path_candidates(ty, |item| {
66 add_assoc_item(acc, item);
67 });
68
69 ty.iterate_assoc_items(ctx.db, |item| {
71 if let hir::AssocItem::TypeAlias(ty) = item {
72 acc.add_type_alias(ctx, ty)
73 }
74 None::<()>
75 });
76 }
77 Qualified::With { resolution: None, .. } => {}
78 Qualified::With { resolution: Some(resolution), .. } => {
79 ctx.scope.assoc_type_shorthand_candidates(resolution, |alias| {
81 acc.add_type_alias(ctx, alias);
82 });
83
84 match resolution {
85 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
86 let module_scope = module.scope(ctx.db, Some(ctx.module));
87 for (name, def) in module_scope {
88 if scope_def_applicable(def) {
89 acc.add_path_resolution(ctx, path_ctx, name, def, vec![]);
90 }
91 }
92 }
93 hir::PathResolution::Def(
94 def @ (hir::ModuleDef::Adt(_)
95 | hir::ModuleDef::TypeAlias(_)
96 | hir::ModuleDef::BuiltinType(_)),
97 ) => {
98 let ty = match def {
99 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
100 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
101 hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db),
102 _ => return,
103 };
104
105 ctx.iterate_path_candidates(&ty, |item| {
109 add_assoc_item(acc, item);
110 });
111
112 ty.iterate_assoc_items(ctx.db, |item| {
114 if let hir::AssocItem::TypeAlias(ty) = item {
115 acc.add_type_alias(ctx, ty)
116 }
117 None::<()>
118 });
119 }
120 hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
121 for item in t.items(ctx.db) {
123 add_assoc_item(acc, item);
124 }
125 }
126 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
127 let ty = match resolution {
128 hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
129 hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
130 _ => return,
131 };
132
133 ctx.iterate_path_candidates(&ty, |item| {
134 add_assoc_item(acc, item);
135 });
136 }
137 _ => (),
138 }
139 }
140 Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
141 Qualified::No => {
142 match location {
143 TypeLocation::TypeBound => {
144 acc.add_nameref_keywords_with_colon(ctx);
145 ctx.process_all_names(&mut |name, res, doc_aliases| {
146 let add_resolution = match res {
147 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
148 mac.is_fn_like(ctx.db)
149 }
150 ScopeDef::ModuleDef(
151 hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
152 ) => true,
153 _ => false,
154 };
155 if add_resolution {
156 acc.add_path_resolution(ctx, path_ctx, name, res, doc_aliases);
157 }
158 });
159 return;
160 }
161 TypeLocation::GenericArg {
162 args: Some(arg_list), of_trait: Some(trait_), ..
163 } => {
164 if arg_list.syntax().ancestors().find_map(ast::TypeBound::cast).is_some() {
165 let arg_idx = arg_list
166 .generic_args()
167 .filter(|arg| {
168 arg.syntax().text_range().end()
169 < ctx.original_token.text_range().start()
170 })
171 .count();
172
173 let n_required_params = trait_.type_or_const_param_count(ctx.sema.db, true);
174 if arg_idx >= n_required_params {
175 trait_.items_with_supertraits(ctx.sema.db).into_iter().for_each(|it| {
176 if let hir::AssocItem::TypeAlias(alias) = it {
177 cov_mark::hit!(complete_assoc_type_in_generics_list);
178 acc.add_type_alias_with_eq(ctx, alias);
179 }
180 });
181
182 let n_params = trait_.type_or_const_param_count(ctx.sema.db, false);
183 if arg_idx >= n_params {
184 return; }
186 }
187 }
188 }
189 TypeLocation::ImplTrait => {
190 acc.add_nameref_keywords_with_colon(ctx);
191 ctx.process_all_names(&mut |name, def, doc_aliases| {
192 let is_trait_or_module = matches!(
193 def,
194 ScopeDef::ModuleDef(
195 hir::ModuleDef::Module(_) | hir::ModuleDef::Trait(_)
196 )
197 );
198 if is_trait_or_module {
199 acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
200 }
201 });
202 return;
203 }
204 _ => {}
205 };
206
207 acc.add_nameref_keywords_with_colon(ctx);
208 acc.add_type_keywords(ctx);
209 ctx.process_all_names(&mut |name, def, doc_aliases| {
210 if scope_def_applicable(def) {
211 acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases);
212 }
213 });
214 }
215 }
216}
217
218pub(crate) fn complete_ascribed_type(
219 acc: &mut Completions,
220 ctx: &CompletionContext<'_>,
221 path_ctx: &PathCompletionCtx<'_>,
222 ascription: &TypeAscriptionTarget,
223) -> Option<()> {
224 if !path_ctx.is_trivial_path() {
225 return None;
226 }
227 let ty = match ascription {
228 TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
229 ctx.sema.type_of_pat(pat.as_ref()?)
230 }
231 TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => {
232 ctx.sema.type_of_expr(exp.as_ref()?)
233 }
234 }?
235 .adjusted();
236 if !ty.is_unknown() {
237 let ty_string = ty.display_source_code(ctx.db, ctx.module.into(), true).ok()?;
238 acc.add(render_type_inference(ty_string, ctx));
239 }
240 None
241}