1use std::{
9 cell::OnceCell,
10 iter::{self, once},
11};
12
13use either::Either;
14use hir_def::{
15 AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId,
16 FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, VariantId,
17 expr_store::{
18 Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId,
19 lower::ExprCollector,
20 path::Path,
21 scope::{ExprScopes, ScopeId},
22 },
23 hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId, generics::GenericParams},
24 lang_item::LangItems,
25 nameres::MacroSubNs,
26 resolver::{Resolver, TypeNs, ValueNs, resolver_for_scope},
27 type_ref::{Mutability, TypeRef, TypeRefId},
28};
29use hir_expand::{
30 HirFileId, InFile,
31 mod_path::{ModPath, PathKind, path},
32 name::{AsName, Name},
33};
34use hir_ty::{
35 Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate,
36 TyLoweringContext,
37 diagnostics::{
38 InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
39 unsafe_operations,
40 },
41 lang_items::lang_items_for_bin_op,
42 method_resolution::{self, CandidateId},
43 next_solver::{
44 AliasTy, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
45 infer::DbInternerInferExt,
46 },
47 traits::structurally_normalize_ty,
48};
49use intern::sym;
50use itertools::Itertools;
51use rustc_hash::FxHashSet;
52use rustc_type_ir::{
53 AliasTyKind,
54 inherent::{IntoKind, Ty as _},
55};
56use smallvec::SmallVec;
57use stdx::never;
58use syntax::{
59 SyntaxKind, SyntaxNode, TextRange, TextSize,
60 ast::{self, AstNode, RangeItem, RangeOp},
61};
62
63use crate::{
64 Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const,
65 DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef,
66 SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias,
67 db::HirDatabase,
68 semantics::{PathResolution, PathResolutionPerNs},
69};
70
71#[derive(Debug)]
74pub(crate) struct SourceAnalyzer<'db> {
75 pub(crate) file_id: HirFileId,
76 pub(crate) resolver: Resolver<'db>,
77 pub(crate) body_or_sig: Option<BodyOrSig<'db>>,
78 pub(crate) infer_body: Option<InferBodyId>,
79}
80
81#[derive(Debug)]
82pub(crate) enum BodyOrSig<'db> {
83 Body {
84 def: DefWithBodyId,
85 body: &'db Body,
86 source_map: &'db BodySourceMap,
87 infer: Option<&'db InferenceResult>,
88 },
89 VariantFields {
90 def: VariantId,
91 store: &'db ExpressionStore,
92 source_map: &'db ExpressionStoreSourceMap,
93 infer: Option<&'db InferenceResult>,
94 },
95 Sig {
96 def: GenericDefId,
97 store: &'db ExpressionStore,
98 source_map: &'db ExpressionStoreSourceMap,
99 infer: Option<&'db InferenceResult>,
100 #[expect(dead_code)]
101 generics: &'db GenericParams,
102 },
103}
104
105impl<'db> SourceAnalyzer<'db> {
106 pub(crate) fn new_for_body(
107 db: &'db dyn HirDatabase,
108 def: DefWithBodyId,
109 node: InFile<&SyntaxNode>,
110 offset: Option<TextSize>,
111 ) -> SourceAnalyzer<'db> {
112 Self::new_for_body_(db, def, node, offset, Some(InferenceResult::of(db, def)))
113 }
114
115 pub(crate) fn new_for_body_no_infer(
116 db: &'db dyn HirDatabase,
117 def: DefWithBodyId,
118 node: InFile<&SyntaxNode>,
119 offset: Option<TextSize>,
120 ) -> SourceAnalyzer<'db> {
121 Self::new_for_body_(db, def, node, offset, None)
122 }
123
124 pub(crate) fn new_for_body_(
125 db: &'db dyn HirDatabase,
126 def: DefWithBodyId,
127 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
128 offset: Option<TextSize>,
129 infer: Option<&'db InferenceResult>,
130 ) -> SourceAnalyzer<'db> {
131 let (body, source_map) = Body::with_source_map(db, def);
132 let scopes = ExprScopes::of(db, def);
133 let scope = match offset {
134 None => scope_for(db, scopes, source_map, node),
135 Some(offset) => {
136 debug_assert!(
137 node.text_range().contains_inclusive(offset),
138 "{:?} not in {:?}",
139 offset,
140 node.text_range()
141 );
142 scope_for_offset(db, scopes, source_map, node.file_id, offset)
143 }
144 };
145 let (scope, _expr) = scope.unzip();
146 let resolver = resolver_for_scope(db, def, scope);
147 SourceAnalyzer {
148 resolver,
149 body_or_sig: Some(BodyOrSig::Body { def, body, source_map, infer }),
150 file_id,
151 infer_body: Some(def.into()),
152 }
153 }
154
155 pub(crate) fn new_generic_def(
156 db: &'db dyn HirDatabase,
157 sema: &SemanticsImpl<'db>,
158 def: GenericDefId,
159 node: InFile<&SyntaxNode>,
160 offset: Option<TextSize>,
161 ) -> SourceAnalyzer<'db> {
162 Self::new_generic_def_(db, sema, def, node, offset, true)
163 }
164
165 pub(crate) fn new_generic_def_no_infer(
166 db: &'db dyn HirDatabase,
167 sema: &SemanticsImpl<'db>,
168 def: GenericDefId,
169 node: InFile<&SyntaxNode>,
170 offset: Option<TextSize>,
171 ) -> SourceAnalyzer<'db> {
172 Self::new_generic_def_(db, sema, def, node, offset, false)
173 }
174
175 pub(crate) fn new_generic_def_(
176 db: &'db dyn HirDatabase,
177 sema: &SemanticsImpl<'db>,
178 def: GenericDefId,
179 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
180 offset: Option<TextSize>,
181 infer: bool,
182 ) -> SourceAnalyzer<'db> {
183 let (generics, store, source_map) = GenericParams::with_source_map(db, def);
184 let scopes = ExprScopes::of(db, def);
185 let scope = match offset {
186 None => scope_for(db, scopes, source_map, node),
187 Some(offset) => {
188 debug_assert!(
189 node.text_range().contains_inclusive(offset),
190 "{:?} not in {:?}",
191 offset,
192 node.text_range()
193 );
194 scope_for_offset(db, scopes, source_map, node.file_id, offset)
195 }
196 };
197 let (scope, expr) = scope.unzip();
198 let resolver = resolver_for_scope(db, def, scope);
199 let infer_body = expr.and_then(|expr| {
200 sema.infer_body_for_expr_or_pat(
201 ExpressionStoreOwnerId::Signature(def),
202 store,
203 expr.into(),
204 )
205 });
206 let infer = if infer && let Some(infer_body) = infer_body {
207 Some(InferenceResult::of(db, infer_body))
208 } else {
209 None
210 };
211 SourceAnalyzer {
212 resolver,
213 body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }),
214 file_id,
215 infer_body,
216 }
217 }
218
219 pub(crate) fn new_variant_body(
220 db: &'db dyn HirDatabase,
221 sema: &SemanticsImpl<'db>,
222 def: VariantId,
223 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
224 offset: Option<TextSize>,
225 infer: bool,
226 ) -> SourceAnalyzer<'db> {
227 let (fields, source_map) = def.fields_with_source_map(db);
228 let scopes = ExprScopes::of(db, def);
229 let scope = match offset {
230 None => scope_for(db, scopes, source_map, node),
231 Some(offset) => {
232 debug_assert!(
233 node.text_range().contains_inclusive(offset),
234 "{:?} not in {:?}",
235 offset,
236 node.text_range()
237 );
238 scope_for_offset(db, scopes, source_map, node.file_id, offset)
239 }
240 };
241 let (scope, expr) = scope.unzip();
242 let resolver = resolver_for_scope(db, def, scope);
243 let infer_body = expr.and_then(|expr| {
244 sema.infer_body_for_expr_or_pat(
245 ExpressionStoreOwnerId::VariantFields(def),
246 &fields.store,
247 expr.into(),
248 )
249 });
250 let infer = if infer && let Some(infer_body) = infer_body {
251 Some(InferenceResult::of(db, infer_body))
252 } else {
253 None
254 };
255 SourceAnalyzer {
256 resolver,
257 body_or_sig: Some(BodyOrSig::VariantFields {
258 def,
259 store: &fields.store,
260 source_map,
261 infer,
262 }),
263 file_id,
264 infer_body,
265 }
266 }
267
268 pub(crate) fn new_for_resolver(
269 resolver: Resolver<'db>,
270 node: InFile<&SyntaxNode>,
271 ) -> SourceAnalyzer<'db> {
272 SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id, infer_body: None }
273 }
274
275 fn owner(&self) -> Option<ExpressionStoreOwnerId> {
276 self.body_or_sig.as_ref().map(|it| match *it {
277 BodyOrSig::VariantFields { def, .. } => def.into(),
278 BodyOrSig::Sig { def, .. } => def.into(),
279 BodyOrSig::Body { def, .. } => def.into(),
280 })
281 }
282
283 fn infer(&self) -> Option<&InferenceResult> {
284 self.body_or_sig.as_ref().and_then(|it| match it {
285 BodyOrSig::VariantFields { infer, .. }
286 | BodyOrSig::Sig { infer, .. }
287 | BodyOrSig::Body { infer, .. } => infer.as_deref(),
288 })
289 }
290
291 pub(crate) fn def(
292 &self,
293 ) -> Option<(
294 ExpressionStoreOwnerId,
295 &ExpressionStore,
296 &ExpressionStoreSourceMap,
297 Option<&InferenceResult>,
298 )> {
299 self.body_or_sig.as_ref().map(|it| match *it {
300 BodyOrSig::VariantFields { def, store, source_map, infer, .. } => {
301 (def.into(), store, source_map, infer)
302 }
303 BodyOrSig::Sig { def, store, source_map, infer, .. } => {
304 (def.into(), store, source_map, infer)
305 }
306 BodyOrSig::Body { def, body, source_map, infer, .. } => {
307 (def.into(), &body.store, &source_map.store, infer)
308 }
309 })
310 }
311
312 pub(crate) fn store(&self) -> Option<&ExpressionStore> {
313 self.body_or_sig.as_ref().map(|it| match it {
314 BodyOrSig::Sig { store, .. } => &**store,
315 BodyOrSig::VariantFields { store, .. } => &**store,
316 BodyOrSig::Body { body, .. } => &body.store,
317 })
318 }
319
320 pub(crate) fn store_sm(&self) -> Option<&ExpressionStoreSourceMap> {
321 self.body_or_sig.as_ref().map(|it| match it {
322 BodyOrSig::Sig { source_map, .. } => &**source_map,
323 BodyOrSig::VariantFields { source_map, .. } => &**source_map,
324 BodyOrSig::Body { source_map, .. } => &source_map.store,
325 })
326 }
327
328 fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> {
329 ParamEnvAndCrate { param_env, krate: self.resolver.krate() }
330 }
331
332 fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> {
333 self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| {
334 match *body_or_sig {
335 BodyOrSig::Body { def, .. } => db.trait_environment(def.into()),
336 BodyOrSig::VariantFields { def, .. } => db.trait_environment(def.into()),
337 BodyOrSig::Sig { def, .. } => db.trait_environment(def.into()),
338 }
339 }))
340 }
341
342 pub(crate) fn expr_id(&self, expr: ast::Expr) -> Option<ExprOrPatId> {
343 let src = InFile { file_id: self.file_id, value: expr };
344 self.store_sm()?.node_expr(src.as_ref())
345 }
346
347 fn pat_id(&self, pat: &ast::Pat) -> Option<ExprOrPatId> {
348 let src = InFile { file_id: self.file_id, value: pat };
349 self.store_sm()?.node_pat(src)
350 }
351
352 fn type_id(&self, pat: &ast::Type) -> Option<TypeRefId> {
353 let src = InFile { file_id: self.file_id, value: pat };
354 self.store_sm()?.node_type(src)
355 }
356
357 fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {
358 let pat_id = self.pat_id(&pat.clone().into())?;
359 if let Pat::Bind { id, .. } = self.store()?[pat_id.as_pat()?] { Some(id) } else { None }
360 }
361
362 pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]> {
363 let expr_id = self.expr_id(expr.clone())?.as_expr()?;
366 let infer = self.infer()?;
367 infer.expr_adjustment(expr_id)
368 }
369
370 pub(crate) fn type_of_type(
371 &self,
372 db: &'db dyn HirDatabase,
373 ty: &ast::Type,
374 ) -> Option<Type<'db>> {
375 let interner = DbInterner::new_no_crate(db);
376
377 let type_ref = self.type_id(ty)?;
378
379 let generic_def = self.resolver.generic_def()?;
380 let generics = OnceCell::new();
381 let mut ty = TyLoweringContext::new(
382 db,
383 &self.resolver,
384 self.store()?,
385 generic_def.into(),
386 generic_def,
387 &generics,
388 LifetimeElisionKind::Infer,
392 )
393 .lower_ty(type_ref);
394
395 if let Some(infer) = self.infer()
397 && let Some(store) = self.store()
398 {
399 let mut inferred_types = vec![];
400 TypeRef::walk(type_ref, store, &mut |type_ref_id, type_ref| {
401 if matches!(type_ref, TypeRef::Placeholder) {
402 inferred_types.push(infer.type_of_type_placeholder(type_ref_id));
403 }
404 });
405 let mut inferred_types = inferred_types.into_iter();
406
407 let substituted_ty = hir_ty::next_solver::fold::fold_tys(interner, ty, |ty| {
408 if ty.is_ty_error() { inferred_types.next().flatten().unwrap_or(ty) } else { ty }
409 });
410
411 let success =
413 inferred_types.next().is_none() && !substituted_ty.references_non_lt_error();
414 if success {
415 ty = substituted_ty;
416 }
417 }
418
419 Some(Type::new_with_resolver(db, &self.resolver, ty))
420 }
421
422 pub(crate) fn type_of_expr(
423 &self,
424 db: &'db dyn HirDatabase,
425 expr: &ast::Expr,
426 ) -> Option<(Type<'db>, Option<Type<'db>>)> {
427 let expr_id = self.expr_id(expr.clone())?;
428 let infer = self.infer()?;
429 let coerced = expr_id
430 .as_expr()
431 .and_then(|expr_id| infer.expr_adjustment(expr_id))
432 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.as_ref()));
433 let ty = infer.expr_or_pat_ty(expr_id);
434 let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty);
435 Some((mk_ty(ty), coerced.map(mk_ty)))
436 }
437
438 pub(crate) fn type_of_pat(
439 &self,
440 db: &'db dyn HirDatabase,
441 pat: &ast::Pat,
442 ) -> Option<(Type<'db>, Option<Type<'db>>)> {
443 let expr_or_pat_id = self.pat_id(pat)?;
444 let infer = self.infer()?;
445 let coerced = match expr_or_pat_id {
446 ExprOrPatId::ExprId(idx) => infer
447 .expr_adjustment(idx)
448 .and_then(|adjusts| adjusts.last())
449 .map(|adjust| adjust.target.as_ref()),
450 ExprOrPatId::PatId(idx) => infer
451 .pat_adjustment(idx)
452 .and_then(|adjusts| adjusts.last())
453 .map(|adjust| adjust.source.as_ref()),
454 };
455
456 let ty = infer.expr_or_pat_ty(expr_or_pat_id);
457 let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty);
458 Some((mk_ty(ty), coerced.map(mk_ty)))
459 }
460
461 pub(crate) fn type_of_binding_in_pat(
462 &self,
463 db: &'db dyn HirDatabase,
464 pat: &ast::IdentPat,
465 ) -> Option<Type<'db>> {
466 let binding_id = self.binding_id_of_pat(pat)?;
467 let infer = self.infer()?;
468 let ty = infer.binding_ty(binding_id);
469 let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty);
470 Some(mk_ty(ty))
471 }
472
473 pub(crate) fn type_of_self(
474 &self,
475 db: &'db dyn HirDatabase,
476 _param: &ast::SelfParam,
477 ) -> Option<Type<'db>> {
478 let binding = match self.body_or_sig.as_ref()? {
479 BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None,
480 BodyOrSig::Body { body, .. } => body.self_param()?,
481 };
482 let ty = self.infer()?.binding_ty(binding);
483 Some(Type::new_with_resolver(db, &self.resolver, ty))
484 }
485
486 pub(crate) fn binding_mode_of_pat(
487 &self,
488 _db: &'db dyn HirDatabase,
489 pat: &ast::IdentPat,
490 ) -> Option<BindingMode> {
491 let id = self.pat_id(&pat.clone().into())?;
492 let infer = self.infer()?;
493 Some(match infer.binding_mode(id.as_pat()?)? {
494 hir_ty::BindingMode(hir_ty::ByRef::No, _) => BindingMode::Move,
495 hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Mut), _) => {
496 BindingMode::Ref(Mutability::Mut)
497 }
498 hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Not), _) => {
499 BindingMode::Ref(Mutability::Shared)
500 }
501 })
502 }
503 pub(crate) fn pattern_adjustments(
504 &self,
505 db: &'db dyn HirDatabase,
506 pat: &ast::Pat,
507 ) -> Option<SmallVec<[Type<'db>; 1]>> {
508 let pat_id = self.pat_id(pat)?;
509 let infer = self.infer()?;
510 Some(
511 infer
512 .pat_adjustment(pat_id.as_pat()?)?
513 .iter()
514 .map(|adjust| Type::new_with_resolver(db, &self.resolver, adjust.source.as_ref()))
515 .collect(),
516 )
517 }
518
519 pub(crate) fn resolve_method_call_as_callable(
520 &self,
521 db: &'db dyn HirDatabase,
522 call: &ast::MethodCallExpr,
523 ) -> Option<Callable<'db>> {
524 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
525 let (func, args) = self.infer()?.method_resolution(expr_id)?;
526 let interner = DbInterner::new_no_crate(db);
527 let ty = db.value_ty(func.into())?.instantiate(interner, args).skip_norm_wip();
528 let ty = Type::new_with_resolver(db, &self.resolver, ty);
529 let mut res = ty.as_callable(db)?;
530 res.is_bound_method = true;
531 Some(res)
532 }
533
534 pub(crate) fn resolve_method_call(
535 &self,
536 db: &'db dyn HirDatabase,
537 call: &ast::MethodCallExpr,
538 ) -> Option<Function> {
539 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
540 let (f_in_trait, substs) = self.infer()?.method_resolution(expr_id)?;
541
542 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
543 }
544
545 pub(crate) fn resolve_method_call_fallback(
546 &self,
547 db: &'db dyn HirDatabase,
548 call: &ast::MethodCallExpr,
549 ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
550 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
551 let inference_result = self.infer()?;
552 match inference_result.method_resolution(expr_id) {
553 Some((f_in_trait, substs)) => {
554 let (fn_, subst) =
555 self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs);
556 Some((
557 Either::Left(fn_),
558 GenericSubstitution::new_from_fn(fn_, subst, self.trait_environment(db)),
559 ))
560 }
561 None => {
562 inference_result.field_resolution(expr_id).and_then(Either::left).map(|field| {
563 (Either::Right(field.into()), self.field_subst(expr_id, inference_result, db))
564 })
565 }
566 }
567 }
568
569 pub(crate) fn resolve_expr_as_callable(
570 &self,
571 db: &'db dyn HirDatabase,
572 call: &ast::Expr,
573 ) -> Option<Callable<'db>> {
574 let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
575 adjusted.unwrap_or(orig).as_callable(db)
576 }
577
578 pub(crate) fn resolve_field(
579 &self,
580 field: &ast::FieldExpr,
581 ) -> Option<Either<Field, TupleField>> {
582 let def = self.infer_body?;
583 let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
584 self.infer()?.field_resolution(expr_id).map(|it| {
585 it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
586 })
587 }
588
589 fn field_subst(
590 &self,
591 field_expr: ExprId,
592 infer: &InferenceResult,
593 db: &'db dyn HirDatabase,
594 ) -> Option<GenericSubstitution<'db>> {
595 let body = self.store()?;
596 if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
597 let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?;
598 return Some(GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)));
599 }
600 None
601 }
602
603 pub(crate) fn resolve_field_fallback(
604 &self,
605 db: &'db dyn HirDatabase,
606 field: &ast::FieldExpr,
607 ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
608 {
609 let def = self.infer_body?;
610 let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
611 let inference_result = self.infer()?;
612 match inference_result.field_resolution(expr_id) {
613 Some(field) => match field {
614 Either::Left(field) => Some((
615 Either::Left(Either::Left(field.into())),
616 self.field_subst(expr_id, inference_result, db),
617 )),
618 Either::Right(field) => Some((
619 Either::Left(Either::Right(TupleField {
620 owner: def,
621 tuple: field.tuple,
622 index: field.index,
623 })),
624 None,
625 )),
626 },
627 None => inference_result.method_resolution(expr_id).map(|(f, substs)| {
628 let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs);
629 (
630 Either::Right(f),
631 GenericSubstitution::new_from_fn(f, subst, self.trait_environment(db)),
632 )
633 }),
634 }
635 }
636
637 pub(crate) fn resolve_range_pat(
638 &self,
639 db: &'db dyn HirDatabase,
640 range_pat: &ast::RangePat,
641 ) -> Option<StructId> {
642 self.resolve_range_struct(
643 db,
644 range_pat.op_kind()?,
645 range_pat.start().is_some(),
646 range_pat.end().is_some(),
647 )
648 }
649
650 pub(crate) fn resolve_range_expr(
651 &self,
652 db: &'db dyn HirDatabase,
653 range_expr: &ast::RangeExpr,
654 ) -> Option<StructId> {
655 self.resolve_range_struct(
656 db,
657 range_expr.op_kind()?,
658 range_expr.start().is_some(),
659 range_expr.end().is_some(),
660 )
661 }
662
663 fn resolve_range_struct(
664 &self,
665 db: &'db dyn HirDatabase,
666 op_kind: RangeOp,
667 has_start: bool,
668 has_end: bool,
669 ) -> Option<StructId> {
670 let has_new_range = self.resolver.top_level_def_map().features().new_range;
671 let lang_items = self.lang_items(db);
672 match (op_kind, has_start, has_end) {
673 (RangeOp::Exclusive, false, false) => lang_items.RangeFull,
674 (RangeOp::Exclusive, false, true) => lang_items.RangeTo,
675 (RangeOp::Exclusive, true, false) => {
676 if has_new_range {
677 lang_items.RangeFromCopy
678 } else {
679 lang_items.RangeFrom
680 }
681 }
682 (RangeOp::Exclusive, true, true) => {
683 if has_new_range {
684 lang_items.RangeCopy
685 } else {
686 lang_items.Range
687 }
688 }
689 (RangeOp::Inclusive, false, true) => {
690 if has_new_range {
691 lang_items.RangeToInclusiveCopy
692 } else {
693 lang_items.RangeToInclusive
694 }
695 }
696 (RangeOp::Inclusive, true, true) => {
697 if has_new_range {
698 lang_items.RangeInclusiveCopy
699 } else {
700 lang_items.RangeInclusiveStruct
701 }
702 }
703 (RangeOp::Inclusive, false, false) => None,
705 (RangeOp::Inclusive, true, false) => None,
706 }
707 }
708
709 pub(crate) fn resolve_await_to_poll(
710 &self,
711 db: &'db dyn HirDatabase,
712 await_expr: &ast::AwaitExpr,
713 ) -> Option<Function> {
714 let mut ty = self.ty_of_expr(await_expr.expr()?)?;
715
716 let into_future_trait = self
717 .resolver
718 .resolve_known_trait(db, &path![core::future::IntoFuture])
719 .map(Trait::from);
720
721 if let Some(into_future_trait) = into_future_trait {
722 let type_ = Type::new_with_resolver(db, &self.resolver, ty);
723 if type_.impls_trait(db, into_future_trait, &[]) {
724 let items = into_future_trait.items(db);
725 let into_future_type = items.into_iter().find_map(|item| match item {
726 AssocItem::TypeAlias(alias)
727 if alias.name(db) == Name::new_symbol_root(sym::IntoFuture) =>
728 {
729 Some(alias)
730 }
731 _ => None,
732 })?;
733 let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
734 ty = future_trait.ty;
735 }
736 }
737
738 let poll_fn = self.lang_items(db).FuturePoll?;
739 let substs = GenericArgs::new_from_slice(&[ty.into()]);
742 Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
743 }
744
745 pub(crate) fn resolve_prefix_expr(
746 &self,
747 db: &'db dyn HirDatabase,
748 prefix_expr: &ast::PrefixExpr,
749 ) -> Option<Function> {
750 let lang_items = self.lang_items(db);
751 let (_op_trait, op_fn) = match prefix_expr.op_kind()? {
752 ast::UnaryOp::Deref => {
753 let (deref_trait, deref) = (lang_items.Deref?, lang_items.Deref_deref?);
757 self.infer()
758 .and_then(|infer| {
759 let expr = self.expr_id(prefix_expr.clone().into())?.as_expr()?;
760 let (func, _) = infer.method_resolution(expr)?;
761 let (deref_mut_trait, deref_mut) =
762 (lang_items.DerefMut?, lang_items.DerefMut_deref_mut?);
763 if func == deref_mut { Some((deref_mut_trait, deref_mut)) } else { None }
764 })
765 .unwrap_or((deref_trait, deref))
766 }
767 ast::UnaryOp::Not => (lang_items.Not?, lang_items.Not_not?),
768 ast::UnaryOp::Neg => (lang_items.Neg?, lang_items.Neg_neg?),
769 };
770
771 let ty = self.ty_of_expr(prefix_expr.expr()?)?;
772
773 let substs = GenericArgs::new_from_slice(&[ty.into()]);
776
777 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
778 }
779
780 pub(crate) fn resolve_index_expr(
781 &self,
782 db: &'db dyn HirDatabase,
783 index_expr: &ast::IndexExpr,
784 ) -> Option<Function> {
785 let base_ty = self.ty_of_expr(index_expr.base()?)?;
786 let index_ty = self.ty_of_expr(index_expr.index()?)?;
787 let lang_items = self.lang_items(db);
788
789 let (_index_trait, index_fn) = (lang_items.Index?, lang_items.Index_index?);
790 let op_fn = self
791 .infer()
792 .and_then(|infer| {
793 let expr = self.expr_id(index_expr.clone().into())?.as_expr()?;
794 let (func, _) = infer.method_resolution(expr)?;
795 let (_index_mut_trait, index_mut_fn) =
796 (lang_items.IndexMut_index_mut?, lang_items.IndexMut_index_mut?);
797 if func == index_mut_fn { Some(index_mut_fn) } else { None }
798 })
799 .unwrap_or(index_fn);
800 let substs = GenericArgs::new_from_slice(&[base_ty.into(), index_ty.into()]);
803 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
804 }
805
806 pub(crate) fn resolve_bin_expr(
807 &self,
808 db: &'db dyn HirDatabase,
809 binop_expr: &ast::BinExpr,
810 ) -> Option<Function> {
811 let op = binop_expr.op_kind()?;
812 let lhs = self.ty_of_expr(binop_expr.lhs()?)?;
813 let rhs = self.ty_of_expr(binop_expr.rhs()?)?;
814
815 let (op_fn, _op_trait) = lang_items_for_bin_op(self.lang_items(db), op)
816 .and_then(|(method, trait_)| method.zip(trait_))?;
817 let substs = GenericArgs::new_from_slice(&[lhs.into(), rhs.into()]);
820
821 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
822 }
823
824 pub(crate) fn resolve_try_expr(
825 &self,
826 db: &'db dyn HirDatabase,
827 try_expr: &ast::TryExpr,
828 ) -> Option<Function> {
829 let ty = self.ty_of_expr(try_expr.expr()?)?;
830
831 let op_fn = self.lang_items(db).TryTraitBranch?;
832 let substs = GenericArgs::new_from_slice(&[ty.into()]);
835
836 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
837 }
838
839 pub(crate) fn resolve_record_field(
840 &self,
841 db: &'db dyn HirDatabase,
842 field: &ast::RecordExprField,
843 ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
844 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
845 let expr = ast::Expr::from(record_expr);
846 let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?;
847 let interner = DbInterner::new_no_crate(db);
848
849 let ast_name = field.field_name()?;
850 let local_name = ast_name.as_name();
851 let local = if field.name_ref().is_some() {
852 None
853 } else {
854 let path = Path::from_known_path_with_no_generic(ModPath::from_segments(
856 PathKind::Plain,
857 once(local_name.clone()),
858 ));
859 match self.resolver.resolve_path_in_value_ns_fully(
860 db,
861 &path,
862 name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),
863 ) {
864 Some(ValueNs::LocalBinding(binding_id)) => Some(Local {
865 binding_id,
866 parent: self.owner()?,
867 parent_infer: self.infer_body?,
868 }),
869 _ => None,
870 }
871 };
872 let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
873 let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
874 let variant_data = variant.fields(db);
875 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
876 let field_ty = (*db.field_types(variant).get(field.local_id)?)
877 .get()
878 .instantiate(interner, subst)
879 .skip_norm_wip();
880 Some((
881 field.into(),
882 local,
883 Type::new_with_resolver(db, &self.resolver, field_ty),
884 GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)),
885 ))
886 }
887
888 pub(crate) fn resolve_record_pat_field(
889 &self,
890 db: &'db dyn HirDatabase,
891 field: &ast::RecordPatField,
892 ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
893 let interner = DbInterner::new_no_crate(db);
894 let field_name = field.field_name()?.as_name();
895 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
896 let pat_id = self.pat_id(&record_pat.into())?;
897 let variant = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?;
898 let variant_data = variant.fields(db);
899 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
900 let (adt, subst) = self.infer()?.pat_ty(pat_id.as_pat()?).as_adt()?;
901 let field_ty = (*db.field_types(variant).get(field.local_id)?)
902 .get()
903 .instantiate(interner, subst)
904 .skip_norm_wip();
905 Some((
906 field.into(),
907 Type::new_with_resolver(db, &self.resolver, field_ty),
908 GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)),
909 ))
910 }
911
912 pub(crate) fn resolve_bind_pat_to_const(
913 &self,
914 db: &'db dyn HirDatabase,
915 pat: &ast::IdentPat,
916 ) -> Option<ModuleDef> {
917 let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
918 let store = self.store()?;
919
920 let path = match expr_or_pat_id {
921 ExprOrPatId::ExprId(idx) => match &store[idx] {
922 Expr::Path(path) => path,
923 _ => return None,
924 },
925 ExprOrPatId::PatId(idx) => match &store[idx] {
926 Pat::Path(path) => path,
927 _ => return None,
928 },
929 };
930
931 let store_owner = self.resolver.expression_store_owner();
932 let res = resolve_hir_value_path(
933 db,
934 &self.resolver,
935 store_owner,
936 self.infer_body,
937 path,
938 HygieneId::ROOT,
939 )?;
940 match res {
941 PathResolution::Def(def) => Some(def),
942 _ => None,
943 }
944 }
945
946 pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<crate::TypeParam> {
947 let name = name.as_name();
948 self.resolver
949 .all_generic_params()
950 .find_map(|(params, parent)| params.find_type_by_name(&name, parent))
951 .map(crate::TypeParam::from)
952 }
953
954 pub(crate) fn resolve_offset_of_field(
955 &self,
956 db: &'db dyn HirDatabase,
957 name_ref: &ast::NameRef,
958 ) -> Option<(Either<crate::EnumVariant, crate::Field>, GenericSubstitution<'db>)> {
959 let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
960 let container = offset_of_expr.ty()?;
961 let container = self.type_of_type(db, &container)?;
962
963 let trait_env = container.env;
964
965 let interner = DbInterner::new_with(db, trait_env.krate);
966 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
967
968 let mut container = Either::Right(container.ty);
969 for field_name in offset_of_expr.fields() {
970 if let Either::Right(container) = &mut container {
971 *container = structurally_normalize_ty(&infcx, *container, trait_env.param_env);
972 }
973 let handle_variants =
974 |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {
975 let fields = variant.fields(db);
976 let field = fields.field(&field_name.as_name())?;
977 let field_types = db.field_types(variant);
978 *container = Either::Right(
979 field_types[field].get().instantiate(interner, subst).skip_norm_wip(),
980 );
981 let generic_def = match variant {
982 VariantId::EnumVariantId(it) => it.loc(db).parent.into(),
983 VariantId::StructId(it) => it.into(),
984 VariantId::UnionId(it) => it.into(),
985 };
986 Some((
987 Either::Right(Field { parent: variant.into(), id: field }),
988 generic_def,
989 subst,
990 ))
991 };
992 let temp_ty = Ty::new_error(interner, ErrorGuaranteed);
993 let (field_def, generic_def, subst) =
994 match std::mem::replace(&mut container, Either::Right(temp_ty)) {
995 Either::Left((variant_id, subst)) => {
996 handle_variants(VariantId::from(variant_id), subst, &mut container)?
997 }
998 Either::Right(container_ty) => match container_ty.kind() {
999 TyKind::Adt(adt_def, subst) => match adt_def.def_id() {
1000 AdtId::StructId(id) => {
1001 handle_variants(id.into(), subst, &mut container)?
1002 }
1003 AdtId::UnionId(id) => {
1004 handle_variants(id.into(), subst, &mut container)?
1005 }
1006 AdtId::EnumId(id) => {
1007 let variants = id.enum_variants(db);
1008 let variant = variants.variant(&field_name.as_name())?;
1009 container = Either::Left((variant, subst));
1010 (Either::Left(EnumVariant { id: variant }), id.into(), subst)
1011 }
1012 },
1013 _ => return None,
1014 },
1015 };
1016
1017 if field_name.syntax().text_range() == name_ref.syntax().text_range() {
1018 return Some((field_def, GenericSubstitution::new(generic_def, subst, trait_env)));
1019 }
1020 }
1021 never!("the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it");
1022 None
1023 }
1024
1025 pub(crate) fn resolve_path(
1026 &self,
1027 db: &'db dyn HirDatabase,
1028 path: &ast::Path,
1029 ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
1030 let parent = path.syntax().parent();
1031 let parent = || parent.clone();
1032
1033 let mut prefer_value_ns = false;
1034 let resolved = (|| {
1035 let infer = self.infer()?;
1036 if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
1037 let expr_id = self.expr_id(path_expr.into())?;
1038 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {
1039 let (assoc, subst) = match assoc {
1040 CandidateId::FunctionId(f_in_trait) => {
1041 match infer.type_of_expr_or_pat(expr_id) {
1042 None => {
1043 let subst = GenericSubstitution::new(
1044 f_in_trait.into(),
1045 subs,
1046 self.trait_environment(db),
1047 );
1048 (AssocItem::Function(f_in_trait.into()), Some(subst))
1049 }
1050 Some(func_ty) => {
1051 if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() {
1052 let (fn_, subst) = self
1053 .resolve_impl_method_or_trait_def_with_subst(
1054 db, f_in_trait, subs,
1055 );
1056 let subst = GenericSubstitution::new_from_fn(
1057 fn_,
1058 subst,
1059 self.trait_environment(db),
1060 );
1061 (AssocItem::Function(fn_), subst)
1062 } else {
1063 let subst = GenericSubstitution::new(
1064 f_in_trait.into(),
1065 subs,
1066 self.trait_environment(db),
1067 );
1068 (AssocItem::Function(f_in_trait.into()), Some(subst))
1069 }
1070 }
1071 }
1072 }
1073 CandidateId::ConstId(const_id) => {
1074 let (konst, subst) =
1075 self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);
1076 let subst = GenericSubstitution::new(
1077 konst.into(),
1078 subst,
1079 self.trait_environment(db),
1080 );
1081 (AssocItem::Const(konst.into()), Some(subst))
1082 }
1083 };
1084
1085 return Some((PathResolution::Def(assoc.into()), subst));
1086 }
1087 if let Some(VariantId::EnumVariantId(variant)) =
1088 infer.variant_resolution_for_expr_or_pat(expr_id)
1089 {
1090 return Some((
1091 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),
1092 None,
1093 ));
1094 }
1095 prefer_value_ns = true;
1096 } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
1097 let expr_or_pat_id = self.pat_id(&path_pat.into())?;
1098 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_or_pat_id)
1099 {
1100 let (assoc, subst) = match assoc {
1101 CandidateId::ConstId(const_id) => {
1102 let (konst, subst) =
1103 self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);
1104 let subst = GenericSubstitution::new(
1105 konst.into(),
1106 subst,
1107 self.trait_environment(db),
1108 );
1109 (AssocItemId::from(konst), subst)
1110 }
1111 CandidateId::FunctionId(function_id) => (
1112 function_id.into(),
1113 GenericSubstitution::new(
1114 function_id.into(),
1115 subs,
1116 self.trait_environment(db),
1117 ),
1118 ),
1119 };
1120 return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));
1121 }
1122 if let Some(VariantId::EnumVariantId(variant)) =
1123 infer.variant_resolution_for_expr_or_pat(expr_or_pat_id)
1124 {
1125 return Some((
1126 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),
1127 None,
1128 ));
1129 }
1130 } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
1131 let expr_id = self.expr_id(rec_lit.into())?;
1132 if let Some(VariantId::EnumVariantId(variant)) =
1133 infer.variant_resolution_for_expr_or_pat(expr_id)
1134 {
1135 return Some((
1136 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),
1137 None,
1138 ));
1139 }
1140 } else {
1141 let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
1142 let tuple_struct_pat =
1143 || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
1144 if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
1145 let pat_id = self.pat_id(&pat)?;
1146 let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?);
1147 if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
1148 return Some((
1149 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),
1150 None,
1151 ));
1152 }
1153 }
1154 }
1155 None
1156 })();
1157 if resolved.is_some() {
1158 return resolved;
1159 }
1160
1161 let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
1163 let hir_path =
1164 collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
1165 let parent_hir_path = path
1166 .parent_path()
1167 .and_then(|p| collector.lower_path(p, &mut ExprCollector::impl_trait_error_allocator));
1168 let (store, _) = collector.store.finish();
1169
1170 if let Some(use_tree) = parent().and_then(ast::UseTree::cast)
1173 && use_tree.coloncolon_token().is_some()
1174 {
1175 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store)
1176 .map(|it| (it, None));
1177 }
1178
1179 let meta_path = path
1180 .syntax()
1181 .ancestors()
1182 .take_while(|it| {
1183 let kind = it.kind();
1184 ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
1185 })
1186 .last()
1187 .and_then(ast::Meta::cast);
1188
1189 if let Some(parent_hir_path) = parent_hir_path {
1192 return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store) {
1193 None if meta_path.is_some() => path
1194 .first_segment()
1195 .and_then(|it| it.name_ref())
1196 .and_then(|name_ref| {
1197 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
1198 .map(PathResolution::ToolModule)
1199 })
1200 .map(|it| (it, None)),
1201 Some(it) if matches!(it, PathResolution::Def(ModuleDef::BuiltinType(_))) => {
1212 if let Some(mod_path) = hir_path.mod_path()
1213 && let Some(ModuleDefId::ModuleId(id)) =
1214 self.resolver.resolve_module_path_in_items(db, mod_path).take_types()
1215 {
1216 let parent_hir_name = parent_hir_path.segments().get(1).map(|it| it.name);
1217 let module = crate::Module { id };
1218 if module
1219 .scope(db, None)
1220 .into_iter()
1221 .any(|(name, _)| Some(&name) == parent_hir_name)
1222 {
1223 return Some((PathResolution::Def(ModuleDef::Module(module)), None));
1224 };
1225 }
1226 Some((it, None))
1227 }
1228 res => res.map(|it| (it, None)),
1232 };
1233 } else if let Some(meta_path) = meta_path {
1234 if let Some(name_ref) = path.as_single_name_ref() {
1238 let builtin = BuiltinAttr::builtin(&name_ref.text());
1239 if builtin.is_some() {
1240 return builtin.map(|it| (PathResolution::BuiltinAttr(it), None));
1241 }
1242
1243 if let Some(attr) = meta_path.parent_attr() {
1244 let adt =
1245 attr.syntax().ancestors().find_map(ast::Item::cast).and_then(
1246 |it| match it {
1247 ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
1248 ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
1249 ast::Item::Union(it) => Some(ast::Adt::Union(it)),
1250 _ => None,
1251 },
1252 );
1253 if let Some(adt) = adt {
1254 let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
1255 if let Some(helpers) = self
1256 .resolver
1257 .def_map()
1258 .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
1259 {
1260 let name_ref = name_ref.as_name();
1262 for (macro_id, mut helpers) in
1263 helpers.iter().chunk_by(|(_, macro_id, ..)| macro_id).into_iter()
1264 {
1265 if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
1266 {
1267 return Some((
1268 PathResolution::DeriveHelper(DeriveHelper {
1269 derive: *macro_id,
1270 idx: idx as u32,
1271 }),
1272 None,
1273 ));
1274 }
1275 }
1276 }
1277 }
1278 }
1279 }
1280 return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {
1281 Some(m) => Some((PathResolution::Def(ModuleDef::Macro(m)), None)),
1282 None => path
1285 .first_segment()
1286 .and_then(|it| it.name_ref())
1287 .and_then(|name_ref| {
1288 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
1289 .map(PathResolution::ToolModule)
1290 })
1291 .map(|it| (it, None)),
1292 };
1293 }
1294 if parent().is_some_and(|it| ast::Visibility::can_cast(it.kind())) {
1295 resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store).map(|it| (it, None))
1297 } else {
1298 let res = resolve_hir_path_(
1300 db,
1301 &self.resolver,
1302 self.infer_body,
1303 &hir_path,
1304 prefer_value_ns,
1305 name_hygiene(db, InFile::new(self.file_id, path.syntax())),
1306 Some(&store),
1307 false,
1308 )
1309 .any()?;
1310 let subst = (|| {
1311 let parent = parent()?;
1312 let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {
1313 let expr_id = self.expr_id(expr)?;
1314 self.infer()?.type_of_expr_or_pat(expr_id)?
1315 } else if let Some(pat) = ast::Pat::cast(parent) {
1316 let pat_id = self.pat_id(&pat)?;
1317 self.infer()?.expr_or_pat_ty(pat_id)
1318 } else {
1319 return None;
1320 };
1321 let env = self.trait_environment(db);
1322 let (subst, expected_resolution) = match ty.kind() {
1323 TyKind::Adt(adt_def, subst) => {
1324 let adt_id = adt_def.def_id();
1325 (
1326 GenericSubstitution::new(adt_id.into(), subst, env),
1327 PathResolution::Def(ModuleDef::Adt(adt_id.into())),
1328 )
1329 }
1330 TyKind::Alias(AliasTy {
1331 kind: AliasTyKind::Projection { def_id },
1332 args,
1333 ..
1334 }) => {
1335 let assoc_id = def_id.0;
1336 (
1337 GenericSubstitution::new(assoc_id.into(), args, env),
1338 PathResolution::Def(ModuleDef::TypeAlias(assoc_id.into())),
1339 )
1340 }
1341 TyKind::FnDef(fn_id, subst) => {
1342 let generic_def_id = match fn_id.0 {
1343 CallableDefId::StructId(id) => id.into(),
1344 CallableDefId::FunctionId(id) => id.into(),
1345 CallableDefId::EnumVariantId(_) => return None,
1346 };
1347 (
1348 GenericSubstitution::new(generic_def_id, subst, env),
1349 PathResolution::Def(ModuleDefId::from(fn_id.0).into()),
1350 )
1351 }
1352 _ => return None,
1353 };
1354 if res != expected_resolution {
1355 return None;
1357 }
1358 Some(subst)
1359 })();
1360 Some((res, subst))
1361 }
1362 }
1363
1364 pub(crate) fn resolve_hir_path_per_ns(
1365 &self,
1366 db: &dyn HirDatabase,
1367 path: &ast::Path,
1368 ) -> Option<PathResolutionPerNs> {
1369 let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
1370 let hir_path =
1371 collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
1372 let (store, _) = collector.store.finish();
1373 Some(resolve_hir_path_(
1374 db,
1375 &self.resolver,
1376 self.infer_body,
1377 &hir_path,
1378 false,
1379 name_hygiene(db, InFile::new(self.file_id, path.syntax())),
1380 Some(&store),
1381 true,
1382 ))
1383 }
1384
1385 pub(crate) fn record_literal_missing_fields(
1386 &self,
1387 db: &'db dyn HirDatabase,
1388 literal: &ast::RecordExpr,
1389 ) -> Option<Vec<(Field, Type<'db>)>> {
1390 let body = self.store()?;
1391 let infer = self.infer()?;
1392
1393 let expr_id = self.expr_id(literal.clone().into())?.as_expr()?;
1394 let substs = infer.expr_ty(expr_id).as_adt()?.1;
1395 let (variant, missing_fields) =
1396 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
1397 let res = self.missing_fields(db, substs, variant, missing_fields);
1398 Some(res)
1399 }
1400
1401 pub(crate) fn record_literal_matched_fields(
1402 &self,
1403 db: &'db dyn HirDatabase,
1404 literal: &ast::RecordExpr,
1405 ) -> Option<Vec<(Field, Type<'db>)>> {
1406 let body = self.store()?;
1407 let infer = self.infer()?;
1408
1409 let expr_id = self.expr_id(literal.clone().into())?.as_expr()?;
1410 let substs = infer.expr_ty(expr_id).as_adt()?.1;
1411 let (variant, matched_fields) =
1412 record_literal_matched_fields(db, infer, expr_id, &body[expr_id])?;
1413
1414 let res = self.missing_fields(db, substs, variant, matched_fields);
1415 Some(res)
1416 }
1417
1418 pub(crate) fn record_pattern_missing_fields(
1419 &self,
1420 db: &'db dyn HirDatabase,
1421 pattern: &ast::RecordPat,
1422 ) -> Option<Vec<(Field, Type<'db>)>> {
1423 let body = self.store()?;
1424 let infer = self.infer()?;
1425
1426 let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;
1427 let substs = infer.pat_ty(pat_id).as_adt()?.1;
1428
1429 let (variant, missing_fields) =
1430 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
1431 let res = self.missing_fields(db, substs, variant, missing_fields);
1432 Some(res)
1433 }
1434
1435 pub(crate) fn record_pattern_matched_fields(
1436 &self,
1437 db: &'db dyn HirDatabase,
1438 pattern: &ast::RecordPat,
1439 ) -> Option<Vec<(Field, Type<'db>)>> {
1440 let body = self.store()?;
1441 let infer = self.infer()?;
1442
1443 let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;
1444 let substs = infer.pat_ty(pat_id).as_adt()?.1;
1445
1446 let (variant, matched_fields) =
1447 record_pattern_matched_fields(db, infer, pat_id, &body[pat_id])?;
1448 let res = self.missing_fields(db, substs, variant, matched_fields);
1449 Some(res)
1450 }
1451
1452 fn missing_fields(
1453 &self,
1454 db: &'db dyn HirDatabase,
1455 substs: GenericArgs<'db>,
1456 variant: VariantId,
1457 missing_fields: Vec<LocalFieldId>,
1458 ) -> Vec<(Field, Type<'db>)> {
1459 let interner = DbInterner::new_no_crate(db);
1460 let field_types = db.field_types(variant);
1461
1462 missing_fields
1463 .into_iter()
1464 .map(|local_id| {
1465 let field = FieldId { parent: variant, local_id };
1466 let ty = field_types[local_id].get().instantiate(interner, substs).skip_norm_wip();
1467 (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
1468 })
1469 .collect()
1470 }
1471
1472 pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
1473 let infer = self.infer()?;
1474 let expr_id = self.expr_id(record_lit.into())?;
1475 infer.variant_resolution_for_expr_or_pat(expr_id)
1476 }
1477
1478 pub(crate) fn is_unsafe_macro_call_expr(
1479 &self,
1480 db: &'db dyn HirDatabase,
1481 macro_expr: InFile<&ast::MacroExpr>,
1482 ) -> bool {
1483 if let Some((def, body, sm, Some(infer))) = self.def()
1484 && let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr)
1485 {
1486 let mut is_unsafe = false;
1487 let mut walk_expr = |expr_id| {
1488 unsafe_operations(db, infer, def, body, expr_id, &mut |_, inside_unsafe_block| {
1489 is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
1490 })
1491 };
1492 match expanded_expr {
1493 ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
1494 ExprOrPatId::PatId(expanded_pat) => body.walk_exprs_in_pat(expanded_pat, walk_expr),
1495 }
1496 return is_unsafe;
1497 }
1498 false
1499 }
1500
1501 pub(crate) fn resolve_offset_in_format_args(
1503 &self,
1504 db: &'db dyn HirDatabase,
1505 format_args: InFile<&ast::FormatArgsExpr>,
1506 offset: TextSize,
1507 ) -> Option<(TextRange, Option<PathResolution>)> {
1508 let (hygiene, implicits) = self.store_sm()?.implicit_format_args(format_args)?;
1509 implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| {
1510 (
1511 *range,
1512 resolve_hir_value_path(
1513 db,
1514 &self.resolver,
1515 self.resolver.expression_store_owner(),
1516 self.infer_body,
1517 &Path::from_known_path_with_no_generic(ModPath::from_segments(
1518 PathKind::Plain,
1519 Some(name.clone()),
1520 )),
1521 hygiene,
1522 ),
1523 )
1524 })
1525 }
1526
1527 pub(crate) fn resolve_offset_in_asm_template(
1528 &self,
1529 asm: InFile<&ast::AsmExpr>,
1530 line: usize,
1531 offset: TextSize,
1532 ) -> Option<(ExpressionStoreOwnerId, (ExprId, TextRange, usize))> {
1533 let (def, _, sm, _) = self.def()?;
1534 let (expr, args) = sm.asm_template_args(asm)?;
1535 Some(def).zip(
1536 args.get(line)?
1537 .iter()
1538 .find(|(range, _)| range.contains_inclusive(offset))
1539 .map(|(range, idx)| (expr, *range, *idx)),
1540 )
1541 }
1542
1543 pub(crate) fn as_format_args_parts<'a>(
1544 &'a self,
1545 db: &'a dyn HirDatabase,
1546 format_args: InFile<&ast::FormatArgsExpr>,
1547 ) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
1548 let (hygiene, names) = self.store_sm()?.implicit_format_args(format_args)?;
1549 Some(names.iter().map(move |(range, name)| {
1550 (
1551 *range,
1552 resolve_hir_value_path(
1553 db,
1554 &self.resolver,
1555 self.resolver.expression_store_owner(),
1556 self.infer_body,
1557 &Path::from_known_path_with_no_generic(ModPath::from_segments(
1558 PathKind::Plain,
1559 Some(name.clone()),
1560 )),
1561 hygiene,
1562 ),
1563 )
1564 }))
1565 }
1566
1567 pub(crate) fn as_asm_parts(
1568 &self,
1569 asm: InFile<&ast::AsmExpr>,
1570 ) -> Option<(ExpressionStoreOwnerId, (ExprId, &[Vec<(TextRange, usize)>]))> {
1571 let (def, _, sm, _) = self.def()?;
1572 Some(def).zip(sm.asm_template_args(asm))
1573 }
1574
1575 fn resolve_impl_method_or_trait_def(
1576 &self,
1577 db: &'db dyn HirDatabase,
1578 func: FunctionId,
1579 substs: GenericArgs<'db>,
1580 ) -> Function {
1581 self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0
1582 }
1583
1584 fn resolve_impl_method_or_trait_def_with_subst(
1585 &self,
1586 db: &'db dyn HirDatabase,
1587 func: FunctionId,
1588 substs: GenericArgs<'db>,
1589 ) -> (Function, GenericArgs<'db>) {
1590 let owner = match self.resolver.expression_store_owner() {
1591 Some(it) => it,
1592 None => return (func.into(), substs),
1593 };
1594 let env = self.param_and(db.trait_environment(owner));
1595 let (func, args) = db.lookup_impl_method(env, func, substs);
1596 match func {
1597 Either::Left(func) => (func.into(), args),
1598 Either::Right((impl_, method)) => {
1599 (Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }, args)
1600 }
1601 }
1602 }
1603
1604 fn resolve_impl_const_or_trait_def_with_subst(
1605 &self,
1606 db: &'db dyn HirDatabase,
1607 const_id: ConstId,
1608 subs: GenericArgs<'db>,
1609 ) -> (ConstId, GenericArgs<'db>) {
1610 let owner = match self.resolver.expression_store_owner() {
1611 Some(it) => it,
1612 None => return (const_id, subs),
1613 };
1614 let env = self.param_and(db.trait_environment(owner));
1615 let interner = DbInterner::new_with(db, env.krate);
1616 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
1617 method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs)
1618 }
1619
1620 fn lang_items<'a>(&self, db: &'a dyn HirDatabase) -> &'a LangItems {
1621 hir_def::lang_item::lang_items(db, self.resolver.krate())
1622 }
1623
1624 fn ty_of_expr(&self, expr: ast::Expr) -> Option<Ty<'db>> {
1625 self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?)
1626 }
1627}
1628
1629fn scope_for(
1632 db: &dyn HirDatabase,
1633 scopes: &ExprScopes,
1634 source_map: &ExpressionStoreSourceMap,
1635 node: InFile<&SyntaxNode>,
1636) -> Option<(ScopeId, ExprId)> {
1637 node.ancestors_with_macros(db)
1638 .take_while(|it| {
1639 let kind = it.kind();
1640 !ast::Item::can_cast(kind)
1641 || ast::MacroCall::can_cast(kind)
1642 || ast::Use::can_cast(kind)
1643 || ast::AsmExpr::can_cast(kind)
1644 })
1645 .filter_map(|it| it.map(ast::Expr::cast).transpose())
1646 .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
1647 .find_map(|expr| scopes.scope_for(expr).map(|scope| (scope, expr)))
1648}
1649
1650fn scope_for_offset(
1651 db: &dyn HirDatabase,
1652 scopes: &ExprScopes,
1653 source_map: &ExpressionStoreSourceMap,
1654 from_file: HirFileId,
1655 offset: TextSize,
1656) -> Option<(ScopeId, ExprId)> {
1657 scopes
1658 .scope_by_expr()
1659 .iter()
1660 .filter_map(|(id, scope)| {
1661 let InFile { file_id, value } = source_map.expr_syntax(id).ok()?;
1662 if from_file == file_id {
1663 return Some((value.text_range(), scope, id));
1664 }
1665
1666 let source = iter::successors(file_id.macro_file().map(|it| it.call_node(db)), |it| {
1668 Some(it.file_id.macro_file()?.call_node(db))
1669 })
1670 .find(|it| it.file_id == from_file)
1671 .filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;
1672 Some((source.text_range(), scope, id))
1673 })
1674 .filter(|(expr_range, _scope, _expr)| {
1675 expr_range.start() <= offset && offset <= expr_range.end()
1676 })
1677 .min_by_key(|(expr_range, _scope, _expr)| expr_range.len())
1679 .map(|(expr_range, scope, expr)| {
1680 adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or((*scope, expr))
1681 })
1682}
1683
1684fn adjust(
1687 db: &dyn HirDatabase,
1688 scopes: &ExprScopes,
1689 source_map: &ExpressionStoreSourceMap,
1690 expr_range: TextRange,
1691 from_file: HirFileId,
1692 offset: TextSize,
1693) -> Option<(ScopeId, ExprId)> {
1694 let child_scopes = scopes
1695 .scope_by_expr()
1696 .iter()
1697 .filter_map(|(id, scope)| {
1698 let source = source_map.expr_syntax(id).ok()?;
1699 if source.file_id != from_file {
1701 return None;
1702 }
1703 let root = source.file_syntax(db);
1704 let node = source.value.to_node(&root);
1705 Some((node.syntax().text_range(), scope, id))
1706 })
1707 .filter(|&(range, _, _)| {
1708 range.start() <= offset && expr_range.contains_range(range) && range != expr_range
1709 });
1710
1711 child_scopes
1712 .max_by(|&(r1, _, _), &(r2, _, _)| {
1713 if r1.contains_range(r2) {
1714 std::cmp::Ordering::Greater
1715 } else if r2.contains_range(r1) {
1716 std::cmp::Ordering::Less
1717 } else {
1718 r1.start().cmp(&r2.start())
1719 }
1720 })
1721 .map(|(_ptr, scope, expr)| (*scope, expr))
1722}
1723
1724#[inline]
1725pub(crate) fn resolve_hir_path(
1726 db: &dyn HirDatabase,
1727 resolver: &Resolver<'_>,
1728 infer_body: Option<InferBodyId>,
1729 path: &Path,
1730 hygiene: HygieneId,
1731 store: Option<&ExpressionStore>,
1732) -> Option<PathResolution> {
1733 resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any()
1734}
1735
1736#[inline]
1737pub(crate) fn resolve_hir_path_as_attr_macro(
1738 db: &dyn HirDatabase,
1739 resolver: &Resolver<'_>,
1740 path: &Path,
1741) -> Option<Macro> {
1742 resolver
1743 .resolve_path_as_macro(db, path.mod_path()?, Some(MacroSubNs::Attr))
1744 .map(|(it, _)| it)
1745 .map(Into::into)
1746}
1747
1748fn resolve_hir_path_(
1749 db: &dyn HirDatabase,
1750 resolver: &Resolver<'_>,
1751 infer_body: Option<InferBodyId>,
1752 path: &Path,
1753 prefer_value_ns: bool,
1754 hygiene: HygieneId,
1755 store: Option<&ExpressionStore>,
1756 resolve_per_ns: bool,
1757) -> PathResolutionPerNs {
1758 let types = || {
1759 let (ty, unresolved) = match path.type_anchor() {
1760 Some(type_ref) => resolver.generic_def().and_then(|def| {
1761 let generics = OnceCell::new();
1762 let (_, res) = TyLoweringContext::new(
1763 db,
1764 resolver,
1765 store?,
1766 def.into(),
1767 def,
1768 &generics,
1769 LifetimeElisionKind::Infer,
1770 )
1771 .lower_ty_ext(type_ref);
1772 res.map(|ty_ns| (ty_ns, path.segments().first()))
1773 }),
1774 None => {
1775 let (ty, remaining_idx, _) = resolver.resolve_path_in_type_ns(db, path)?;
1776 match remaining_idx {
1777 Some(remaining_idx) => {
1778 if remaining_idx + 1 == path.segments().len() {
1779 Some((ty, path.segments().last()))
1780 } else {
1781 None
1782 }
1783 }
1784 None => Some((ty, None)),
1785 }
1786 }
1787 }?;
1788
1789 if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty)
1792 && let Some(type_alias_id) =
1793 trait_id.trait_items(db).associated_type_by_name(unresolved.name)
1794 {
1795 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
1796 }
1797
1798 let res = match ty {
1799 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
1800 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
1801 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
1802 PathResolution::Def(Adt::from(it).into())
1803 }
1804 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
1805 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
1806 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
1807 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
1808 TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())),
1809 };
1810 match unresolved {
1811 Some(unresolved) => resolver
1812 .generic_def()
1813 .and_then(|def| {
1814 hir_ty::associated_type_shorthand_candidates(
1815 db,
1816 def,
1817 res.in_type_ns()?,
1818 |name, _| name == unresolved.name,
1819 )
1820 })
1821 .map(TypeAlias::from)
1822 .map(Into::into)
1823 .map(PathResolution::Def),
1824 None => Some(res),
1825 }
1826 };
1827
1828 let body_owner = resolver.expression_store_owner();
1829 let values = || resolve_hir_value_path(db, resolver, body_owner, infer_body, path, hygiene);
1830
1831 let items = || {
1832 resolver
1833 .resolve_module_path_in_items(db, path.mod_path()?)
1834 .take_types()
1835 .map(|it| PathResolution::Def(it.into()))
1836 };
1837
1838 let macros = || {
1839 resolver
1840 .resolve_path_as_macro(db, path.mod_path()?, None)
1841 .map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into())))
1842 };
1843
1844 if resolve_per_ns {
1845 PathResolutionPerNs {
1846 type_ns: types().or_else(items),
1847 value_ns: values(),
1848 macro_ns: macros(),
1849 }
1850 } else {
1851 let res = if prefer_value_ns {
1852 values()
1853 .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None))
1854 .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None))
1855 } else {
1856 types()
1857 .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None))
1858 .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None))
1859 };
1860
1861 if res.any().is_some() {
1862 res
1863 } else if let Some(type_ns) = items() {
1864 PathResolutionPerNs::new(Some(type_ns), None, None)
1865 } else {
1866 PathResolutionPerNs::new(None, None, macros())
1867 }
1868 }
1869}
1870
1871fn resolve_hir_value_path(
1872 db: &dyn HirDatabase,
1873 resolver: &Resolver<'_>,
1874 store_owner: Option<ExpressionStoreOwnerId>,
1875 infer_body: Option<InferBodyId>,
1876 path: &Path,
1877 hygiene: HygieneId,
1878) -> Option<PathResolution> {
1879 resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| {
1880 let res = match val {
1881 ValueNs::LocalBinding(binding_id) => {
1882 let var = Local { parent: store_owner?, parent_infer: infer_body?, binding_id };
1883 PathResolution::Local(var)
1884 }
1885 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
1886 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
1887 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
1888 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
1889 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
1890 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
1891 ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
1892 };
1893 Some(res)
1894 })
1895}
1896
1897fn resolve_hir_path_qualifier(
1911 db: &dyn HirDatabase,
1912 resolver: &Resolver<'_>,
1913 path: &Path,
1914 store: &ExpressionStore,
1915) -> Option<PathResolution> {
1916 (|| {
1917 let (ty, unresolved) = match path.type_anchor() {
1918 Some(type_ref) => resolver.generic_def().and_then(|def| {
1919 let generics = OnceCell::new();
1920 let (_, res) = TyLoweringContext::new(
1921 db,
1922 resolver,
1923 store,
1924 def.into(),
1925 def,
1926 &generics,
1927 LifetimeElisionKind::Infer,
1928 )
1929 .lower_ty_ext(type_ref);
1930 res.map(|ty_ns| (ty_ns, path.segments().first()))
1931 }),
1932 None => {
1933 let (ty, remaining_idx, _) = resolver.resolve_path_in_type_ns(db, path)?;
1934 match remaining_idx {
1935 Some(remaining_idx) => {
1936 if remaining_idx + 1 == path.segments().len() {
1937 Some((ty, path.segments().last()))
1938 } else {
1939 None
1940 }
1941 }
1942 None => Some((ty, None)),
1943 }
1944 }
1945 }?;
1946
1947 if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty)
1950 && let Some(type_alias_id) =
1951 trait_id.trait_items(db).associated_type_by_name(unresolved.name)
1952 {
1953 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
1954 }
1955
1956 let res = match ty {
1957 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
1958 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
1959 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
1960 PathResolution::Def(Adt::from(it).into())
1961 }
1962 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
1963 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
1964 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
1965 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
1966 TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())),
1967 };
1968 match unresolved {
1969 Some(unresolved) => resolver
1970 .generic_def()
1971 .and_then(|def| {
1972 hir_ty::associated_type_shorthand_candidates(
1973 db,
1974 def,
1975 res.in_type_ns()?,
1976 |name, _| name == unresolved.name,
1977 )
1978 })
1979 .map(TypeAlias::from)
1980 .map(Into::into)
1981 .map(PathResolution::Def),
1982 None => Some(res),
1983 }
1984 })()
1985 .or_else(|| {
1986 resolver
1987 .resolve_module_path_in_items(db, path.mod_path()?)
1988 .take_types()
1989 .map(|it| PathResolution::Def(it.into()))
1990 })
1991}
1992
1993pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> HygieneId {
1994 let Some(macro_file) = name.file_id.macro_file() else {
1995 return HygieneId::ROOT;
1996 };
1997 let span_map = db.expansion_span_map(macro_file);
1998 let ctx = span_map.span_at(name.value.text_range().start()).ctx;
1999 HygieneId::new(ctx.opaque_and_semiopaque(db))
2000}
2001
2002fn record_literal_matched_fields(
2003 db: &dyn HirDatabase,
2004 infer: &InferenceResult,
2005 id: ExprId,
2006 expr: &Expr,
2007) -> Option<(VariantId, Vec<LocalFieldId>)> {
2008 let (fields, _spread) = match expr {
2009 Expr::RecordLit { fields, spread, .. } => (fields, spread),
2010 _ => return None,
2011 };
2012
2013 let variant_def = infer.variant_resolution_for_expr(id)?;
2014 if let VariantId::UnionId(_) = variant_def {
2015 return None;
2016 }
2017
2018 let variant_data = variant_def.fields(db);
2019
2020 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
2021 let matched_fields: Vec<LocalFieldId> = variant_data
2024 .fields()
2025 .iter()
2026 .filter_map(|(f, d)| (!specified_fields.contains(&d.name)).then_some(f))
2027 .collect();
2028 if matched_fields.is_empty() {
2029 return None;
2030 }
2031 Some((variant_def, matched_fields))
2032}
2033
2034fn record_pattern_matched_fields(
2035 db: &dyn HirDatabase,
2036 infer: &InferenceResult,
2037 id: PatId,
2038 pat: &Pat,
2039) -> Option<(VariantId, Vec<LocalFieldId>)> {
2040 let (fields, _ellipsis) = match pat {
2041 Pat::Record { path: _, args, ellipsis } => (args, *ellipsis),
2042 _ => return None,
2043 };
2044
2045 let variant_def = infer.variant_resolution_for_pat(id)?;
2046 if let VariantId::UnionId(_) = variant_def {
2047 return None;
2048 }
2049
2050 let variant_data = variant_def.fields(db);
2051
2052 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
2053 let matched_fields: Vec<LocalFieldId> = variant_data
2056 .fields()
2057 .iter()
2058 .filter_map(|(f, d)| if !specified_fields.contains(&d.name) { Some(f) } else { None })
2059 .collect();
2060 if matched_fields.is_empty() {
2061 return None;
2062 }
2063 Some((variant_def, matched_fields))
2064}