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