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