]>
Commit | Line | Data |
---|---|---|
064997fb FG |
1 | //! Lookup hir elements using positions in the source code. This is a lossy |
2 | //! transformation: in general, a single source might correspond to several | |
3 | //! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on | |
4 | //! modules. | |
5 | //! | |
6 | //! So, this modules should not be used during hir construction, it exists | |
7 | //! purely for "IDE needs". | |
8 | use std::{ | |
9 | iter::{self, once}, | |
10 | sync::Arc, | |
11 | }; | |
12 | ||
353b0b11 | 13 | use either::Either; |
064997fb FG |
14 | use hir_def::{ |
15 | body::{ | |
16 | self, | |
17 | scope::{ExprScopes, ScopeId}, | |
18 | Body, BodySourceMap, | |
19 | }, | |
20 | expr::{ExprId, Pat, PatId}, | |
9ffffee4 | 21 | lang_item::LangItem, |
064997fb FG |
22 | macro_id_to_def_id, |
23 | path::{ModPath, Path, PathKind}, | |
24 | resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, | |
25 | type_ref::Mutability, | |
9c376795 FG |
26 | AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, |
27 | LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId, | |
064997fb FG |
28 | }; |
29 | use hir_expand::{ | |
f2b60f7d FG |
30 | builtin_fn_macro::BuiltinFnLikeExpander, |
31 | hygiene::Hygiene, | |
32 | mod_path::path, | |
33 | name, | |
34 | name::{AsName, Name}, | |
35 | HirFileId, InFile, | |
064997fb FG |
36 | }; |
37 | use hir_ty::{ | |
38 | diagnostics::{ | |
39 | record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, | |
40 | UnsafeExpr, | |
41 | }, | |
9ffffee4 | 42 | method_resolution::{self, lang_items_for_bin_op}, |
487cf647 | 43 | Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, |
064997fb FG |
44 | }; |
45 | use itertools::Itertools; | |
46 | use smallvec::SmallVec; | |
47 | use syntax::{ | |
48 | ast::{self, AstNode}, | |
49 | SyntaxKind, SyntaxNode, TextRange, TextSize, | |
50 | }; | |
51 | ||
52 | use crate::{ | |
53 | db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, | |
54 | BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, | |
353b0b11 | 55 | Struct, ToolModule, Trait, TraitAlias, Type, TypeAlias, Variant, |
064997fb FG |
56 | }; |
57 | ||
58 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | |
59 | /// original source files. It should not be used inside the HIR itself. | |
60 | #[derive(Debug)] | |
61 | pub(crate) struct SourceAnalyzer { | |
62 | pub(crate) file_id: HirFileId, | |
63 | pub(crate) resolver: Resolver, | |
64 | def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>, | |
65 | infer: Option<Arc<InferenceResult>>, | |
66 | } | |
67 | ||
68 | impl SourceAnalyzer { | |
69 | pub(crate) fn new_for_body( | |
70 | db: &dyn HirDatabase, | |
71 | def: DefWithBodyId, | |
72 | node @ InFile { file_id, .. }: InFile<&SyntaxNode>, | |
73 | offset: Option<TextSize>, | |
74 | ) -> SourceAnalyzer { | |
75 | let (body, source_map) = db.body_with_source_map(def); | |
76 | let scopes = db.expr_scopes(def); | |
77 | let scope = match offset { | |
78 | None => scope_for(&scopes, &source_map, node), | |
79 | Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset), | |
80 | }; | |
81 | let resolver = resolver_for_scope(db.upcast(), def, scope); | |
82 | SourceAnalyzer { | |
83 | resolver, | |
84 | def: Some((def, body, source_map)), | |
85 | infer: Some(db.infer(def)), | |
86 | file_id, | |
87 | } | |
88 | } | |
89 | ||
90 | pub(crate) fn new_for_body_no_infer( | |
91 | db: &dyn HirDatabase, | |
92 | def: DefWithBodyId, | |
93 | node @ InFile { file_id, .. }: InFile<&SyntaxNode>, | |
94 | offset: Option<TextSize>, | |
95 | ) -> SourceAnalyzer { | |
96 | let (body, source_map) = db.body_with_source_map(def); | |
97 | let scopes = db.expr_scopes(def); | |
98 | let scope = match offset { | |
99 | None => scope_for(&scopes, &source_map, node), | |
100 | Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset), | |
101 | }; | |
102 | let resolver = resolver_for_scope(db.upcast(), def, scope); | |
103 | SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id } | |
104 | } | |
105 | ||
106 | pub(crate) fn new_for_resolver( | |
107 | resolver: Resolver, | |
108 | node: InFile<&SyntaxNode>, | |
109 | ) -> SourceAnalyzer { | |
110 | SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id } | |
111 | } | |
112 | ||
113 | fn body_source_map(&self) -> Option<&BodySourceMap> { | |
114 | self.def.as_ref().map(|(.., source_map)| &**source_map) | |
115 | } | |
116 | fn body(&self) -> Option<&Body> { | |
117 | self.def.as_ref().map(|(_, body, _)| &**body) | |
118 | } | |
119 | ||
120 | fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> { | |
121 | let src = match expr { | |
122 | ast::Expr::MacroExpr(expr) => { | |
9c376795 | 123 | self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))? |
064997fb FG |
124 | } |
125 | _ => InFile::new(self.file_id, expr.clone()), | |
126 | }; | |
127 | let sm = self.body_source_map()?; | |
128 | sm.node_expr(src.as_ref()) | |
129 | } | |
130 | ||
131 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { | |
132 | // FIXME: macros, see `expr_id` | |
133 | let src = InFile { file_id: self.file_id, value: pat }; | |
134 | self.body_source_map()?.node_pat(src) | |
135 | } | |
136 | ||
137 | fn expand_expr( | |
138 | &self, | |
139 | db: &dyn HirDatabase, | |
140 | expr: InFile<ast::MacroCall>, | |
141 | ) -> Option<InFile<ast::Expr>> { | |
142 | let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; | |
143 | let expanded = db.parse_or_expand(macro_file)?; | |
f2b60f7d FG |
144 | let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { |
145 | match stmts.expr()? { | |
146 | ast::Expr::MacroExpr(mac) => { | |
147 | self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))? | |
148 | } | |
149 | expr => InFile::new(macro_file, expr), | |
150 | } | |
151 | } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) { | |
152 | self.expand_expr(db, InFile::new(macro_file, call))? | |
153 | } else { | |
154 | InFile::new(macro_file, ast::Expr::cast(expanded)?) | |
064997fb | 155 | }; |
f2b60f7d | 156 | |
064997fb FG |
157 | Some(res) |
158 | } | |
159 | ||
487cf647 | 160 | pub(crate) fn expr_adjustments( |
064997fb FG |
161 | &self, |
162 | db: &dyn HirDatabase, | |
163 | expr: &ast::Expr, | |
487cf647 | 164 | ) -> Option<&[Adjustment]> { |
064997fb FG |
165 | let expr_id = self.expr_id(db, expr)?; |
166 | let infer = self.infer.as_ref()?; | |
487cf647 | 167 | infer.expr_adjustments.get(&expr_id).map(|v| &**v) |
064997fb FG |
168 | } |
169 | ||
170 | pub(crate) fn type_of_expr( | |
171 | &self, | |
172 | db: &dyn HirDatabase, | |
173 | expr: &ast::Expr, | |
174 | ) -> Option<(Type, Option<Type>)> { | |
175 | let expr_id = self.expr_id(db, expr)?; | |
176 | let infer = self.infer.as_ref()?; | |
177 | let coerced = infer | |
178 | .expr_adjustments | |
179 | .get(&expr_id) | |
180 | .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone())); | |
181 | let ty = infer[expr_id].clone(); | |
182 | let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); | |
183 | Some((mk_ty(ty), coerced.map(mk_ty))) | |
184 | } | |
185 | ||
186 | pub(crate) fn type_of_pat( | |
187 | &self, | |
188 | db: &dyn HirDatabase, | |
189 | pat: &ast::Pat, | |
190 | ) -> Option<(Type, Option<Type>)> { | |
191 | let pat_id = self.pat_id(pat)?; | |
192 | let infer = self.infer.as_ref()?; | |
193 | let coerced = infer | |
194 | .pat_adjustments | |
195 | .get(&pat_id) | |
196 | .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone())); | |
197 | let ty = infer[pat_id].clone(); | |
198 | let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); | |
199 | Some((mk_ty(ty), coerced.map(mk_ty))) | |
200 | } | |
201 | ||
202 | pub(crate) fn type_of_self( | |
203 | &self, | |
204 | db: &dyn HirDatabase, | |
205 | param: &ast::SelfParam, | |
206 | ) -> Option<Type> { | |
207 | let src = InFile { file_id: self.file_id, value: param }; | |
208 | let pat_id = self.body_source_map()?.node_self_param(src)?; | |
209 | let ty = self.infer.as_ref()?[pat_id].clone(); | |
210 | Some(Type::new_with_resolver(db, &self.resolver, ty)) | |
211 | } | |
212 | ||
213 | pub(crate) fn binding_mode_of_pat( | |
214 | &self, | |
215 | _db: &dyn HirDatabase, | |
216 | pat: &ast::IdentPat, | |
217 | ) -> Option<BindingMode> { | |
218 | let pat_id = self.pat_id(&pat.clone().into())?; | |
219 | let infer = self.infer.as_ref()?; | |
220 | infer.pat_binding_modes.get(&pat_id).map(|bm| match bm { | |
221 | hir_ty::BindingMode::Move => BindingMode::Move, | |
222 | hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut), | |
223 | hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => { | |
224 | BindingMode::Ref(Mutability::Shared) | |
225 | } | |
226 | }) | |
227 | } | |
228 | pub(crate) fn pattern_adjustments( | |
229 | &self, | |
230 | db: &dyn HirDatabase, | |
231 | pat: &ast::Pat, | |
232 | ) -> Option<SmallVec<[Type; 1]>> { | |
9c376795 | 233 | let pat_id = self.pat_id(pat)?; |
064997fb FG |
234 | let infer = self.infer.as_ref()?; |
235 | Some( | |
236 | infer | |
237 | .pat_adjustments | |
238 | .get(&pat_id)? | |
239 | .iter() | |
240 | .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone())) | |
241 | .collect(), | |
242 | ) | |
243 | } | |
244 | ||
245 | pub(crate) fn resolve_method_call_as_callable( | |
246 | &self, | |
247 | db: &dyn HirDatabase, | |
248 | call: &ast::MethodCallExpr, | |
249 | ) -> Option<Callable> { | |
250 | let expr_id = self.expr_id(db, &call.clone().into())?; | |
251 | let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; | |
252 | let ty = db.value_ty(func.into()).substitute(Interner, &substs); | |
253 | let ty = Type::new_with_resolver(db, &self.resolver, ty); | |
254 | let mut res = ty.as_callable(db)?; | |
255 | res.is_bound_method = true; | |
256 | Some(res) | |
257 | } | |
258 | ||
259 | pub(crate) fn resolve_method_call( | |
260 | &self, | |
261 | db: &dyn HirDatabase, | |
262 | call: &ast::MethodCallExpr, | |
263 | ) -> Option<FunctionId> { | |
264 | let expr_id = self.expr_id(db, &call.clone().into())?; | |
265 | let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; | |
f2b60f7d | 266 | |
487cf647 | 267 | Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)) |
f2b60f7d FG |
268 | } |
269 | ||
353b0b11 FG |
270 | pub(crate) fn resolve_method_call_fallback( |
271 | &self, | |
272 | db: &dyn HirDatabase, | |
273 | call: &ast::MethodCallExpr, | |
274 | ) -> Option<Either<FunctionId, FieldId>> { | |
275 | let expr_id = self.expr_id(db, &call.clone().into())?; | |
276 | let inference_result = self.infer.as_ref()?; | |
277 | match inference_result.method_resolution(expr_id) { | |
278 | Some((f_in_trait, substs)) => { | |
279 | Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))) | |
280 | } | |
281 | None => inference_result.field_resolution(expr_id).map(Either::Right), | |
282 | } | |
283 | } | |
284 | ||
f2b60f7d FG |
285 | pub(crate) fn resolve_await_to_poll( |
286 | &self, | |
287 | db: &dyn HirDatabase, | |
288 | await_expr: &ast::AwaitExpr, | |
289 | ) -> Option<FunctionId> { | |
9c376795 | 290 | let mut ty = self.ty_of_expr(db, &await_expr.expr()?)?.clone(); |
f2b60f7d FG |
291 | |
292 | let into_future_trait = self | |
293 | .resolver | |
294 | .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture]) | |
295 | .map(Trait::from); | |
296 | ||
297 | if let Some(into_future_trait) = into_future_trait { | |
298 | let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone()); | |
299 | if type_.impls_trait(db, into_future_trait, &[]) { | |
300 | let items = into_future_trait.items(db); | |
301 | let into_future_type = items.into_iter().find_map(|item| match item { | |
302 | AssocItem::TypeAlias(alias) | |
303 | if alias.name(db) == hir_expand::name![IntoFuture] => | |
304 | { | |
305 | Some(alias) | |
306 | } | |
307 | _ => None, | |
308 | })?; | |
309 | let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?; | |
310 | ty = future_trait.ty; | |
311 | } | |
312 | } | |
313 | ||
9ffffee4 FG |
314 | let future_trait = db.lang_item(self.resolver.krate(), LangItem::Future)?.as_trait()?; |
315 | let poll_fn = db.lang_item(self.resolver.krate(), LangItem::FuturePoll)?.as_function()?; | |
2b03887a FG |
316 | // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself |
317 | // doesn't have any generic parameters, so we skip building another subst for `poll()`. | |
318 | let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build(); | |
487cf647 | 319 | Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs)) |
f2b60f7d FG |
320 | } |
321 | ||
322 | pub(crate) fn resolve_prefix_expr( | |
323 | &self, | |
324 | db: &dyn HirDatabase, | |
325 | prefix_expr: &ast::PrefixExpr, | |
326 | ) -> Option<FunctionId> { | |
9ffffee4 FG |
327 | let (lang_item, fn_name) = match prefix_expr.op_kind()? { |
328 | ast::UnaryOp::Deref => (LangItem::Deref, name![deref]), | |
329 | ast::UnaryOp::Not => (LangItem::Not, name![not]), | |
330 | ast::UnaryOp::Neg => (LangItem::Neg, name![neg]), | |
f2b60f7d | 331 | }; |
9c376795 | 332 | let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?; |
f2b60f7d | 333 | |
9ffffee4 | 334 | let (op_trait, op_fn) = self.lang_trait_fn(db, lang_item, &fn_name)?; |
2b03887a FG |
335 | // HACK: subst for all methods coincides with that for their trait because the methods |
336 | // don't have any generic parameters, so we skip building another subst for the methods. | |
337 | let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); | |
f2b60f7d | 338 | |
487cf647 | 339 | Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) |
f2b60f7d FG |
340 | } |
341 | ||
342 | pub(crate) fn resolve_index_expr( | |
343 | &self, | |
344 | db: &dyn HirDatabase, | |
345 | index_expr: &ast::IndexExpr, | |
346 | ) -> Option<FunctionId> { | |
9c376795 FG |
347 | let base_ty = self.ty_of_expr(db, &index_expr.base()?)?; |
348 | let index_ty = self.ty_of_expr(db, &index_expr.index()?)?; | |
f2b60f7d | 349 | |
9ffffee4 | 350 | let (op_trait, op_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?; |
2b03887a FG |
351 | // HACK: subst for all methods coincides with that for their trait because the methods |
352 | // don't have any generic parameters, so we skip building another subst for the methods. | |
353 | let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None) | |
f2b60f7d FG |
354 | .push(base_ty.clone()) |
355 | .push(index_ty.clone()) | |
356 | .build(); | |
487cf647 | 357 | Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) |
f2b60f7d FG |
358 | } |
359 | ||
360 | pub(crate) fn resolve_bin_expr( | |
361 | &self, | |
362 | db: &dyn HirDatabase, | |
363 | binop_expr: &ast::BinExpr, | |
364 | ) -> Option<FunctionId> { | |
365 | let op = binop_expr.op_kind()?; | |
9c376795 FG |
366 | let lhs = self.ty_of_expr(db, &binop_expr.lhs()?)?; |
367 | let rhs = self.ty_of_expr(db, &binop_expr.rhs()?)?; | |
f2b60f7d | 368 | |
9ffffee4 FG |
369 | let (op_trait, op_fn) = lang_items_for_bin_op(op) |
370 | .and_then(|(name, lang_item)| self.lang_trait_fn(db, lang_item, &name))?; | |
2b03887a FG |
371 | // HACK: subst for `index()` coincides with that for `Index` because `index()` itself |
372 | // doesn't have any generic parameters, so we skip building another subst for `index()`. | |
373 | let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None) | |
374 | .push(lhs.clone()) | |
375 | .push(rhs.clone()) | |
376 | .build(); | |
f2b60f7d | 377 | |
487cf647 | 378 | Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) |
f2b60f7d FG |
379 | } |
380 | ||
381 | pub(crate) fn resolve_try_expr( | |
382 | &self, | |
383 | db: &dyn HirDatabase, | |
384 | try_expr: &ast::TryExpr, | |
385 | ) -> Option<FunctionId> { | |
9c376795 | 386 | let ty = self.ty_of_expr(db, &try_expr.expr()?)?; |
f2b60f7d | 387 | |
9ffffee4 | 388 | let op_fn = db.lang_item(self.resolver.krate(), LangItem::TryTraitBranch)?.as_function()?; |
2b03887a FG |
389 | let op_trait = match op_fn.lookup(db.upcast()).container { |
390 | ItemContainerId::TraitId(id) => id, | |
391 | _ => return None, | |
392 | }; | |
393 | // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself | |
394 | // doesn't have any generic parameters, so we skip building another subst for `branch()`. | |
395 | let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); | |
f2b60f7d | 396 | |
487cf647 | 397 | Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) |
064997fb FG |
398 | } |
399 | ||
400 | pub(crate) fn resolve_field( | |
401 | &self, | |
402 | db: &dyn HirDatabase, | |
403 | field: &ast::FieldExpr, | |
404 | ) -> Option<Field> { | |
405 | let expr_id = self.expr_id(db, &field.clone().into())?; | |
406 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) | |
407 | } | |
408 | ||
409 | pub(crate) fn resolve_record_field( | |
410 | &self, | |
411 | db: &dyn HirDatabase, | |
412 | field: &ast::RecordExprField, | |
413 | ) -> Option<(Field, Option<Local>, Type)> { | |
414 | let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; | |
415 | let expr = ast::Expr::from(record_expr); | |
416 | let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?; | |
417 | ||
418 | let local_name = field.field_name()?.as_name(); | |
419 | let local = if field.name_ref().is_some() { | |
420 | None | |
421 | } else { | |
f2b60f7d | 422 | // Shorthand syntax, resolve to the local |
064997fb FG |
423 | let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); |
424 | match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { | |
353b0b11 FG |
425 | Some(ValueNs::LocalBinding(binding_id)) => { |
426 | Some(Local { binding_id, parent: self.resolver.body_owner()? }) | |
064997fb FG |
427 | } |
428 | _ => None, | |
429 | } | |
430 | }; | |
431 | let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?; | |
432 | let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; | |
433 | let variant_data = variant.variant_data(db.upcast()); | |
434 | let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; | |
435 | let field_ty = | |
436 | db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); | |
437 | Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty))) | |
438 | } | |
439 | ||
440 | pub(crate) fn resolve_record_pat_field( | |
441 | &self, | |
442 | db: &dyn HirDatabase, | |
443 | field: &ast::RecordPatField, | |
353b0b11 | 444 | ) -> Option<(Field, Type)> { |
064997fb FG |
445 | let field_name = field.field_name()?.as_name(); |
446 | let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; | |
447 | let pat_id = self.pat_id(&record_pat.into())?; | |
448 | let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?; | |
449 | let variant_data = variant.variant_data(db.upcast()); | |
450 | let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; | |
353b0b11 FG |
451 | let (_, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?; |
452 | let field_ty = | |
453 | db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); | |
454 | Some((field.into(), Type::new_with_resolver(db, &self.resolver, field_ty))) | |
064997fb FG |
455 | } |
456 | ||
457 | pub(crate) fn resolve_macro_call( | |
458 | &self, | |
459 | db: &dyn HirDatabase, | |
460 | macro_call: InFile<&ast::MacroCall>, | |
461 | ) -> Option<Macro> { | |
462 | let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); | |
463 | let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; | |
464 | self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) | |
465 | } | |
466 | ||
467 | pub(crate) fn resolve_bind_pat_to_const( | |
468 | &self, | |
469 | db: &dyn HirDatabase, | |
470 | pat: &ast::IdentPat, | |
471 | ) -> Option<ModuleDef> { | |
472 | let pat_id = self.pat_id(&pat.clone().into())?; | |
473 | let body = self.body()?; | |
474 | let path = match &body[pat_id] { | |
475 | Pat::Path(path) => path, | |
476 | _ => return None, | |
477 | }; | |
478 | let res = resolve_hir_path(db, &self.resolver, path)?; | |
479 | match res { | |
480 | PathResolution::Def(def) => Some(def), | |
481 | _ => None, | |
482 | } | |
483 | } | |
484 | ||
485 | pub(crate) fn resolve_path( | |
486 | &self, | |
487 | db: &dyn HirDatabase, | |
488 | path: &ast::Path, | |
489 | ) -> Option<PathResolution> { | |
490 | let parent = path.syntax().parent(); | |
491 | let parent = || parent.clone(); | |
492 | ||
493 | let mut prefer_value_ns = false; | |
494 | let resolved = (|| { | |
487cf647 | 495 | let infer = self.infer.as_deref()?; |
064997fb FG |
496 | if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) { |
497 | let expr_id = self.expr_id(db, &path_expr.into())?; | |
9c376795 | 498 | if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) { |
064997fb FG |
499 | let assoc = match assoc { |
500 | AssocItemId::FunctionId(f_in_trait) => { | |
501 | match infer.type_of_expr.get(expr_id) { | |
502 | None => assoc, | |
503 | Some(func_ty) => { | |
504 | if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) { | |
487cf647 FG |
505 | self.resolve_impl_method_or_trait_def( |
506 | db, | |
507 | f_in_trait, | |
508 | subs.clone(), | |
509 | ) | |
510 | .into() | |
064997fb FG |
511 | } else { |
512 | assoc | |
513 | } | |
514 | } | |
515 | } | |
516 | } | |
9c376795 FG |
517 | AssocItemId::ConstId(const_id) => { |
518 | self.resolve_impl_const_or_trait_def(db, const_id, subs).into() | |
519 | } | |
9ffffee4 | 520 | assoc => assoc, |
064997fb FG |
521 | }; |
522 | ||
523 | return Some(PathResolution::Def(AssocItem::from(assoc).into())); | |
524 | } | |
525 | if let Some(VariantId::EnumVariantId(variant)) = | |
526 | infer.variant_resolution_for_expr(expr_id) | |
527 | { | |
528 | return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); | |
529 | } | |
530 | prefer_value_ns = true; | |
531 | } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) { | |
532 | let pat_id = self.pat_id(&path_pat.into())?; | |
9ffffee4 FG |
533 | if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) { |
534 | let assoc = match assoc { | |
535 | AssocItemId::ConstId(const_id) => { | |
536 | self.resolve_impl_const_or_trait_def(db, const_id, subs).into() | |
537 | } | |
538 | assoc => assoc, | |
539 | }; | |
064997fb FG |
540 | return Some(PathResolution::Def(AssocItem::from(assoc).into())); |
541 | } | |
542 | if let Some(VariantId::EnumVariantId(variant)) = | |
487cf647 | 543 | infer.variant_resolution_for_pat(pat_id) |
064997fb FG |
544 | { |
545 | return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); | |
546 | } | |
547 | } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) { | |
548 | let expr_id = self.expr_id(db, &rec_lit.into())?; | |
549 | if let Some(VariantId::EnumVariantId(variant)) = | |
487cf647 | 550 | infer.variant_resolution_for_expr(expr_id) |
064997fb FG |
551 | { |
552 | return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); | |
553 | } | |
554 | } else { | |
555 | let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from); | |
556 | let tuple_struct_pat = | |
557 | || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from); | |
558 | if let Some(pat) = record_pat.or_else(tuple_struct_pat) { | |
559 | let pat_id = self.pat_id(&pat)?; | |
487cf647 | 560 | let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id); |
064997fb FG |
561 | if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat { |
562 | return Some(PathResolution::Def(ModuleDef::Variant(variant.into()))); | |
563 | } | |
564 | } | |
565 | } | |
566 | None | |
567 | })(); | |
568 | if let Some(_) = resolved { | |
569 | return resolved; | |
570 | } | |
571 | ||
572 | // This must be a normal source file rather than macro file. | |
573 | let hygiene = Hygiene::new(db.upcast(), self.file_id); | |
574 | let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); | |
575 | let hir_path = Path::from_src(path.clone(), &ctx)?; | |
576 | ||
577 | // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are | |
578 | // trying to resolve foo::bar. | |
579 | if let Some(use_tree) = parent().and_then(ast::UseTree::cast) { | |
580 | if use_tree.coloncolon_token().is_some() { | |
581 | return resolve_hir_path_qualifier(db, &self.resolver, &hir_path); | |
582 | } | |
583 | } | |
584 | ||
585 | let meta_path = path | |
586 | .syntax() | |
587 | .ancestors() | |
588 | .take_while(|it| { | |
589 | let kind = it.kind(); | |
590 | ast::Path::can_cast(kind) || ast::Meta::can_cast(kind) | |
591 | }) | |
592 | .last() | |
593 | .and_then(ast::Meta::cast); | |
594 | ||
595 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are | |
596 | // trying to resolve foo::bar. | |
597 | if path.parent_path().is_some() { | |
598 | return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) { | |
599 | None if meta_path.is_some() => { | |
600 | path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| { | |
601 | ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text()) | |
602 | .map(PathResolution::ToolModule) | |
603 | }) | |
604 | } | |
605 | res => res, | |
606 | }; | |
607 | } else if let Some(meta_path) = meta_path { | |
608 | // Case where we are resolving the final path segment of a path in an attribute | |
609 | // in this case we have to check for inert/builtin attributes and tools and prioritize | |
610 | // resolution of attributes over other namespaces | |
611 | if let Some(name_ref) = path.as_single_name_ref() { | |
612 | let builtin = | |
613 | BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text()); | |
614 | if let Some(_) = builtin { | |
615 | return builtin.map(PathResolution::BuiltinAttr); | |
616 | } | |
617 | ||
618 | if let Some(attr) = meta_path.parent_attr() { | |
619 | let adt = if let Some(field) = | |
620 | attr.syntax().parent().and_then(ast::RecordField::cast) | |
621 | { | |
622 | field.syntax().ancestors().take(4).find_map(ast::Adt::cast) | |
623 | } else if let Some(field) = | |
624 | attr.syntax().parent().and_then(ast::TupleField::cast) | |
625 | { | |
626 | field.syntax().ancestors().take(4).find_map(ast::Adt::cast) | |
627 | } else if let Some(variant) = | |
628 | attr.syntax().parent().and_then(ast::Variant::cast) | |
629 | { | |
630 | variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast) | |
631 | } else { | |
632 | None | |
633 | }; | |
634 | if let Some(adt) = adt { | |
635 | let ast_id = db.ast_id_map(self.file_id).ast_id(&adt); | |
636 | if let Some(helpers) = self | |
637 | .resolver | |
638 | .def_map() | |
639 | .derive_helpers_in_scope(InFile::new(self.file_id, ast_id)) | |
640 | { | |
641 | // FIXME: Multiple derives can have the same helper | |
642 | let name_ref = name_ref.as_name(); | |
643 | for (macro_id, mut helpers) in | |
644 | helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter() | |
645 | { | |
646 | if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref) | |
647 | { | |
648 | return Some(PathResolution::DeriveHelper(DeriveHelper { | |
649 | derive: *macro_id, | |
9ffffee4 | 650 | idx: idx as u32, |
064997fb FG |
651 | })); |
652 | } | |
653 | } | |
654 | } | |
655 | } | |
656 | } | |
657 | } | |
658 | return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) { | |
659 | Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))), | |
660 | // this labels any path that starts with a tool module as the tool itself, this is technically wrong | |
661 | // but there is no benefit in differentiating these two cases for the time being | |
662 | None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| { | |
663 | ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text()) | |
664 | .map(PathResolution::ToolModule) | |
665 | }), | |
666 | }; | |
667 | } | |
668 | if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { | |
669 | resolve_hir_path_qualifier(db, &self.resolver, &hir_path) | |
670 | } else { | |
671 | resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) | |
672 | } | |
673 | } | |
674 | ||
675 | pub(crate) fn record_literal_missing_fields( | |
676 | &self, | |
677 | db: &dyn HirDatabase, | |
678 | literal: &ast::RecordExpr, | |
679 | ) -> Option<Vec<(Field, Type)>> { | |
680 | let body = self.body()?; | |
681 | let infer = self.infer.as_ref()?; | |
682 | ||
683 | let expr_id = self.expr_id(db, &literal.clone().into())?; | |
684 | let substs = infer.type_of_expr[expr_id].as_adt()?.1; | |
685 | ||
686 | let (variant, missing_fields, _exhaustive) = | |
687 | record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; | |
688 | let res = self.missing_fields(db, substs, variant, missing_fields); | |
689 | Some(res) | |
690 | } | |
691 | ||
692 | pub(crate) fn record_pattern_missing_fields( | |
693 | &self, | |
694 | db: &dyn HirDatabase, | |
695 | pattern: &ast::RecordPat, | |
696 | ) -> Option<Vec<(Field, Type)>> { | |
697 | let body = self.body()?; | |
698 | let infer = self.infer.as_ref()?; | |
699 | ||
700 | let pat_id = self.pat_id(&pattern.clone().into())?; | |
701 | let substs = infer.type_of_pat[pat_id].as_adt()?.1; | |
702 | ||
703 | let (variant, missing_fields, _exhaustive) = | |
704 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; | |
705 | let res = self.missing_fields(db, substs, variant, missing_fields); | |
706 | Some(res) | |
707 | } | |
708 | ||
709 | fn missing_fields( | |
710 | &self, | |
711 | db: &dyn HirDatabase, | |
712 | substs: &Substitution, | |
713 | variant: VariantId, | |
714 | missing_fields: Vec<LocalFieldId>, | |
715 | ) -> Vec<(Field, Type)> { | |
716 | let field_types = db.field_types(variant); | |
717 | ||
718 | missing_fields | |
719 | .into_iter() | |
720 | .map(|local_id| { | |
721 | let field = FieldId { parent: variant, local_id }; | |
722 | let ty = field_types[local_id].clone().substitute(Interner, substs); | |
723 | (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty)) | |
724 | }) | |
725 | .collect() | |
726 | } | |
727 | ||
728 | pub(crate) fn expand( | |
729 | &self, | |
730 | db: &dyn HirDatabase, | |
731 | macro_call: InFile<&ast::MacroCall>, | |
732 | ) -> Option<HirFileId> { | |
733 | let krate = self.resolver.krate(); | |
734 | let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { | |
735 | self.resolver | |
736 | .resolve_path_as_macro(db.upcast(), &path) | |
737 | .map(|it| macro_id_to_def_id(db.upcast(), it)) | |
738 | })?; | |
739 | Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64) | |
740 | } | |
741 | ||
742 | pub(crate) fn resolve_variant( | |
743 | &self, | |
744 | db: &dyn HirDatabase, | |
745 | record_lit: ast::RecordExpr, | |
746 | ) -> Option<VariantId> { | |
747 | let infer = self.infer.as_ref()?; | |
748 | let expr_id = self.expr_id(db, &record_lit.into())?; | |
749 | infer.variant_resolution_for_expr(expr_id) | |
750 | } | |
751 | ||
752 | pub(crate) fn is_unsafe_macro_call( | |
753 | &self, | |
754 | db: &dyn HirDatabase, | |
755 | macro_call: InFile<&ast::MacroCall>, | |
756 | ) -> bool { | |
757 | // check for asm/global_asm | |
758 | if let Some(mac) = self.resolve_macro_call(db, macro_call) { | |
759 | let ex = match mac.id { | |
760 | hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander, | |
761 | hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander, | |
762 | _ => hir_def::MacroExpander::Declarative, | |
763 | }; | |
764 | match ex { | |
765 | hir_def::MacroExpander::BuiltIn(e) | |
766 | if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm => | |
767 | { | |
768 | return true | |
769 | } | |
770 | _ => (), | |
771 | } | |
772 | } | |
773 | let macro_expr = match macro_call | |
774 | .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast)) | |
775 | .transpose() | |
776 | { | |
777 | Some(it) => it, | |
778 | None => return false, | |
779 | }; | |
780 | ||
781 | if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) { | |
782 | if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) { | |
783 | let mut is_unsafe = false; | |
784 | unsafe_expressions( | |
785 | db, | |
786 | infer, | |
787 | *def, | |
788 | body, | |
789 | expanded_expr, | |
790 | &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block, | |
791 | ); | |
792 | return is_unsafe; | |
793 | } | |
794 | } | |
795 | false | |
796 | } | |
797 | ||
487cf647 | 798 | fn resolve_impl_method_or_trait_def( |
064997fb FG |
799 | &self, |
800 | db: &dyn HirDatabase, | |
801 | func: FunctionId, | |
487cf647 FG |
802 | substs: Substitution, |
803 | ) -> FunctionId { | |
064997fb | 804 | let krate = self.resolver.krate(); |
487cf647 FG |
805 | let owner = match self.resolver.body_owner() { |
806 | Some(it) => it, | |
807 | None => return func, | |
808 | }; | |
809 | let env = owner.as_generic_def_id().map_or_else( | |
064997fb FG |
810 | || Arc::new(hir_ty::TraitEnvironment::empty(krate)), |
811 | |d| db.trait_environment(d), | |
812 | ); | |
353b0b11 | 813 | method_resolution::lookup_impl_method(db, env, func, substs).0 |
f2b60f7d FG |
814 | } |
815 | ||
9c376795 FG |
816 | fn resolve_impl_const_or_trait_def( |
817 | &self, | |
818 | db: &dyn HirDatabase, | |
819 | const_id: ConstId, | |
820 | subs: Substitution, | |
821 | ) -> ConstId { | |
822 | let krate = self.resolver.krate(); | |
823 | let owner = match self.resolver.body_owner() { | |
824 | Some(it) => it, | |
825 | None => return const_id, | |
826 | }; | |
827 | let env = owner.as_generic_def_id().map_or_else( | |
828 | || Arc::new(hir_ty::TraitEnvironment::empty(krate)), | |
829 | |d| db.trait_environment(d), | |
830 | ); | |
353b0b11 | 831 | method_resolution::lookup_impl_const(db, env, const_id, subs).0 |
9c376795 FG |
832 | } |
833 | ||
f2b60f7d FG |
834 | fn lang_trait_fn( |
835 | &self, | |
836 | db: &dyn HirDatabase, | |
9ffffee4 | 837 | lang_trait: LangItem, |
f2b60f7d | 838 | method_name: &Name, |
2b03887a | 839 | ) -> Option<(TraitId, FunctionId)> { |
9ffffee4 | 840 | let trait_id = db.lang_item(self.resolver.krate(), lang_trait)?.as_trait()?; |
2b03887a FG |
841 | let fn_id = db.trait_data(trait_id).method_by_name(method_name)?; |
842 | Some((trait_id, fn_id)) | |
f2b60f7d FG |
843 | } |
844 | ||
845 | fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { | |
9c376795 | 846 | self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?) |
f2b60f7d | 847 | } |
064997fb FG |
848 | } |
849 | ||
850 | fn scope_for( | |
851 | scopes: &ExprScopes, | |
852 | source_map: &BodySourceMap, | |
853 | node: InFile<&SyntaxNode>, | |
854 | ) -> Option<ScopeId> { | |
855 | node.value | |
856 | .ancestors() | |
857 | .filter_map(ast::Expr::cast) | |
858 | .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it))) | |
859 | .find_map(|it| scopes.scope_for(it)) | |
860 | } | |
861 | ||
862 | fn scope_for_offset( | |
863 | db: &dyn HirDatabase, | |
864 | scopes: &ExprScopes, | |
865 | source_map: &BodySourceMap, | |
866 | from_file: HirFileId, | |
867 | offset: TextSize, | |
868 | ) -> Option<ScopeId> { | |
869 | scopes | |
870 | .scope_by_expr() | |
871 | .iter() | |
872 | .filter_map(|(id, scope)| { | |
873 | let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?; | |
874 | if from_file == file_id { | |
875 | return Some((value.text_range(), scope)); | |
876 | } | |
877 | ||
878 | // FIXME handle attribute expansion | |
879 | let source = iter::successors(file_id.call_node(db.upcast()), |it| { | |
880 | it.file_id.call_node(db.upcast()) | |
881 | }) | |
882 | .find(|it| it.file_id == from_file) | |
883 | .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?; | |
884 | Some((source.value.text_range(), scope)) | |
885 | }) | |
886 | .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end()) | |
887 | // find containing scope | |
888 | .min_by_key(|(expr_range, _scope)| expr_range.len()) | |
889 | .map(|(expr_range, scope)| { | |
890 | adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope) | |
891 | }) | |
892 | } | |
893 | ||
894 | // XXX: during completion, cursor might be outside of any particular | |
895 | // expression. Try to figure out the correct scope... | |
896 | fn adjust( | |
897 | db: &dyn HirDatabase, | |
898 | scopes: &ExprScopes, | |
899 | source_map: &BodySourceMap, | |
900 | expr_range: TextRange, | |
901 | from_file: HirFileId, | |
902 | offset: TextSize, | |
903 | ) -> Option<ScopeId> { | |
904 | let child_scopes = scopes | |
905 | .scope_by_expr() | |
906 | .iter() | |
907 | .filter_map(|(id, scope)| { | |
908 | let source = source_map.expr_syntax(*id).ok()?; | |
909 | // FIXME: correctly handle macro expansion | |
910 | if source.file_id != from_file { | |
911 | return None; | |
912 | } | |
913 | let root = source.file_syntax(db.upcast()); | |
914 | let node = source.value.to_node(&root); | |
915 | Some((node.syntax().text_range(), scope)) | |
916 | }) | |
917 | .filter(|&(range, _)| { | |
918 | range.start() <= offset && expr_range.contains_range(range) && range != expr_range | |
919 | }); | |
920 | ||
921 | child_scopes | |
922 | .max_by(|&(r1, _), &(r2, _)| { | |
923 | if r1.contains_range(r2) { | |
924 | std::cmp::Ordering::Greater | |
925 | } else if r2.contains_range(r1) { | |
926 | std::cmp::Ordering::Less | |
927 | } else { | |
928 | r1.start().cmp(&r2.start()) | |
929 | } | |
930 | }) | |
931 | .map(|(_ptr, scope)| *scope) | |
932 | } | |
933 | ||
934 | #[inline] | |
935 | pub(crate) fn resolve_hir_path( | |
936 | db: &dyn HirDatabase, | |
937 | resolver: &Resolver, | |
938 | path: &Path, | |
939 | ) -> Option<PathResolution> { | |
940 | resolve_hir_path_(db, resolver, path, false) | |
941 | } | |
942 | ||
943 | #[inline] | |
944 | pub(crate) fn resolve_hir_path_as_macro( | |
945 | db: &dyn HirDatabase, | |
946 | resolver: &Resolver, | |
947 | path: &Path, | |
948 | ) -> Option<Macro> { | |
949 | resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into) | |
950 | } | |
951 | ||
952 | fn resolve_hir_path_( | |
953 | db: &dyn HirDatabase, | |
954 | resolver: &Resolver, | |
955 | path: &Path, | |
956 | prefer_value_ns: bool, | |
957 | ) -> Option<PathResolution> { | |
958 | let types = || { | |
959 | let (ty, unresolved) = match path.type_anchor() { | |
960 | Some(type_ref) => { | |
961 | let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref); | |
962 | res.map(|ty_ns| (ty_ns, path.segments().first())) | |
963 | } | |
964 | None => { | |
353b0b11 | 965 | let (ty, remaining_idx) = |
064997fb | 966 | resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?; |
353b0b11 FG |
967 | match remaining_idx { |
968 | Some(remaining_idx) => { | |
969 | if remaining_idx + 1 == path.segments().len() { | |
064997fb FG |
970 | Some((ty, path.segments().last())) |
971 | } else { | |
972 | None | |
973 | } | |
974 | } | |
353b0b11 | 975 | None => Some((ty, None)), |
064997fb FG |
976 | } |
977 | } | |
978 | }?; | |
979 | ||
980 | // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type | |
981 | // within the trait's associated types. | |
982 | if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) { | |
983 | if let Some(type_alias_id) = | |
984 | db.trait_data(trait_id).associated_type_by_name(unresolved.name) | |
985 | { | |
986 | return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); | |
987 | } | |
988 | } | |
989 | ||
990 | let res = match ty { | |
991 | TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), | |
992 | TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()), | |
993 | TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { | |
994 | PathResolution::Def(Adt::from(it).into()) | |
995 | } | |
996 | TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | |
997 | TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), | |
998 | TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), | |
999 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), | |
353b0b11 | 1000 | TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), |
064997fb FG |
1001 | }; |
1002 | match unresolved { | |
1003 | Some(unresolved) => resolver | |
1004 | .generic_def() | |
1005 | .and_then(|def| { | |
1006 | hir_ty::associated_type_shorthand_candidates( | |
1007 | db, | |
1008 | def, | |
1009 | res.in_type_ns()?, | |
9c376795 | 1010 | |name, id| (name == unresolved.name).then_some(id), |
064997fb FG |
1011 | ) |
1012 | }) | |
1013 | .map(TypeAlias::from) | |
1014 | .map(Into::into) | |
1015 | .map(PathResolution::Def), | |
1016 | None => Some(res), | |
1017 | } | |
1018 | }; | |
1019 | ||
1020 | let body_owner = resolver.body_owner(); | |
1021 | let values = || { | |
1022 | resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { | |
1023 | let res = match val { | |
353b0b11 FG |
1024 | ValueNs::LocalBinding(binding_id) => { |
1025 | let var = Local { parent: body_owner?, binding_id }; | |
064997fb FG |
1026 | PathResolution::Local(var) |
1027 | } | |
1028 | ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), | |
1029 | ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), | |
1030 | ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), | |
1031 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | |
1032 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | |
1033 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), | |
1034 | ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()), | |
1035 | }; | |
1036 | Some(res) | |
1037 | }) | |
1038 | }; | |
1039 | ||
1040 | let items = || { | |
1041 | resolver | |
1042 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) | |
1043 | .take_types() | |
1044 | .map(|it| PathResolution::Def(it.into())) | |
1045 | }; | |
1046 | ||
1047 | let macros = || { | |
1048 | resolver | |
1049 | .resolve_path_as_macro(db.upcast(), path.mod_path()) | |
1050 | .map(|def| PathResolution::Def(ModuleDef::Macro(def.into()))) | |
1051 | }; | |
1052 | ||
1053 | if prefer_value_ns { values().or_else(types) } else { types().or_else(values) } | |
1054 | .or_else(items) | |
1055 | .or_else(macros) | |
1056 | } | |
1057 | ||
1058 | /// Resolves a path where we know it is a qualifier of another path. | |
1059 | /// | |
1060 | /// For example, if we have: | |
1061 | /// ``` | |
1062 | /// mod my { | |
1063 | /// pub mod foo { | |
1064 | /// struct Bar; | |
1065 | /// } | |
1066 | /// | |
1067 | /// pub fn foo() {} | |
1068 | /// } | |
1069 | /// ``` | |
1070 | /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function. | |
1071 | fn resolve_hir_path_qualifier( | |
1072 | db: &dyn HirDatabase, | |
1073 | resolver: &Resolver, | |
1074 | path: &Path, | |
1075 | ) -> Option<PathResolution> { | |
1076 | resolver | |
1077 | .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) | |
1078 | .map(|ty| match ty { | |
1079 | TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), | |
1080 | TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()), | |
1081 | TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { | |
1082 | PathResolution::Def(Adt::from(it).into()) | |
1083 | } | |
1084 | TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | |
1085 | TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), | |
1086 | TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), | |
1087 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), | |
353b0b11 | 1088 | TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), |
064997fb FG |
1089 | }) |
1090 | .or_else(|| { | |
1091 | resolver | |
1092 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) | |
1093 | .take_types() | |
1094 | .map(|it| PathResolution::Def(it.into())) | |
1095 | }) | |
1096 | } |