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