1//! Lookup hir elements using positions in the source code. This is a lossy2//! transformation: in general, a single source might correspond to several3//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on4//! modules.5//!6//! So, this modules should not be used during hir construction, it exists7//! purely for "IDE needs".8use std::{9 cell::OnceCell,10 iter::{self, once},11};1213use either::Either;14use hir_def::{15 AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId,16 FunctionId, GenericDefId, HasModule, LocalFieldId, ModuleDefId, StructId, VariantId,17 expr_store::{18 Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId,19 lower::{ExprCollector, lower_generic_params},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, 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, TyLoweringInferVarsCtx,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, DefaultAny, EarlyBinder, ErrorGuaranteed, GenericArgs, ParamEnv,45 Region, Ty, TyKind, TypingMode, infer::DbInternerInferExt,46 },47 traits::{WherePredicateEvaluation, structurally_normalize_ty, where_predicate_must_hold},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};6263use crate::{64 Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const,65 DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef,66 PredicateEvaluationResult, SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type,67 TypeAlias, TypeOwnerId,68 db::HirDatabase,69 semantics::{PathResolution, PathResolutionPerNs},70};7172/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of73/// original source files. It should not be used inside the HIR itself.74#[derive(Debug)]75pub(crate) struct SourceAnalyzer<'db> {76 pub(crate) file_id: HirFileId,77 pub(crate) resolver: Resolver<'db>,78 pub(crate) body_or_sig: Option<BodyOrSig<'db>>,79 pub(crate) type_owner: TypeOwnerId,80 pub(crate) infer_body: Option<InferBodyId>,81}8283#[derive(Debug)]84pub(crate) enum BodyOrSig<'db> {85 Body {86 def: DefWithBodyId,87 body: &'db Body,88 source_map: &'db BodySourceMap,89 infer: Option<&'db InferenceResult>,90 },91 VariantFields {92 def: VariantId,93 store: &'db ExpressionStore,94 source_map: &'db ExpressionStoreSourceMap,95 infer: Option<&'db InferenceResult>,96 },97 Sig {98 def: GenericDefId,99 store: &'db ExpressionStore,100 source_map: &'db ExpressionStoreSourceMap,101 infer: Option<&'db InferenceResult>,102 #[expect(dead_code)]103 generics: &'db GenericParams,104 },105}106107impl<'db> SourceAnalyzer<'db> {108 pub(crate) fn new_for_body(109 db: &'db dyn HirDatabase,110 def: DefWithBodyId,111 node: InFile<&SyntaxNode>,112 offset: Option<TextSize>,113 ) -> SourceAnalyzer<'db> {114 Self::new_for_body_(db, def, node, offset, Some(InferenceResult::of(db, def)))115 }116117 pub(crate) fn new_for_body_no_infer(118 db: &'db dyn HirDatabase,119 def: DefWithBodyId,120 node: InFile<&SyntaxNode>,121 offset: Option<TextSize>,122 ) -> SourceAnalyzer<'db> {123 Self::new_for_body_(db, def, node, offset, None)124 }125126 pub(crate) fn new_for_body_(127 db: &'db dyn HirDatabase,128 def: DefWithBodyId,129 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,130 offset: Option<TextSize>,131 infer: Option<&'db InferenceResult>,132 ) -> SourceAnalyzer<'db> {133 let (body, source_map) = Body::with_source_map(db, def);134 let scopes = ExprScopes::of(db, def);135 let scope = match offset {136 None => scope_for(db, scopes, source_map, node),137 Some(offset) => {138 debug_assert!(139 node.text_range().contains_inclusive(offset),140 "{:?} not in {:?}",141 offset,142 node.text_range()143 );144 scope_for_offset(db, scopes, source_map, node.file_id, offset)145 }146 };147 let (scope, _expr) = scope.unzip();148 let resolver = resolver_for_scope(db, def, scope);149 SourceAnalyzer {150 resolver,151 body_or_sig: Some(BodyOrSig::Body { def, body, source_map, infer }),152 file_id,153 type_owner: def.generic_def(db).into(),154 infer_body: Some(def.into()),155 }156 }157158 pub(crate) fn new_generic_def(159 db: &'db dyn HirDatabase,160 sema: &SemanticsImpl<'db>,161 def: GenericDefId,162 node: InFile<&SyntaxNode>,163 offset: Option<TextSize>,164 ) -> SourceAnalyzer<'db> {165 Self::new_generic_def_(db, sema, def, node, offset, true)166 }167168 pub(crate) fn new_generic_def_no_infer(169 db: &'db dyn HirDatabase,170 sema: &SemanticsImpl<'db>,171 def: GenericDefId,172 node: InFile<&SyntaxNode>,173 offset: Option<TextSize>,174 ) -> SourceAnalyzer<'db> {175 Self::new_generic_def_(db, sema, def, node, offset, false)176 }177178 pub(crate) fn new_generic_def_(179 db: &'db dyn HirDatabase,180 sema: &SemanticsImpl<'db>,181 def: GenericDefId,182 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,183 offset: Option<TextSize>,184 infer: bool,185 ) -> SourceAnalyzer<'db> {186 let (generics, store, source_map) = GenericParams::with_source_map(db, def);187 let scopes = ExprScopes::of(db, def);188 let scope = match offset {189 None => scope_for(db, scopes, source_map, node),190 Some(offset) => {191 debug_assert!(192 node.text_range().contains_inclusive(offset),193 "{:?} not in {:?}",194 offset,195 node.text_range()196 );197 scope_for_offset(db, scopes, source_map, node.file_id, offset)198 }199 };200 let (scope, expr) = scope.unzip();201 let resolver = resolver_for_scope(db, def, scope);202 let infer_body = expr.and_then(|expr| {203 sema.infer_body_for_expr_or_pat(204 ExpressionStoreOwnerId::Signature(def),205 store,206 expr.into(),207 )208 });209 let infer = if infer && let Some(infer_body) = infer_body {210 Some(InferenceResult::of(db, infer_body))211 } else {212 None213 };214 SourceAnalyzer {215 resolver,216 body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }),217 file_id,218 type_owner: def.into(),219 infer_body,220 }221 }222223 pub(crate) fn new_variant_body(224 db: &'db dyn HirDatabase,225 sema: &SemanticsImpl<'db>,226 def: VariantId,227 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,228 offset: Option<TextSize>,229 infer: bool,230 ) -> SourceAnalyzer<'db> {231 let (fields, source_map) = def.fields_with_source_map(db);232 let scopes = ExprScopes::of(db, def);233 let scope = match offset {234 None => scope_for(db, scopes, source_map, node),235 Some(offset) => {236 debug_assert!(237 node.text_range().contains_inclusive(offset),238 "{:?} not in {:?}",239 offset,240 node.text_range()241 );242 scope_for_offset(db, scopes, source_map, node.file_id, offset)243 }244 };245 let (scope, expr) = scope.unzip();246 let resolver = resolver_for_scope(db, def, scope);247 let infer_body = expr.and_then(|expr| {248 sema.infer_body_for_expr_or_pat(249 ExpressionStoreOwnerId::VariantFields(def),250 &fields.store,251 expr.into(),252 )253 });254 let infer = if infer && let Some(infer_body) = infer_body {255 Some(InferenceResult::of(db, infer_body))256 } else {257 None258 };259 SourceAnalyzer {260 resolver,261 body_or_sig: Some(BodyOrSig::VariantFields {262 def,263 store: &fields.store,264 source_map,265 infer,266 }),267 file_id,268 type_owner: GenericDefId::from(def.adt_id(db)).into(),269 infer_body,270 }271 }272273 pub(crate) fn new_for_resolver(274 resolver: Resolver<'db>,275 node: InFile<&SyntaxNode>,276 ) -> SourceAnalyzer<'db> {277 SourceAnalyzer {278 type_owner: resolver279 .generic_def()280 .map(Into::into)281 .unwrap_or_else(|| TypeOwnerId::NoParams(resolver.krate())),282 resolver,283 body_or_sig: None,284 file_id: node.file_id,285 infer_body: None,286 }287 }288289 fn owner(&self) -> Option<ExpressionStoreOwnerId> {290 self.body_or_sig.as_ref().map(|it| match *it {291 BodyOrSig::VariantFields { def, .. } => def.into(),292 BodyOrSig::Sig { def, .. } => def.into(),293 BodyOrSig::Body { def, .. } => def.into(),294 })295 }296297 fn infer(&self) -> Option<&InferenceResult> {298 self.body_or_sig.as_ref().and_then(|it| match it {299 BodyOrSig::VariantFields { infer, .. }300 | BodyOrSig::Sig { infer, .. }301 | BodyOrSig::Body { infer, .. } => infer.as_deref(),302 })303 }304305 pub(crate) fn ty(&self, ty: Ty<'db>) -> Type<'db> {306 Type { owner: self.type_owner, ty: EarlyBinder::bind(ty) }307 }308309 pub(crate) fn def(310 &self,311 ) -> Option<(312 ExpressionStoreOwnerId,313 &ExpressionStore,314 &ExpressionStoreSourceMap,315 Option<&InferenceResult>,316 )> {317 self.body_or_sig.as_ref().map(|it| match *it {318 BodyOrSig::VariantFields { def, store, source_map, infer, .. } => {319 (def.into(), store, source_map, infer)320 }321 BodyOrSig::Sig { def, store, source_map, infer, .. } => {322 (def.into(), store, source_map, infer)323 }324 BodyOrSig::Body { def, body, source_map, infer, .. } => {325 (def.into(), &body.store, &source_map.store, infer)326 }327 })328 }329330 pub(crate) fn store(&self) -> Option<&ExpressionStore> {331 self.body_or_sig.as_ref().map(|it| match it {332 BodyOrSig::Sig { store, .. } => &**store,333 BodyOrSig::VariantFields { store, .. } => &**store,334 BodyOrSig::Body { body, .. } => &body.store,335 })336 }337338 pub(crate) fn store_sm(&self) -> Option<&ExpressionStoreSourceMap> {339 self.body_or_sig.as_ref().map(|it| match it {340 BodyOrSig::Sig { source_map, .. } => &**source_map,341 BodyOrSig::VariantFields { source_map, .. } => &**source_map,342 BodyOrSig::Body { source_map, .. } => &source_map.store,343 })344 }345346 fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> {347 ParamEnvAndCrate { param_env, krate: self.resolver.krate() }348 }349350 fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> {351 self.param_and(self.body_or_sig.as_ref().map_or_else(352 || ParamEnv::empty(DbInterner::new_no_crate(db)),353 |body_or_sig| {354 let def = match *body_or_sig {355 BodyOrSig::Body { def, .. } => def.generic_def(db),356 BodyOrSig::VariantFields { def, .. } => match def {357 VariantId::EnumVariantId(def) => def.loc(db).parent.into(),358 VariantId::StructId(def) => def.into(),359 VariantId::UnionId(def) => def.into(),360 },361 BodyOrSig::Sig { def, .. } => def,362 };363 db.trait_environment(def)364 },365 ))366 }367368 pub(crate) fn evaluate_where_clause(369 &self,370 db: &'db dyn HirDatabase,371 where_clause: ast::WhereClause,372 ) -> PredicateEvaluationResult {373 let Some(owner) = self.owner() else {374 // FIXME375 return PredicateEvaluationResult::unsupported(376 "predicate evaluation is only supported inside an item",377 );378 };379 let generic_def = owner.generic_def(db);380 let module = generic_def.module(db);381 let (store, params, _) =382 lower_generic_params(db, module, generic_def, self.file_id, None, Some(where_clause));383 let predicates = params.where_predicates();384 if predicates.is_empty() {385 return PredicateEvaluationResult::holds("predicate does not impose any obligations");386 }387388 let env = self.trait_environment(db);389 for predicate in predicates {390 match where_predicate_must_hold(391 db,392 &self.resolver,393 &store,394 owner,395 generic_def,396 env,397 predicate,398 ) {399 WherePredicateEvaluation::Holds | WherePredicateEvaluation::NoObligations => {}400 WherePredicateEvaluation::HasErrors => {401 return PredicateEvaluationResult::invalid(402 "predicate contains unresolved names or invalid type syntax",403 );404 }405 WherePredicateEvaluation::NotProven => {406 return PredicateEvaluationResult::not_proven("predicate is not known to hold");407 }408 }409 }410411 PredicateEvaluationResult::holds("predicate holds")412 }413414 pub(crate) fn expr_id(&self, expr: ast::Expr) -> Option<ExprOrPatId> {415 let src = InFile { file_id: self.file_id, value: expr };416 self.store_sm()?.node_expr(src.as_ref())417 }418419 fn pat_id(&self, pat: &ast::Pat) -> Option<ExprOrPatId> {420 let src = InFile { file_id: self.file_id, value: pat };421 self.store_sm()?.node_pat(src)422 }423424 fn type_id(&self, pat: &ast::Type) -> Option<TypeRefId> {425 let src = InFile { file_id: self.file_id, value: pat };426 self.store_sm()?.node_type(src)427 }428429 fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {430 let pat_id = self.pat_id(&pat.clone().into())?;431 if let Pat::Bind { id, .. } = self.store()?[pat_id.as_pat()?] { Some(id) } else { None }432 }433434 pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]> {435 // It is safe to omit destructuring assignments here because they have no adjustments (neither436 // expressions nor patterns).437 let expr_id = self.expr_id(expr.clone())?.as_expr()?;438 let infer = self.infer()?;439 infer.expr_adjustment(expr_id)440 }441442 pub(crate) fn type_of_type(443 &self,444 db: &'db dyn HirDatabase,445 ty: &ast::Type,446 ) -> Option<Type<'db>> {447 let interner = DbInterner::new_no_crate(db);448449 let type_ref = self.type_id(ty)?;450451 let generic_def = self.resolver.generic_def()?;452 let generics = OnceCell::new();453 let mut vars_cts = VarsCtx { types: interner.default_types(), infer: self.infer() };454 let ty = TyLoweringContext::new(455 db,456 &self.resolver,457 self.store()?,458 generic_def.into(),459 generic_def,460 &generics,461 // FIXME: Is this correct here? Anyway that should impact mostly diagnostics, which we don't emit here462 // (this can impact the lifetimes generated, e.g. in `const` they won't be `'static`, but this seems like a463 // small problem).464 LifetimeElisionKind::Infer,465 )466 .with_infer_vars_behavior(Some(&mut vars_cts))467 .lower_ty(type_ref);468469 struct VarsCtx<'a, 'db> {470 types: &'db DefaultAny<'db>,471 infer: Option<&'a InferenceResult>,472 }473474 impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> {475 fn next_ty_var(&mut self, span: hir_ty::Span) -> Ty<'db> {476 if let hir_ty::Span::TypeRefId(type_ref) = span477 && let Some(ty) =478 self.infer.and_then(|infer| infer.type_of_type_placeholder(type_ref))479 {480 ty481 } else {482 self.types.types.error483 }484 }485 fn next_const_var(&mut self, _span: hir_ty::Span) -> hir_ty::next_solver::Const<'db> {486 self.types.consts.error487 }488 fn next_region_var(&mut self, _span: hir_ty::Span) -> Region<'db> {489 self.types.regions.error490 }491 }492493 Some(self.ty(ty))494 }495496 pub(crate) fn expr_is_diverging(497 &self,498 _db: &'db dyn HirDatabase,499 expr: &ast::Expr,500 ) -> Option<bool> {501 let expr_id = self.expr_id(expr.clone())?;502 let store = self.store()?;503 let infer = self.infer()?;504 Some(self.expr_id_is_diverging(store, infer, expr_id))505 }506507 fn expr_id_is_diverging(508 &self,509 store: &ExpressionStore,510 infer: &InferenceResult,511 expr_id: ExprOrPatId,512 ) -> bool {513 // FIXME: This is an approximation, perhaps we need to store a set of diverging exprs in inference?514 if infer.type_of_expr_or_pat(expr_id).is_some_and(|ty| ty.is_never()) {515 true516 } else if let ExprOrPatId::ExprId(expr_id) = expr_id517 && let Expr::Block { tail: Some(tail), .. } = store[expr_id]518 {519 self.expr_id_is_diverging(store, infer, tail.into())520 } else {521 false522 }523 }524525 pub(crate) fn type_of_expr(526 &self,527 _db: &'db dyn HirDatabase,528 expr: &ast::Expr,529 ) -> Option<(Type<'db>, Option<Type<'db>>)> {530 let expr_id = self.expr_id(expr.clone())?;531 let infer = self.infer()?;532 let coerced = expr_id533 .as_expr()534 .and_then(|expr_id| infer.expr_adjustment(expr_id))535 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.as_ref()));536 let ty = infer.expr_or_pat_ty(expr_id);537 let mk_ty = |ty: Ty<'db>| self.ty(ty);538 Some((mk_ty(ty), coerced.map(mk_ty)))539 }540541 pub(crate) fn type_of_pat(542 &self,543 _db: &'db dyn HirDatabase,544 pat: &ast::Pat,545 ) -> Option<(Type<'db>, Option<Type<'db>>)> {546 let expr_or_pat_id = self.pat_id(pat)?;547 let infer = self.infer()?;548 let coerced = match expr_or_pat_id {549 ExprOrPatId::ExprId(idx) => infer550 .expr_adjustment(idx)551 .and_then(|adjusts| adjusts.last())552 .map(|adjust| adjust.target.as_ref()),553 ExprOrPatId::PatId(idx) => infer554 .pat_adjustment(idx)555 .and_then(|adjusts| adjusts.last())556 .map(|adjust| adjust.source.as_ref()),557 };558559 let ty = infer.expr_or_pat_ty(expr_or_pat_id);560 let mk_ty = |ty: Ty<'db>| self.ty(ty);561 Some((mk_ty(ty), coerced.map(mk_ty)))562 }563564 pub(crate) fn type_of_binding_in_pat(565 &self,566 _db: &'db dyn HirDatabase,567 pat: &ast::IdentPat,568 ) -> Option<Type<'db>> {569 let binding_id = self.binding_id_of_pat(pat)?;570 let infer = self.infer()?;571 let ty = infer.binding_ty(binding_id);572 let mk_ty = |ty: Ty<'db>| self.ty(ty);573 Some(mk_ty(ty))574 }575576 pub(crate) fn type_of_self(577 &self,578 _db: &'db dyn HirDatabase,579 _param: &ast::SelfParam,580 ) -> Option<Type<'db>> {581 let binding = match self.body_or_sig.as_ref()? {582 BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None,583 BodyOrSig::Body { body, .. } => body.self_param()?,584 };585 let ty = self.infer()?.binding_ty(binding);586 Some(self.ty(ty))587 }588589 pub(crate) fn binding_mode_of_pat(590 &self,591 _db: &'db dyn HirDatabase,592 pat: &ast::IdentPat,593 ) -> Option<BindingMode> {594 let id = self.pat_id(&pat.clone().into())?;595 let infer = self.infer()?;596 Some(match infer.binding_mode(id.as_pat()?)? {597 hir_ty::BindingMode(hir_ty::ByRef::No, _) => BindingMode::Move,598 hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Mut), _) => {599 BindingMode::Ref(Mutability::Mut)600 }601 hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Not), _) => {602 BindingMode::Ref(Mutability::Shared)603 }604 })605 }606 pub(crate) fn pattern_adjustments(607 &self,608 _db: &'db dyn HirDatabase,609 pat: &ast::Pat,610 ) -> Option<SmallVec<[Type<'db>; 1]>> {611 let pat_id = self.pat_id(pat)?;612 let infer = self.infer()?;613 Some(614 infer615 .pat_adjustment(pat_id.as_pat()?)?616 .iter()617 .map(|adjust| self.ty(adjust.source.as_ref()))618 .collect(),619 )620 }621622 pub(crate) fn resolve_method_call_as_callable(623 &self,624 db: &'db dyn HirDatabase,625 call: &ast::MethodCallExpr,626 ) -> Option<Callable<'db>> {627 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;628 let (func, args) = self.infer()?.method_resolution(expr_id)?;629 let interner = DbInterner::new_no_crate(db);630 let ty = db.value_ty(func.into())?.instantiate(interner, args).skip_norm_wip();631 let ty = self.ty(ty);632 let mut res = ty.as_callable(db)?;633 res.is_bound_method = true;634 Some(res)635 }636637 pub(crate) fn resolve_method_call(638 &self,639 db: &'db dyn HirDatabase,640 call: &ast::MethodCallExpr,641 ) -> Option<Function> {642 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;643 let (f_in_trait, substs) = self.infer()?.method_resolution(expr_id)?;644645 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))646 }647648 pub(crate) fn resolve_method_call_fallback(649 &self,650 db: &'db dyn HirDatabase,651 call: &ast::MethodCallExpr,652 ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {653 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;654 let inference_result = self.infer()?;655 match inference_result.method_resolution(expr_id) {656 Some((f_in_trait, substs)) => {657 let (fn_, subst) =658 self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs);659 Some((660 Either::Left(fn_),661 GenericSubstitution::new_from_fn(fn_, subst, self.type_owner),662 ))663 }664 None => {665 inference_result.field_resolution(expr_id).and_then(Either::left).map(|field| {666 (Either::Right(field.into()), self.field_subst(expr_id, inference_result, db))667 })668 }669 }670 }671672 pub(crate) fn resolve_expr_as_callable(673 &self,674 db: &'db dyn HirDatabase,675 call: &ast::Expr,676 ) -> Option<Callable<'db>> {677 let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;678 adjusted.unwrap_or(orig).as_callable(db)679 }680681 pub(crate) fn resolve_field(682 &self,683 field: &ast::FieldExpr,684 ) -> Option<Either<Field, TupleField>> {685 let def = self.infer_body?;686 let expr_id = self.expr_id(field.clone().into())?.as_expr()?;687 self.infer()?.field_resolution(expr_id).map(|it| {688 it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })689 })690 }691692 fn field_subst(693 &self,694 field_expr: ExprId,695 infer: &InferenceResult,696 _db: &'db dyn HirDatabase,697 ) -> Option<GenericSubstitution<'db>> {698 let body = self.store()?;699 if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {700 let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?;701 return Some(GenericSubstitution::new(adt.into(), subst, self.type_owner));702 }703 None704 }705706 pub(crate) fn resolve_field_fallback(707 &self,708 db: &'db dyn HirDatabase,709 field: &ast::FieldExpr,710 ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>711 {712 let def = self.infer_body?;713 let expr_id = self.expr_id(field.clone().into())?.as_expr()?;714 let inference_result = self.infer()?;715 match inference_result.field_resolution(expr_id) {716 Some(field) => match field {717 Either::Left(field) => Some((718 Either::Left(Either::Left(field.into())),719 self.field_subst(expr_id, inference_result, db),720 )),721 Either::Right(field) => Some((722 Either::Left(Either::Right(TupleField {723 owner: def,724 tuple: field.tuple,725 index: field.index,726 })),727 None,728 )),729 },730 None => inference_result.method_resolution(expr_id).map(|(f, substs)| {731 let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs);732 (Either::Right(f), GenericSubstitution::new_from_fn(f, subst, self.type_owner))733 }),734 }735 }736737 pub(crate) fn resolve_range_pat(738 &self,739 db: &'db dyn HirDatabase,740 range_pat: &ast::RangePat,741 ) -> Option<StructId> {742 self.resolve_range_struct(743 db,744 range_pat.op_kind()?,745 range_pat.start().is_some(),746 range_pat.end().is_some(),747 )748 }749750 pub(crate) fn resolve_range_expr(751 &self,752 db: &'db dyn HirDatabase,753 range_expr: &ast::RangeExpr,754 ) -> Option<StructId> {755 self.resolve_range_struct(756 db,757 range_expr.op_kind()?,758 range_expr.start().is_some(),759 range_expr.end().is_some(),760 )761 }762763 fn resolve_range_struct(764 &self,765 db: &'db dyn HirDatabase,766 op_kind: RangeOp,767 has_start: bool,768 has_end: bool,769 ) -> Option<StructId> {770 let has_new_range = self.resolver.top_level_def_map().features().new_range;771 let lang_items = self.lang_items(db);772 match (op_kind, has_start, has_end) {773 (RangeOp::Exclusive, false, false) => lang_items.RangeFull,774 (RangeOp::Exclusive, false, true) => lang_items.RangeTo,775 (RangeOp::Exclusive, true, false) => {776 if has_new_range {777 lang_items.RangeFromCopy778 } else {779 lang_items.RangeFrom780 }781 }782 (RangeOp::Exclusive, true, true) => {783 if has_new_range {784 lang_items.RangeCopy785 } else {786 lang_items.Range787 }788 }789 (RangeOp::Inclusive, false, true) => {790 if has_new_range {791 lang_items.RangeToInclusiveCopy792 } else {793 lang_items.RangeToInclusive794 }795 }796 (RangeOp::Inclusive, true, true) => {797 if has_new_range {798 lang_items.RangeInclusiveCopy799 } else {800 lang_items.RangeInclusiveStruct801 }802 }803 // [E0586] inclusive ranges must be bounded at the end804 (RangeOp::Inclusive, false, false) => None,805 (RangeOp::Inclusive, true, false) => None,806 }807 }808809 pub(crate) fn resolve_await_to_poll(810 &self,811 db: &'db dyn HirDatabase,812 await_expr: &ast::AwaitExpr,813 ) -> Option<Function> {814 let mut ty = self.ty_of_expr(await_expr.expr()?)?;815816 let into_future_trait = self817 .resolver818 .resolve_known_trait(db, &path![core::future::IntoFuture])819 .map(Trait::from);820821 if let Some(into_future_trait) = into_future_trait {822 let type_ = self.ty(ty);823 if type_.impls_trait(db, into_future_trait, &[]) {824 let items = into_future_trait.items(db);825 let into_future_type = items.into_iter().find_map(|item| match item {826 AssocItem::TypeAlias(alias)827 if alias.name(db) == Name::new_symbol_root(sym::IntoFuture) =>828 {829 Some(alias)830 }831 _ => None,832 })?;833 let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;834 ty = future_trait.ty.skip_binder();835 }836 }837838 let poll_fn = self.lang_items(db).FuturePoll?;839 // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself840 // doesn't have any generic parameters, so we skip building another subst for `poll()`.841 let substs = GenericArgs::new_from_slice(&[ty.into()]);842 Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))843 }844845 pub(crate) fn resolve_prefix_expr(846 &self,847 db: &'db dyn HirDatabase,848 prefix_expr: &ast::PrefixExpr,849 ) -> Option<Function> {850 let lang_items = self.lang_items(db);851 let (_op_trait, op_fn) = match prefix_expr.op_kind()? {852 ast::UnaryOp::Deref => {853 // This can be either `Deref::deref` or `DerefMut::deref_mut`.854 // Since deref kind is inferenced and stored in `InferenceResult.method_resolution`,855 // use that result to find out which one it is.856 let (deref_trait, deref) = (lang_items.Deref?, lang_items.Deref_deref?);857 self.infer()858 .and_then(|infer| {859 let expr = self.expr_id(prefix_expr.clone().into())?.as_expr()?;860 let (func, _) = infer.method_resolution(expr)?;861 let (deref_mut_trait, deref_mut) =862 (lang_items.DerefMut?, lang_items.DerefMut_deref_mut?);863 if func == deref_mut { Some((deref_mut_trait, deref_mut)) } else { None }864 })865 .unwrap_or((deref_trait, deref))866 }867 ast::UnaryOp::Not => (lang_items.Not?, lang_items.Not_not?),868 ast::UnaryOp::Neg => (lang_items.Neg?, lang_items.Neg_neg?),869 };870871 let ty = self.ty_of_expr(prefix_expr.expr()?)?;872873 // HACK: subst for all methods coincides with that for their trait because the methods874 // don't have any generic parameters, so we skip building another subst for the methods.875 let substs = GenericArgs::new_from_slice(&[ty.into()]);876877 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))878 }879880 pub(crate) fn resolve_index_expr(881 &self,882 db: &'db dyn HirDatabase,883 index_expr: &ast::IndexExpr,884 ) -> Option<Function> {885 let base_ty = self.ty_of_expr(index_expr.base()?)?;886 let index_ty = self.ty_of_expr(index_expr.index()?)?;887 let lang_items = self.lang_items(db);888889 let (_index_trait, index_fn) = (lang_items.Index?, lang_items.Index_index?);890 let op_fn = self891 .infer()892 .and_then(|infer| {893 let expr = self.expr_id(index_expr.clone().into())?.as_expr()?;894 let (func, _) = infer.method_resolution(expr)?;895 let (_index_mut_trait, index_mut_fn) =896 (lang_items.IndexMut_index_mut?, lang_items.IndexMut_index_mut?);897 if func == index_mut_fn { Some(index_mut_fn) } else { None }898 })899 .unwrap_or(index_fn);900 // HACK: subst for all methods coincides with that for their trait because the methods901 // don't have any generic parameters, so we skip building another subst for the methods.902 let substs = GenericArgs::new_from_slice(&[base_ty.into(), index_ty.into()]);903 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))904 }905906 pub(crate) fn resolve_bin_expr(907 &self,908 db: &'db dyn HirDatabase,909 binop_expr: &ast::BinExpr,910 ) -> Option<Function> {911 let op = binop_expr.op_kind()?;912 let lhs = self.ty_of_expr(binop_expr.lhs()?)?;913 let rhs = self.ty_of_expr(binop_expr.rhs()?)?;914915 let (op_fn, _op_trait) = lang_items_for_bin_op(self.lang_items(db), op)916 .and_then(|(method, trait_)| method.zip(trait_))?;917 // HACK: subst for `index()` coincides with that for `Index` because `index()` itself918 // doesn't have any generic parameters, so we skip building another subst for `index()`.919 let substs = GenericArgs::new_from_slice(&[lhs.into(), rhs.into()]);920921 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))922 }923924 pub(crate) fn resolve_try_expr(925 &self,926 db: &'db dyn HirDatabase,927 try_expr: &ast::TryExpr,928 ) -> Option<Function> {929 let ty = self.ty_of_expr(try_expr.expr()?)?;930931 let op_fn = self.lang_items(db).TryTraitBranch?;932 // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself933 // doesn't have any generic parameters, so we skip building another subst for `branch()`.934 let substs = GenericArgs::new_from_slice(&[ty.into()]);935936 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))937 }938939 pub(crate) fn resolve_record_field(940 &self,941 db: &'db dyn HirDatabase,942 field: &ast::RecordExprField,943 ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {944 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;945 let expr = ast::Expr::from(record_expr);946 let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?;947 let interner = DbInterner::new_no_crate(db);948949 let ast_name = field.field_name()?;950 let local_name = ast_name.as_name();951 let local = if field.name_ref().is_some() {952 None953 } else {954 // Shorthand syntax, resolve to the local955 let path = Path::from_known_path_with_no_generic(ModPath::from_segments(956 PathKind::Plain,957 once(local_name.clone()),958 ));959 match self.resolver.resolve_path_in_value_ns_fully(960 db,961 &path,962 name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),963 ) {964 Some(ValueNs::LocalBinding(binding_id)) => Some(Local {965 binding_id,966 parent: self.owner()?,967 parent_infer: self.infer_body?,968 }),969 _ => None,970 }971 };972 let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?;973 let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;974 let variant_data = variant.fields(db);975 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };976 let field_ty = (*db.field_types(variant).get(field.local_id)?)977 .ty()978 .instantiate(interner, subst)979 .skip_norm_wip();980 Some((981 field.into(),982 local,983 self.ty(field_ty),984 GenericSubstitution::new(adt.into(), subst, self.type_owner),985 ))986 }987988 pub(crate) fn resolve_record_pat_field(989 &self,990 db: &'db dyn HirDatabase,991 field: &ast::RecordPatField,992 ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {993 let interner = DbInterner::new_no_crate(db);994 let field_name = field.field_name()?.as_name();995 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;996 let pat_id = self.pat_id(&record_pat.into())?;997 let variant = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?;998 let variant_data = variant.fields(db);999 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };1000 let (adt, subst) = self.infer()?.pat_ty(pat_id.as_pat()?).as_adt()?;1001 let field_ty = (*db.field_types(variant).get(field.local_id)?)1002 .ty()1003 .instantiate(interner, subst)1004 .skip_norm_wip();1005 Some((1006 field.into(),1007 self.ty(field_ty),1008 GenericSubstitution::new(adt.into(), subst, self.type_owner),1009 ))1010 }10111012 pub(crate) fn resolve_tuple_struct_pat_fields(1013 &self,1014 db: &'db dyn HirDatabase,1015 tuple_struct_pat: &ast::TupleStructPat,1016 ) -> Option<Vec<(Field, Type<'db>)>> {1017 let interner = DbInterner::new_no_crate(db);1018 let pat_id = self.pat_id(&tuple_struct_pat.clone().into())?;1019 let variant_id = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?;1020 let (_adt, substs) = self.infer()?.pat_ty(pat_id.as_pat()?).as_adt()?;10211022 Some(1023 db.field_types(variant_id)1024 .iter()1025 .map(|(local_id, field)| {1026 let def = Field { parent: variant_id.into(), id: local_id };1027 let ty = field.ty().instantiate(interner, substs).skip_norm_wip();1028 (def, self.ty(ty))1029 })1030 .collect(),1031 )1032 }10331034 pub(crate) fn resolve_bind_pat_to_const(1035 &self,1036 db: &'db dyn HirDatabase,1037 pat: &ast::IdentPat,1038 ) -> Option<ModuleDef> {1039 let expr_or_pat_id = self.pat_id(&pat.clone().into())?;1040 let store = self.store()?;10411042 let path = match expr_or_pat_id {1043 ExprOrPatId::ExprId(idx) => match &store[idx] {1044 Expr::Path(path) => path,1045 _ => return None,1046 },1047 ExprOrPatId::PatId(idx) => match &store[idx] {1048 Pat::Path(path) => path,1049 _ => return None,1050 },1051 };10521053 let store_owner = self.resolver.expression_store_owner();1054 let res = resolve_hir_value_path(1055 db,1056 &self.resolver,1057 store_owner,1058 self.infer_body,1059 path,1060 HygieneId::ROOT,1061 )?;1062 match res {1063 PathResolution::Def(def) => Some(def),1064 _ => None,1065 }1066 }10671068 pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<crate::TypeParam> {1069 let name = name.as_name();1070 self.resolver1071 .all_generic_params()1072 .find_map(|(params, parent)| params.find_type_by_name(&name, parent))1073 .map(crate::TypeParam::from)1074 }10751076 pub(crate) fn resolve_offset_of_field(1077 &self,1078 db: &'db dyn HirDatabase,1079 name_ref: &ast::NameRef,1080 ) -> Option<(Either<crate::EnumVariant, crate::Field>, GenericSubstitution<'db>)> {1081 let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;1082 let container = offset_of_expr.ty()?;1083 let container = self.type_of_type(db, &container)?;10841085 let env = self.trait_environment(db);10861087 let interner = DbInterner::new_with(db, env.krate);1088 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);10891090 let mut container = Either::Right(container.ty.skip_binder());1091 for field_name in offset_of_expr.fields() {1092 if let Either::Right(container) = &mut container {1093 *container = structurally_normalize_ty(&infcx, *container, env.param_env);1094 }1095 let handle_variants =1096 |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {1097 let fields = variant.fields(db);1098 let field = fields.field(&field_name.as_name())?;1099 let field_types = db.field_types(variant);1100 *container = Either::Right(1101 field_types[field].ty().instantiate(interner, subst).skip_norm_wip(),1102 );1103 let generic_def = match variant {1104 VariantId::EnumVariantId(it) => it.loc(db).parent.into(),1105 VariantId::StructId(it) => it.into(),1106 VariantId::UnionId(it) => it.into(),1107 };1108 Some((1109 Either::Right(Field { parent: variant.into(), id: field }),1110 generic_def,1111 subst,1112 ))1113 };1114 let temp_ty = Ty::new_error(interner, ErrorGuaranteed);1115 let (field_def, generic_def, subst) =1116 match std::mem::replace(&mut container, Either::Right(temp_ty)) {1117 Either::Left((variant_id, subst)) => {1118 handle_variants(VariantId::from(variant_id), subst, &mut container)?1119 }1120 Either::Right(container_ty) => match container_ty.kind() {1121 TyKind::Adt(adt_def, subst) => match adt_def.def_id() {1122 AdtId::StructId(id) => {1123 handle_variants(id.into(), subst, &mut container)?1124 }1125 AdtId::UnionId(id) => {1126 handle_variants(id.into(), subst, &mut container)?1127 }1128 AdtId::EnumId(id) => {1129 let variants = id.enum_variants(db);1130 let variant = variants.variant(&field_name.as_name())?;1131 container = Either::Left((variant, subst));1132 (Either::Left(EnumVariant { id: variant }), id.into(), subst)1133 }1134 },1135 _ => return None,1136 },1137 };11381139 if field_name.syntax().text_range() == name_ref.syntax().text_range() {1140 return Some((1141 field_def,1142 GenericSubstitution::new(generic_def, subst, self.type_owner),1143 ));1144 }1145 }1146 never!("the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it");1147 None1148 }11491150 pub(crate) fn resolve_path(1151 &self,1152 db: &'db dyn HirDatabase,1153 path: &ast::Path,1154 ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {1155 let parent = path.syntax().parent();1156 let parent = || parent.clone();11571158 let mut prefer_value_ns = false;1159 let resolved = (|| {1160 let infer = self.infer()?;1161 if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {1162 let expr_id = self.expr_id(path_expr.into())?;1163 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {1164 let (assoc, subst) = match assoc {1165 CandidateId::FunctionId(f_in_trait) => {1166 match infer.type_of_expr_or_pat(expr_id) {1167 None => {1168 let subst = GenericSubstitution::new(1169 f_in_trait.into(),1170 subs,1171 self.type_owner,1172 );1173 (AssocItem::Function(f_in_trait.into()), Some(subst))1174 }1175 Some(func_ty) => {1176 if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() {1177 let (fn_, subst) = self1178 .resolve_impl_method_or_trait_def_with_subst(1179 db, f_in_trait, subs,1180 );1181 let subst = GenericSubstitution::new_from_fn(1182 fn_,1183 subst,1184 self.type_owner,1185 );1186 (AssocItem::Function(fn_), subst)1187 } else {1188 let subst = GenericSubstitution::new(1189 f_in_trait.into(),1190 subs,1191 self.type_owner,1192 );1193 (AssocItem::Function(f_in_trait.into()), Some(subst))1194 }1195 }1196 }1197 }1198 CandidateId::ConstId(const_id) => {1199 let (konst, subst) =1200 self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);1201 let subst =1202 GenericSubstitution::new(konst.into(), subst, self.type_owner);1203 (AssocItem::Const(konst.into()), Some(subst))1204 }1205 };12061207 return Some((PathResolution::Def(assoc.into()), subst));1208 }1209 if let Some(VariantId::EnumVariantId(variant)) =1210 infer.variant_resolution_for_expr_or_pat(expr_id)1211 {1212 return Some((1213 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),1214 None,1215 ));1216 }1217 prefer_value_ns = true;1218 } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {1219 let expr_or_pat_id = self.pat_id(&path_pat.into())?;1220 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_or_pat_id)1221 {1222 let (assoc, subst) = match assoc {1223 CandidateId::ConstId(const_id) => {1224 let (konst, subst) =1225 self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);1226 let subst =1227 GenericSubstitution::new(konst.into(), subst, self.type_owner);1228 (AssocItemId::from(konst), subst)1229 }1230 CandidateId::FunctionId(function_id) => (1231 function_id.into(),1232 GenericSubstitution::new(function_id.into(), subs, self.type_owner),1233 ),1234 };1235 return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));1236 }1237 if let Some(VariantId::EnumVariantId(variant)) =1238 infer.variant_resolution_for_expr_or_pat(expr_or_pat_id)1239 {1240 return Some((1241 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),1242 None,1243 ));1244 }1245 } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {1246 let expr_id = self.expr_id(rec_lit.into())?;1247 if let Some(VariantId::EnumVariantId(variant)) =1248 infer.variant_resolution_for_expr_or_pat(expr_id)1249 {1250 return Some((1251 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),1252 None,1253 ));1254 }1255 } else {1256 let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);1257 let tuple_struct_pat =1258 || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);1259 if let Some(pat) = record_pat.or_else(tuple_struct_pat) {1260 let pat_id = self.pat_id(&pat)?;1261 let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?);1262 if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {1263 return Some((1264 PathResolution::Def(ModuleDef::EnumVariant(variant.into())),1265 None,1266 ));1267 }1268 }1269 }1270 None1271 })();1272 if resolved.is_some() {1273 return resolved;1274 }12751276 // FIXME: collectiong here shouldnt be necessary?1277 let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);1278 let hir_path =1279 collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;1280 let parent_hir_path = path1281 .parent_path()1282 .and_then(|p| collector.lower_path(p, &mut ExprCollector::impl_trait_error_allocator));1283 let (store, _) = collector.store.finish();12841285 // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are1286 // trying to resolve foo::bar.1287 if let Some(use_tree) = parent().and_then(ast::UseTree::cast)1288 && use_tree.coloncolon_token().is_some()1289 {1290 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store)1291 .map(|it| (it, None));1292 }12931294 let meta_path = path1295 .syntax()1296 .ancestors()1297 .take_while(|it| {1298 let kind = it.kind();1299 ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)1300 })1301 .last()1302 .and_then(ast::Meta::cast);13031304 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are1305 // trying to resolve foo::bar.1306 if let Some(parent_hir_path) = parent_hir_path {1307 return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store) {1308 None if meta_path.is_some() => path1309 .first_segment()1310 .and_then(|it| it.name_ref())1311 .and_then(|name_ref| {1312 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())1313 .map(PathResolution::ToolModule)1314 })1315 .map(|it| (it, None)),1316 // Case the type name conflict with use module,1317 // e.g.1318 // ```1319 // use std::str;1320 // fn main() {1321 // str::from_utf8(); // as module std::str1322 // str::len(); // as primitive type str1323 // str::no_exist_item(); // as primitive type str1324 // }1325 // ```1326 Some(it) if matches!(it, PathResolution::Def(ModuleDef::BuiltinType(_))) => {1327 if let Some(mod_path) = hir_path.mod_path()1328 && let Some(ModuleDefId::ModuleId(id)) =1329 self.resolver.resolve_module_path_in_items(db, mod_path).take_types()1330 {1331 let parent_hir_name = parent_hir_path.segments().get(1).map(|it| it.name);1332 let module = crate::Module { id };1333 if module1334 .scope(db, None)1335 .into_iter()1336 .any(|(name, _)| Some(&name) == parent_hir_name)1337 {1338 return Some((PathResolution::Def(ModuleDef::Module(module)), None));1339 };1340 }1341 Some((it, None))1342 }1343 // FIXME: We do not show substitutions for parts of path, because this is really complex1344 // due to the interactions with associated items of `impl`s and associated items of associated1345 // types.1346 res => res.map(|it| (it, None)),1347 };1348 } else if let Some(meta_path) = meta_path {1349 // Case where we are resolving the final path segment of a path in an attribute1350 // in this case we have to check for inert/builtin attributes and tools and prioritize1351 // resolution of attributes over other namespaces1352 if let Some(name_ref) = path.as_single_name_ref() {1353 let builtin = BuiltinAttr::builtin(&name_ref.text());1354 if builtin.is_some() {1355 return builtin.map(|it| (PathResolution::BuiltinAttr(it), None));1356 }13571358 if let Some(attr) = meta_path.parent_attr() {1359 let adt =1360 attr.syntax().ancestors().find_map(ast::Item::cast).and_then(1361 |it| match it {1362 ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),1363 ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),1364 ast::Item::Union(it) => Some(ast::Adt::Union(it)),1365 _ => None,1366 },1367 );1368 if let Some(adt) = adt {1369 let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);1370 if let Some(helpers) = self1371 .resolver1372 .def_map()1373 .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))1374 {1375 // FIXME: Multiple derives can have the same helper1376 let name_ref = name_ref.as_name();1377 for (macro_id, mut helpers) in1378 helpers.iter().chunk_by(|(_, macro_id, ..)| macro_id).into_iter()1379 {1380 if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)1381 {1382 return Some((1383 PathResolution::DeriveHelper(DeriveHelper {1384 derive: *macro_id,1385 idx: idx as u32,1386 }),1387 None,1388 ));1389 }1390 }1391 }1392 }1393 }1394 }1395 return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {1396 Some(m) => Some((PathResolution::Def(ModuleDef::Macro(m)), None)),1397 // this labels any path that starts with a tool module as the tool itself, this is technically wrong1398 // but there is no benefit in differentiating these two cases for the time being1399 None => path1400 .first_segment()1401 .and_then(|it| it.name_ref())1402 .and_then(|name_ref| {1403 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())1404 .map(PathResolution::ToolModule)1405 })1406 .map(|it| (it, None)),1407 };1408 }1409 if parent().is_some_and(|it| ast::Visibility::can_cast(it.kind())) {1410 // No substitution because only modules can be inside visibilities, and those have no generics.1411 resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store).map(|it| (it, None))1412 } else {1413 // Probably a type, no need to show substitutions for those.1414 let res = resolve_hir_path_(1415 db,1416 &self.resolver,1417 self.infer_body,1418 &hir_path,1419 prefer_value_ns,1420 name_hygiene(db, InFile::new(self.file_id, path.syntax())),1421 Some(&store),1422 false,1423 )1424 .any()?;1425 let subst = (|| {1426 let parent = parent()?;1427 let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {1428 let expr_id = self.expr_id(expr)?;1429 self.infer()?.type_of_expr_or_pat(expr_id)?1430 } else if let Some(pat) = ast::Pat::cast(parent) {1431 let pat_id = self.pat_id(&pat)?;1432 self.infer()?.expr_or_pat_ty(pat_id)1433 } else {1434 return None;1435 };1436 let (subst, expected_resolution) = match ty.kind() {1437 TyKind::Adt(adt_def, subst) => {1438 let adt_id = adt_def.def_id();1439 (1440 GenericSubstitution::new(adt_id.into(), subst, self.type_owner),1441 PathResolution::Def(ModuleDef::Adt(adt_id.into())),1442 )1443 }1444 TyKind::Alias(AliasTy {1445 kind: AliasTyKind::Projection { def_id },1446 args,1447 ..1448 }) => {1449 let assoc_id = def_id.0;1450 (1451 GenericSubstitution::new(assoc_id.into(), args, self.type_owner),1452 PathResolution::Def(ModuleDef::TypeAlias(assoc_id.into())),1453 )1454 }1455 TyKind::FnDef(fn_id, subst) => {1456 let generic_def_id = match fn_id.0 {1457 CallableDefId::StructId(id) => id.into(),1458 CallableDefId::FunctionId(id) => id.into(),1459 CallableDefId::EnumVariantId(_) => return None,1460 };1461 (1462 GenericSubstitution::new(generic_def_id, subst, self.type_owner),1463 PathResolution::Def(ModuleDefId::from(fn_id.0).into()),1464 )1465 }1466 _ => return None,1467 };1468 if res != expected_resolution {1469 // The user will not understand where we're coming from. This can happen (I think) with type aliases.1470 return None;1471 }1472 Some(subst)1473 })();1474 Some((res, subst))1475 }1476 }14771478 pub(crate) fn resolve_hir_path_per_ns(1479 &self,1480 db: &dyn HirDatabase,1481 path: &ast::Path,1482 ) -> Option<PathResolutionPerNs> {1483 let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);1484 let hir_path =1485 collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;1486 let (store, _) = collector.store.finish();1487 Some(resolve_hir_path_(1488 db,1489 &self.resolver,1490 self.infer_body,1491 &hir_path,1492 false,1493 name_hygiene(db, InFile::new(self.file_id, path.syntax())),1494 Some(&store),1495 true,1496 ))1497 }14981499 pub(crate) fn record_literal_missing_fields(1500 &self,1501 db: &'db dyn HirDatabase,1502 literal: &ast::RecordExpr,1503 ) -> Option<Vec<(Field, Type<'db>)>> {1504 let body = self.store()?;1505 let infer = self.infer()?;15061507 let expr_id = self.expr_id(literal.clone().into())?.as_expr()?;1508 let substs = infer.expr_ty(expr_id).as_adt()?.1;1509 let (variant, missing_fields) =1510 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;1511 let res = self.missing_fields(db, substs, variant, missing_fields);1512 Some(res)1513 }15141515 pub(crate) fn record_literal_matched_fields(1516 &self,1517 db: &'db dyn HirDatabase,1518 literal: &ast::RecordExpr,1519 ) -> Option<Vec<(Field, Type<'db>)>> {1520 let body = self.store()?;1521 let infer = self.infer()?;15221523 let expr_id = self.expr_id(literal.clone().into())?.as_expr()?;1524 let substs = infer.expr_ty(expr_id).as_adt()?.1;1525 let (variant, matched_fields) =1526 record_literal_matched_fields(db, infer, expr_id, &body[expr_id])?;15271528 let res = self.missing_fields(db, substs, variant, matched_fields);1529 Some(res)1530 }15311532 pub(crate) fn record_pattern_missing_fields(1533 &self,1534 db: &'db dyn HirDatabase,1535 pattern: &ast::RecordPat,1536 ) -> Option<Vec<(Field, Type<'db>)>> {1537 let body = self.store()?;1538 let infer = self.infer()?;15391540 let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;1541 let substs = infer.pat_ty(pat_id).as_adt()?.1;15421543 let (variant, missing_fields) =1544 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;1545 let res = self.missing_fields(db, substs, variant, missing_fields);1546 Some(res)1547 }15481549 pub(crate) fn record_pattern_matched_fields(1550 &self,1551 db: &'db dyn HirDatabase,1552 pattern: &ast::RecordPat,1553 ) -> Option<Vec<(Field, Type<'db>)>> {1554 let body = self.store()?;1555 let infer = self.infer()?;15561557 let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;1558 let substs = infer.pat_ty(pat_id).as_adt()?.1;15591560 let (variant, matched_fields) =1561 record_pattern_matched_fields(db, infer, pat_id, &body[pat_id])?;1562 let res = self.missing_fields(db, substs, variant, matched_fields);1563 Some(res)1564 }15651566 fn missing_fields(1567 &self,1568 db: &'db dyn HirDatabase,1569 substs: GenericArgs<'db>,1570 variant: VariantId,1571 missing_fields: Vec<LocalFieldId>,1572 ) -> Vec<(Field, Type<'db>)> {1573 let interner = DbInterner::new_no_crate(db);1574 let field_types = db.field_types(variant);15751576 missing_fields1577 .into_iter()1578 .map(|local_id| {1579 let field = FieldId { parent: variant, local_id };1580 let ty = field_types[local_id].ty().instantiate(interner, substs).skip_norm_wip();1581 (field.into(), self.ty(ty))1582 })1583 .collect()1584 }15851586 pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {1587 let infer = self.infer()?;1588 let expr_id = self.expr_id(record_lit.into())?;1589 infer.variant_resolution_for_expr_or_pat(expr_id)1590 }15911592 pub(crate) fn is_unsafe_macro_call_expr(1593 &self,1594 db: &'db dyn HirDatabase,1595 macro_expr: InFile<&ast::MacroExpr>,1596 ) -> bool {1597 if let Some((def, body, sm, Some(infer))) = self.def()1598 && let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr)1599 {1600 let mut is_unsafe = false;1601 let mut walk_expr = |expr_id| {1602 unsafe_operations(db, infer, def, body, expr_id, &mut |_, inside_unsafe_block| {1603 is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No1604 })1605 };1606 match expanded_expr {1607 ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),1608 ExprOrPatId::PatId(expanded_pat) => body.walk_exprs_in_pat(expanded_pat, walk_expr),1609 }1610 return is_unsafe;1611 }1612 false1613 }16141615 /// Returns the range of the implicit template argument and its resolution at the given `offset`1616 pub(crate) fn resolve_offset_in_format_args(1617 &self,1618 db: &'db dyn HirDatabase,1619 format_args: InFile<&ast::FormatArgsExpr>,1620 offset: TextSize,1621 ) -> Option<(TextRange, Option<PathResolution>)> {1622 let (hygiene, implicits) = self.store_sm()?.implicit_format_args(format_args)?;1623 implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| {1624 (1625 *range,1626 resolve_hir_value_path(1627 db,1628 &self.resolver,1629 self.resolver.expression_store_owner(),1630 self.infer_body,1631 &Path::from_known_path_with_no_generic(ModPath::from_segments(1632 PathKind::Plain,1633 Some(name.clone()),1634 )),1635 hygiene,1636 ),1637 )1638 })1639 }16401641 pub(crate) fn resolve_offset_in_asm_template(1642 &self,1643 asm: InFile<&ast::AsmExpr>,1644 line: usize,1645 offset: TextSize,1646 ) -> Option<(ExpressionStoreOwnerId, (ExprId, TextRange, usize))> {1647 let (def, _, sm, _) = self.def()?;1648 let (expr, args) = sm.asm_template_args(asm)?;1649 Some(def).zip(1650 args.get(line)?1651 .iter()1652 .find(|(range, _)| range.contains_inclusive(offset))1653 .map(|(range, idx)| (expr, *range, *idx)),1654 )1655 }16561657 pub(crate) fn as_format_args_parts<'a>(1658 &'a self,1659 db: &'a dyn HirDatabase,1660 format_args: InFile<&ast::FormatArgsExpr>,1661 ) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {1662 let (hygiene, names) = self.store_sm()?.implicit_format_args(format_args)?;1663 Some(names.iter().map(move |(range, name)| {1664 (1665 *range,1666 resolve_hir_value_path(1667 db,1668 &self.resolver,1669 self.resolver.expression_store_owner(),1670 self.infer_body,1671 &Path::from_known_path_with_no_generic(ModPath::from_segments(1672 PathKind::Plain,1673 Some(name.clone()),1674 )),1675 hygiene,1676 ),1677 )1678 }))1679 }16801681 pub(crate) fn as_asm_parts(1682 &self,1683 asm: InFile<&ast::AsmExpr>,1684 ) -> Option<(ExpressionStoreOwnerId, (ExprId, &[Vec<(TextRange, usize)>]))> {1685 let (def, _, sm, _) = self.def()?;1686 Some(def).zip(sm.asm_template_args(asm))1687 }16881689 fn resolve_impl_method_or_trait_def(1690 &self,1691 db: &'db dyn HirDatabase,1692 func: FunctionId,1693 substs: GenericArgs<'db>,1694 ) -> Function {1695 self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).01696 }16971698 fn resolve_impl_method_or_trait_def_with_subst(1699 &self,1700 db: &'db dyn HirDatabase,1701 func: FunctionId,1702 substs: GenericArgs<'db>,1703 ) -> (Function, GenericArgs<'db>) {1704 let owner = match self.resolver.generic_def() {1705 Some(it) => it,1706 None => return (func.into(), substs),1707 };1708 let env = self.param_and(db.trait_environment(owner));1709 let (func, args) = db.lookup_impl_method(env, func, substs);1710 match func {1711 Either::Left(func) => (func.into(), args),1712 Either::Right((impl_, method)) => {1713 (Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }, args)1714 }1715 }1716 }17171718 fn resolve_impl_const_or_trait_def_with_subst(1719 &self,1720 db: &'db dyn HirDatabase,1721 const_id: ConstId,1722 subs: GenericArgs<'db>,1723 ) -> (ConstId, GenericArgs<'db>) {1724 let owner = match self.resolver.generic_def() {1725 Some(it) => it,1726 None => return (const_id, subs),1727 };1728 let env = self.param_and(db.trait_environment(owner));1729 let interner = DbInterner::new_with(db, env.krate);1730 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);1731 method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs)1732 }17331734 fn lang_items<'a>(&self, db: &'a dyn HirDatabase) -> &'a LangItems {1735 hir_def::lang_item::lang_items(db, self.resolver.krate())1736 }17371738 fn ty_of_expr(&self, expr: ast::Expr) -> Option<Ty<'db>> {1739 self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?)1740 }1741}17421743// Note: the `ExprId` here does not need to be accurate, what's important is that it points at the same1744// inference root.1745fn scope_for(1746 db: &dyn HirDatabase,1747 scopes: &ExprScopes,1748 source_map: &ExpressionStoreSourceMap,1749 node: InFile<&SyntaxNode>,1750) -> Option<(ScopeId, ExprId)> {1751 node.ancestors_with_macros(db)1752 .take_while(|it| {1753 let kind = it.kind();1754 !ast::Item::can_cast(kind)1755 || ast::MacroCall::can_cast(kind)1756 || ast::Use::can_cast(kind)1757 || ast::AsmExpr::can_cast(kind)1758 })1759 .filter_map(|it| it.map(ast::Expr::cast).transpose())1760 .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())1761 .find_map(|expr| scopes.scope_for(expr).map(|scope| (scope, expr)))1762}17631764fn scope_for_offset(1765 db: &dyn HirDatabase,1766 scopes: &ExprScopes,1767 source_map: &ExpressionStoreSourceMap,1768 from_file: HirFileId,1769 offset: TextSize,1770) -> Option<(ScopeId, ExprId)> {1771 scopes1772 .scope_by_expr()1773 .iter()1774 .filter_map(|(id, scope)| {1775 let InFile { file_id, value } = source_map.expr_syntax(id).ok()?;1776 if from_file == file_id {1777 return Some((value.text_range(), scope, id));1778 }17791780 // FIXME handle attribute expansion1781 let source = iter::successors(file_id.macro_file().map(|it| it.call_node(db)), |it| {1782 Some(it.file_id.macro_file()?.call_node(db))1783 })1784 .find(|it| it.file_id == from_file)1785 .filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;1786 Some((source.text_range(), scope, id))1787 })1788 .filter(|(expr_range, _scope, _expr)| {1789 expr_range.start() <= offset && offset <= expr_range.end()1790 })1791 // find containing scope1792 .min_by_key(|(expr_range, _scope, _expr)| expr_range.len())1793 .map(|(expr_range, scope, expr)| {1794 adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or((*scope, expr))1795 })1796}17971798// XXX: during completion, cursor might be outside of any particular1799// expression. Try to figure out the correct scope...1800fn adjust(1801 db: &dyn HirDatabase,1802 scopes: &ExprScopes,1803 source_map: &ExpressionStoreSourceMap,1804 expr_range: TextRange,1805 from_file: HirFileId,1806 offset: TextSize,1807) -> Option<(ScopeId, ExprId)> {1808 let child_scopes = scopes1809 .scope_by_expr()1810 .iter()1811 .filter_map(|(id, scope)| {1812 let source = source_map.expr_syntax(id).ok()?;1813 // FIXME: correctly handle macro expansion1814 if source.file_id != from_file {1815 return None;1816 }1817 let root = source.file_syntax(db);1818 let node = source.value.to_node(&root);1819 Some((node.syntax().text_range(), scope, id))1820 })1821 .filter(|&(range, _, _)| {1822 range.start() <= offset && expr_range.contains_range(range) && range != expr_range1823 });18241825 child_scopes1826 .max_by(|&(r1, _, _), &(r2, _, _)| {1827 if r1.contains_range(r2) {1828 std::cmp::Ordering::Greater1829 } else if r2.contains_range(r1) {1830 std::cmp::Ordering::Less1831 } else {1832 r1.start().cmp(&r2.start())1833 }1834 })1835 .map(|(_ptr, scope, expr)| (*scope, expr))1836}18371838#[inline]1839pub(crate) fn resolve_hir_path(1840 db: &dyn HirDatabase,1841 resolver: &Resolver<'_>,1842 infer_body: Option<InferBodyId>,1843 path: &Path,1844 hygiene: HygieneId,1845 store: Option<&ExpressionStore>,1846) -> Option<PathResolution> {1847 resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any()1848}18491850#[inline]1851pub(crate) fn resolve_hir_path_as_attr_macro(1852 db: &dyn HirDatabase,1853 resolver: &Resolver<'_>,1854 path: &Path,1855) -> Option<Macro> {1856 resolver1857 .resolve_path_as_macro(db, path.mod_path()?, Some(MacroSubNs::Attr))1858 .map(|(it, _)| it)1859 .map(Into::into)1860}18611862fn resolve_hir_path_(1863 db: &dyn HirDatabase,1864 resolver: &Resolver<'_>,1865 infer_body: Option<InferBodyId>,1866 path: &Path,1867 prefer_value_ns: bool,1868 hygiene: HygieneId,1869 store: Option<&ExpressionStore>,1870 resolve_per_ns: bool,1871) -> PathResolutionPerNs {1872 let types = || {1873 let (ty, unresolved) = match path.type_anchor() {1874 Some(type_ref) => resolver.generic_def().and_then(|def| {1875 let generics = OnceCell::new();1876 let (_, res) = TyLoweringContext::new(1877 db,1878 resolver,1879 store?,1880 def.into(),1881 def,1882 &generics,1883 LifetimeElisionKind::Infer,1884 )1885 .lower_ty_ext(type_ref);1886 res.map(|ty_ns| (ty_ns, path.segments().first()))1887 }),1888 None => {1889 let (ty, remaining_idx, _) = resolver.resolve_path_in_type_ns(db, path)?;1890 match remaining_idx {1891 Some(remaining_idx) => {1892 if remaining_idx + 1 == path.segments().len() {1893 Some((ty, path.segments().last()))1894 } else {1895 None1896 }1897 }1898 None => Some((ty, None)),1899 }1900 }1901 }?;19021903 // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type1904 // within the trait's associated types.1905 if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty)1906 && let Some(type_alias_id) =1907 trait_id.trait_items(db).associated_type_by_name(unresolved.name)1908 {1909 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));1910 }19111912 let res = match ty {1913 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),1914 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),1915 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {1916 PathResolution::Def(Adt::from(it).into())1917 }1918 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),1919 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),1920 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),1921 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),1922 TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())),1923 };1924 match unresolved {1925 Some(unresolved) => resolver1926 .generic_def()1927 .and_then(|def| {1928 hir_ty::associated_type_shorthand_candidates(1929 db,1930 def,1931 res.in_type_ns()?,1932 |name, _| name == unresolved.name,1933 )1934 })1935 .map(TypeAlias::from)1936 .map(Into::into)1937 .map(PathResolution::Def),1938 None => Some(res),1939 }1940 };19411942 let body_owner = resolver.expression_store_owner();1943 let values = || resolve_hir_value_path(db, resolver, body_owner, infer_body, path, hygiene);19441945 let items = || {1946 resolver1947 .resolve_module_path_in_items(db, path.mod_path()?)1948 .take_types()1949 .map(|it| PathResolution::Def(it.into()))1950 };19511952 let macros = || {1953 resolver1954 .resolve_path_as_macro(db, path.mod_path()?, None)1955 .map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into())))1956 };19571958 if resolve_per_ns {1959 PathResolutionPerNs {1960 type_ns: types().or_else(items),1961 value_ns: values(),1962 macro_ns: macros(),1963 }1964 } else {1965 let res = if prefer_value_ns {1966 values()1967 .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None))1968 .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None))1969 } else {1970 types()1971 .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None))1972 .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None))1973 };19741975 if res.any().is_some() {1976 res1977 } else if let Some(type_ns) = items() {1978 PathResolutionPerNs::new(Some(type_ns), None, None)1979 } else {1980 PathResolutionPerNs::new(None, None, macros())1981 }1982 }1983}19841985fn resolve_hir_value_path(1986 db: &dyn HirDatabase,1987 resolver: &Resolver<'_>,1988 store_owner: Option<ExpressionStoreOwnerId>,1989 infer_body: Option<InferBodyId>,1990 path: &Path,1991 hygiene: HygieneId,1992) -> Option<PathResolution> {1993 resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| {1994 let res = match val {1995 ValueNs::LocalBinding(binding_id) => {1996 let var = Local { parent: store_owner?, parent_infer: infer_body?, binding_id };1997 PathResolution::Local(var)1998 }1999 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),2000 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
Findings
✓ No findings reported for this file.