| //! See `Semantics`. | 
 |  | 
 | mod child_by_source; | 
 | mod source_to_def; | 
 |  | 
 | use std::{ | 
 |     cell::RefCell, | 
 |     convert::Infallible, | 
 |     fmt, iter, mem, | 
 |     ops::{self, ControlFlow, Not}, | 
 | }; | 
 |  | 
 | use either::Either; | 
 | use hir_def::{ | 
 |     DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId, | 
 |     expr_store::{Body, ExprOrPatSource, path::Path}, | 
 |     hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, | 
 |     nameres::ModuleOrigin, | 
 |     resolver::{self, HasResolver, Resolver, TypeNs}, | 
 |     type_ref::Mutability, | 
 | }; | 
 | use hir_expand::{ | 
 |     EditionedFileId, ExpandResult, FileRange, HirFileId, InMacroFile, MacroCallId, | 
 |     attrs::collect_attrs, | 
 |     builtin::{BuiltinFnLikeExpander, EagerExpander}, | 
 |     db::ExpandDatabase, | 
 |     files::{FileRangeWrapper, InRealFile}, | 
 |     hygiene::SyntaxContextExt as _, | 
 |     inert_attr_macro::find_builtin_attr_idx, | 
 |     mod_path::{ModPath, PathKind}, | 
 |     name::AsName, | 
 | }; | 
 | use hir_ty::diagnostics::unsafe_operations_for_body; | 
 | use intern::{Interned, Symbol, sym}; | 
 | use itertools::Itertools; | 
 | use rustc_hash::{FxHashMap, FxHashSet}; | 
 | use smallvec::{SmallVec, smallvec}; | 
 | use span::{Edition, FileId, SyntaxContext}; | 
 | use stdx::TupleExt; | 
 | use syntax::{ | 
 |     AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, | 
 |     TextSize, | 
 |     algo::skip_trivia_token, | 
 |     ast::{self, HasAttrs as _, HasGenericParams}, | 
 | }; | 
 |  | 
 | use crate::{ | 
 |     Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, | 
 |     Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource, Impl, | 
 |     InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, | 
 |     Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField, | 
 |     Type, TypeAlias, TypeParam, Union, Variant, VariantDef, | 
 |     db::HirDatabase, | 
 |     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 
 |     source_analyzer::{SourceAnalyzer, name_hygiene, resolve_hir_path}, | 
 | }; | 
 |  | 
 | const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(()); | 
 |  | 
 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 
 | pub enum PathResolution { | 
 |     /// An item | 
 |     Def(ModuleDef), | 
 |     /// A local binding (only value namespace) | 
 |     Local(Local), | 
 |     /// A type parameter | 
 |     TypeParam(TypeParam), | 
 |     /// A const parameter | 
 |     ConstParam(ConstParam), | 
 |     SelfType(Impl), | 
 |     BuiltinAttr(BuiltinAttr), | 
 |     ToolModule(ToolModule), | 
 |     DeriveHelper(DeriveHelper), | 
 | } | 
 |  | 
 | impl PathResolution { | 
 |     pub(crate) fn in_type_ns(&self) -> Option<TypeNs> { | 
 |         match self { | 
 |             PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())), | 
 |             PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { | 
 |                 Some(TypeNs::BuiltinType((*builtin).into())) | 
 |             } | 
 |             PathResolution::Def( | 
 |                 ModuleDef::Const(_) | 
 |                 | ModuleDef::Variant(_) | 
 |                 | ModuleDef::Macro(_) | 
 |                 | ModuleDef::Function(_) | 
 |                 | ModuleDef::Module(_) | 
 |                 | ModuleDef::Static(_) | 
 |                 | ModuleDef::Trait(_) | 
 |                 | ModuleDef::TraitAlias(_), | 
 |             ) => None, | 
 |             PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | 
 |                 Some(TypeNs::TypeAliasId((*alias).into())) | 
 |             } | 
 |             PathResolution::BuiltinAttr(_) | 
 |             | PathResolution::ToolModule(_) | 
 |             | PathResolution::Local(_) | 
 |             | PathResolution::DeriveHelper(_) | 
 |             | PathResolution::ConstParam(_) => None, | 
 |             PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | 
 |             PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #[derive(Debug)] | 
 | pub struct TypeInfo { | 
 |     /// The original type of the expression or pattern. | 
 |     pub original: Type, | 
 |     /// The adjusted type, if an adjustment happened. | 
 |     pub adjusted: Option<Type>, | 
 | } | 
 |  | 
 | impl TypeInfo { | 
 |     pub fn original(self) -> Type { | 
 |         self.original | 
 |     } | 
 |  | 
 |     pub fn has_adjustment(&self) -> bool { | 
 |         self.adjusted.is_some() | 
 |     } | 
 |  | 
 |     /// The adjusted type, or the original in case no adjustments occurred. | 
 |     pub fn adjusted(self) -> Type { | 
 |         self.adjusted.unwrap_or(self.original) | 
 |     } | 
 | } | 
 |  | 
 | /// Primary API to get semantic information, like types, from syntax trees. | 
 | pub struct Semantics<'db, DB> { | 
 |     pub db: &'db DB, | 
 |     imp: SemanticsImpl<'db>, | 
 | } | 
 |  | 
 | pub struct SemanticsImpl<'db> { | 
 |     pub db: &'db dyn HirDatabase, | 
 |     s2d_cache: RefCell<SourceToDefCache>, | 
 |     /// MacroCall to its expansion's MacroCallId cache | 
 |     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>, | 
 | } | 
 |  | 
 | impl<DB> fmt::Debug for Semantics<'_, DB> { | 
 |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
 |         write!(f, "Semantics {{ ... }}") | 
 |     } | 
 | } | 
 |  | 
 | impl<'db, DB> ops::Deref for Semantics<'db, DB> { | 
 |     type Target = SemanticsImpl<'db>; | 
 |  | 
 |     fn deref(&self) -> &Self::Target { | 
 |         &self.imp | 
 |     } | 
 | } | 
 |  | 
 | impl<DB: HirDatabase> Semantics<'_, DB> { | 
 |     pub fn new(db: &DB) -> Semantics<'_, DB> { | 
 |         let impl_ = SemanticsImpl::new(db); | 
 |         Semantics { db, imp: impl_ } | 
 |     } | 
 |  | 
 |     pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId { | 
 |         self.imp.find_file(syntax_node).file_id | 
 |     } | 
 |  | 
 |     pub fn token_ancestors_with_macros( | 
 |         &self, | 
 |         token: SyntaxToken, | 
 |     ) -> impl Iterator<Item = SyntaxNode> + '_ { | 
 |         token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it)) | 
 |     } | 
 |  | 
 |     /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | 
 |     /// search up until it is of the target AstNode type | 
 |     pub fn find_node_at_offset_with_macros<N: AstNode>( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> Option<N> { | 
 |         self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | 
 |     } | 
 |  | 
 |     /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | 
 |     /// descend it and find again | 
 |     // FIXME: Rethink this API | 
 |     pub fn find_node_at_offset_with_descend<N: AstNode>( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> Option<N> { | 
 |         self.imp.descend_node_at_offset(node, offset).flatten().find_map(N::cast) | 
 |     } | 
 |  | 
 |     /// Find an AstNode by offset inside SyntaxNode, if it is inside an attribute macro call, | 
 |     /// descend it and find again | 
 |     // FIXME: Rethink this API | 
 |     pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>( | 
 |         &'slf self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> impl Iterator<Item = N> + 'slf { | 
 |         self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast)) | 
 |     } | 
 |  | 
 |     pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> { | 
 |         self.imp.resolve_range_pat(range_pat).map(Struct::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> { | 
 |         self.imp.resolve_range_expr(range_expr).map(Struct::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> { | 
 |         self.imp.resolve_await_to_poll(await_expr).map(Function::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> { | 
 |         self.imp.resolve_prefix_expr(prefix_expr).map(Function::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> { | 
 |         self.imp.resolve_index_expr(index_expr).map(Function::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> { | 
 |         self.imp.resolve_bin_expr(bin_expr).map(Function::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> { | 
 |         self.imp.resolve_try_expr(try_expr).map(Function::from) | 
 |     } | 
 |  | 
 |     pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { | 
 |         self.imp.resolve_variant(record_lit).map(VariantDef::from) | 
 |     } | 
 |  | 
 |     pub fn file_to_module_def(&self, file: impl Into<FileId>) -> Option<Module> { | 
 |         self.imp.file_to_module_defs(file.into()).next() | 
 |     } | 
 |  | 
 |     pub fn file_to_module_defs(&self, file: impl Into<FileId>) -> impl Iterator<Item = Module> { | 
 |         self.imp.file_to_module_defs(file.into()) | 
 |     } | 
 |  | 
 |     pub fn to_adt_def(&self, a: &ast::Adt) -> Option<Adt> { | 
 |         self.imp.to_def(a) | 
 |     } | 
 |  | 
 |     pub fn to_const_def(&self, c: &ast::Const) -> Option<Const> { | 
 |         self.imp.to_def(c) | 
 |     } | 
 |  | 
 |     pub fn to_enum_def(&self, e: &ast::Enum) -> Option<Enum> { | 
 |         self.imp.to_def(e) | 
 |     } | 
 |  | 
 |     pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<Variant> { | 
 |         self.imp.to_def(v) | 
 |     } | 
 |  | 
 |     pub fn to_fn_def(&self, f: &ast::Fn) -> Option<Function> { | 
 |         self.imp.to_def(f) | 
 |     } | 
 |  | 
 |     pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> { | 
 |         self.imp.to_def(i) | 
 |     } | 
 |  | 
 |     pub fn to_macro_def(&self, m: &ast::Macro) -> Option<Macro> { | 
 |         self.imp.to_def(m) | 
 |     } | 
 |  | 
 |     pub fn to_module_def(&self, m: &ast::Module) -> Option<Module> { | 
 |         self.imp.to_def(m) | 
 |     } | 
 |  | 
 |     pub fn to_static_def(&self, s: &ast::Static) -> Option<Static> { | 
 |         self.imp.to_def(s) | 
 |     } | 
 |  | 
 |     pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> { | 
 |         self.imp.to_def(s) | 
 |     } | 
 |  | 
 |     pub fn to_trait_alias_def(&self, t: &ast::TraitAlias) -> Option<TraitAlias> { | 
 |         self.imp.to_def(t) | 
 |     } | 
 |  | 
 |     pub fn to_trait_def(&self, t: &ast::Trait) -> Option<Trait> { | 
 |         self.imp.to_def(t) | 
 |     } | 
 |  | 
 |     pub fn to_type_alias_def(&self, t: &ast::TypeAlias) -> Option<TypeAlias> { | 
 |         self.imp.to_def(t) | 
 |     } | 
 |  | 
 |     pub fn to_union_def(&self, u: &ast::Union) -> Option<Union> { | 
 |         self.imp.to_def(u) | 
 |     } | 
 | } | 
 |  | 
 | impl<'db> SemanticsImpl<'db> { | 
 |     fn new(db: &'db dyn HirDatabase) -> Self { | 
 |         SemanticsImpl { db, s2d_cache: Default::default(), macro_call_cache: Default::default() } | 
 |     } | 
 |  | 
 |     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile { | 
 |         let hir_file_id = file_id.into(); | 
 |         let tree = self.db.parse(file_id).tree(); | 
 |         self.cache(tree.syntax().clone(), hir_file_id); | 
 |         tree | 
 |     } | 
 |  | 
 |     /// If not crate is found for the file, try to return the last crate in topological order. | 
 |     pub fn first_crate(&self, file: FileId) -> Option<Crate> { | 
 |         match self.file_to_module_defs(file).next() { | 
 |             Some(module) => Some(module.krate()), | 
 |             None => self.db.all_crates().last().copied().map(Into::into), | 
 |         } | 
 |     } | 
 |  | 
 |     pub fn attach_first_edition(&self, file: FileId) -> Option<EditionedFileId> { | 
 |         Some(EditionedFileId::new( | 
 |             self.db, | 
 |             file, | 
 |             self.file_to_module_defs(file).next()?.krate().edition(self.db), | 
 |         )) | 
 |     } | 
 |  | 
 |     pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile { | 
 |         let file_id = self | 
 |             .attach_first_edition(file_id) | 
 |             .unwrap_or_else(|| EditionedFileId::new(self.db, file_id, Edition::CURRENT)); | 
 |  | 
 |         let tree = self.db.parse(file_id).tree(); | 
 |         self.cache(tree.syntax().clone(), file_id.into()); | 
 |         tree | 
 |     } | 
 |  | 
 |     pub fn find_parent_file(&self, file_id: HirFileId) -> Option<InFile<SyntaxNode>> { | 
 |         match file_id { | 
 |             HirFileId::FileId(file_id) => { | 
 |                 let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?; | 
 |                 let def_map = self.db.crate_def_map(module.krate().id); | 
 |                 match def_map[module.id.local_id].origin { | 
 |                     ModuleOrigin::CrateRoot { .. } => None, | 
 |                     ModuleOrigin::File { declaration, declaration_tree_id, .. } => { | 
 |                         let file_id = declaration_tree_id.file_id(); | 
 |                         let in_file = InFile::new(file_id, declaration); | 
 |                         let node = in_file.to_node(self.db); | 
 |                         let root = find_root(node.syntax()); | 
 |                         self.cache(root, file_id); | 
 |                         Some(in_file.with_value(node.syntax().clone())) | 
 |                     } | 
 |                     _ => unreachable!("FileId can only belong to a file module"), | 
 |                 } | 
 |             } | 
 |             HirFileId::MacroFile(macro_file) => { | 
 |                 let node = self.db.lookup_intern_macro_call(macro_file).to_node(self.db); | 
 |                 let root = find_root(&node.value); | 
 |                 self.cache(root, node.file_id); | 
 |                 Some(node) | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns the `SyntaxNode` of the module. If this is a file module, returns | 
 |     /// the `SyntaxNode` of the *definition* file, not of the *declaration*. | 
 |     pub fn module_definition_node(&self, module: Module) -> InFile<SyntaxNode> { | 
 |         let def_map = module.id.def_map(self.db); | 
 |         let definition = def_map[module.id.local_id].origin.definition_source(self.db); | 
 |         let definition = definition.map(|it| it.node()); | 
 |         let root_node = find_root(&definition.value); | 
 |         self.cache(root_node, definition.file_id); | 
 |         definition | 
 |     } | 
 |  | 
 |     pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { | 
 |         let node = self.db.parse_or_expand(file_id); | 
 |         self.cache(node.clone(), file_id); | 
 |         node | 
 |     } | 
 |  | 
 |     pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> { | 
 |         let res = self.db.parse_macro_expansion(file_id).map(|it| it.0.syntax_node()); | 
 |         self.cache(res.value.clone(), file_id.into()); | 
 |         res | 
 |     } | 
 |  | 
 |     pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 
 |         let sa = self.analyze_no_infer(macro_call.syntax())?; | 
 |  | 
 |         let macro_call = InFile::new(sa.file_id, macro_call); | 
 |         let file_id = sa.expand(self.db, macro_call)?; | 
 |  | 
 |         let node = self.parse_or_expand(file_id.into()); | 
 |         Some(node) | 
 |     } | 
 |  | 
 |     pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option<bool> { | 
 |         let file_id = self.find_file(attr.syntax()).file_id; | 
 |         let krate = match file_id { | 
 |             HirFileId::FileId(file_id) => { | 
 |                 self.file_to_module_defs(file_id.file_id(self.db)).next()?.krate().id | 
 |             } | 
 |             HirFileId::MacroFile(macro_file) => self.db.lookup_intern_macro_call(macro_file).krate, | 
 |         }; | 
 |         hir_expand::check_cfg_attr_value(self.db, attr, krate) | 
 |     } | 
 |  | 
 |     /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy | 
 |     /// expansions. | 
 |     pub fn expand_allowed_builtins( | 
 |         &self, | 
 |         macro_call: &ast::MacroCall, | 
 |     ) -> Option<ExpandResult<SyntaxNode>> { | 
 |         let sa = self.analyze_no_infer(macro_call.syntax())?; | 
 |  | 
 |         let macro_call = InFile::new(sa.file_id, macro_call); | 
 |         let file_id = sa.expand(self.db, macro_call)?; | 
 |         let macro_call = self.db.lookup_intern_macro_call(file_id); | 
 |  | 
 |         let skip = matches!( | 
 |             macro_call.def.kind, | 
 |             hir_expand::MacroDefKind::BuiltIn( | 
 |                 _, | 
 |                 BuiltinFnLikeExpander::Column | 
 |                     | BuiltinFnLikeExpander::File | 
 |                     | BuiltinFnLikeExpander::ModulePath | 
 |                     | BuiltinFnLikeExpander::Asm | 
 |                     | BuiltinFnLikeExpander::GlobalAsm | 
 |                     | BuiltinFnLikeExpander::NakedAsm | 
 |                     | BuiltinFnLikeExpander::LogSyntax | 
 |                     | BuiltinFnLikeExpander::TraceMacros | 
 |                     | BuiltinFnLikeExpander::FormatArgs | 
 |                     | BuiltinFnLikeExpander::FormatArgsNl | 
 |                     | BuiltinFnLikeExpander::ConstFormatArgs, | 
 |             ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError) | 
 |         ); | 
 |         if skip { | 
 |             // these macros expand to custom builtin syntax and/or dummy things, no point in | 
 |             // showing these to the user | 
 |             return None; | 
 |         } | 
 |  | 
 |         let node = self.expand(file_id); | 
 |         Some(node) | 
 |     } | 
 |  | 
 |     /// If `item` has an attribute macro attached to it, expands it. | 
 |     pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<ExpandResult<SyntaxNode>> { | 
 |         let src = self.wrap_node_infile(item.clone()); | 
 |         let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?; | 
 |         Some(self.expand(macro_call_id)) | 
 |     } | 
 |  | 
 |     pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> { | 
 |         let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; | 
 |         let src = self.wrap_node_infile(attr.clone()); | 
 |         let call_id = self.with_ctx(|ctx| { | 
 |             ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it) | 
 |         })?; | 
 |         Some(self.parse_or_expand(call_id.into())) | 
 |     } | 
 |  | 
 |     pub fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> { | 
 |         let calls = self.derive_macro_calls(attr)?; | 
 |         self.with_ctx(|ctx| { | 
 |             Some( | 
 |                 calls | 
 |                     .into_iter() | 
 |                     .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) | 
 |                     .collect(), | 
 |             ) | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<ExpandResult<SyntaxNode>>> { | 
 |         let res: Vec<_> = self | 
 |             .derive_macro_calls(attr)? | 
 |             .into_iter() | 
 |             .flat_map(|call| { | 
 |                 let file_id = call?; | 
 |                 let ExpandResult { value, err } = self.db.parse_macro_expansion(file_id); | 
 |                 let root_node = value.0.syntax_node(); | 
 |                 self.cache(root_node.clone(), file_id.into()); | 
 |                 Some(ExpandResult { value: root_node, err }) | 
 |             }) | 
 |             .collect(); | 
 |         Some(res) | 
 |     } | 
 |  | 
 |     fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>>> { | 
 |         let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; | 
 |         let file_id = self.find_file(adt.syntax()).file_id; | 
 |         let adt = InFile::new(file_id, &adt); | 
 |         let src = InFile::new(file_id, attr.clone()); | 
 |         self.with_ctx(|ctx| { | 
 |             let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?; | 
 |             Some(res.to_vec()) | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn is_derive_annotated(&self, adt: InFile<&ast::Adt>) -> bool { | 
 |         self.with_ctx(|ctx| ctx.has_derives(adt)) | 
 |     } | 
 |  | 
 |     pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> { | 
 |         let sa = self.analyze_no_infer(adt.syntax())?; | 
 |         let id = self.db.ast_id_map(sa.file_id).ast_id(adt); | 
 |         let result = sa | 
 |             .resolver | 
 |             .def_map() | 
 |             .derive_helpers_in_scope(InFile::new(sa.file_id, id))? | 
 |             .iter() | 
 |             .map(|(name, macro_, _)| { | 
 |                 let macro_name = Macro::from(*macro_).name(self.db).symbol().clone(); | 
 |                 (name.symbol().clone(), macro_name) | 
 |             }) | 
 |             .collect(); | 
 |         Some(result) | 
 |     } | 
 |  | 
 |     pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroCallId)>> { | 
 |         let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it { | 
 |             ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), | 
 |             ast::Item::Enum(it) => Some(ast::Adt::Enum(it)), | 
 |             ast::Item::Union(it) => Some(ast::Adt::Union(it)), | 
 |             _ => None, | 
 |         })?; | 
 |         let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); | 
 |         let sa = self.analyze_no_infer(adt.syntax())?; | 
 |         let id = self.db.ast_id_map(sa.file_id).ast_id(&adt); | 
 |         let res: Vec<_> = sa | 
 |             .resolver | 
 |             .def_map() | 
 |             .derive_helpers_in_scope(InFile::new(sa.file_id, id))? | 
 |             .iter() | 
 |             .filter(|&(name, _, _)| *name == attr_name) | 
 |             .map(|&(_, macro_, call)| (macro_.into(), call)) | 
 |             .collect(); | 
 |         res.is_empty().not().then_some(res) | 
 |     } | 
 |  | 
 |     pub fn is_attr_macro_call(&self, item: InFile<&ast::Item>) -> bool { | 
 |         self.with_ctx(|ctx| ctx.item_to_macro_call(item).is_some()) | 
 |     } | 
 |  | 
 |     /// Expand the macro call with a different token tree, mapping the `token_to_map` down into the | 
 |     /// expansion. `token_to_map` should be a token from the `speculative args` node. | 
 |     pub fn speculative_expand_macro_call( | 
 |         &self, | 
 |         actual_macro_call: &ast::MacroCall, | 
 |         speculative_args: &ast::TokenTree, | 
 |         token_to_map: SyntaxToken, | 
 |     ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { | 
 |         let analyzer = self.analyze_no_infer(actual_macro_call.syntax())?; | 
 |         let macro_call = InFile::new(analyzer.file_id, actual_macro_call); | 
 |         let macro_file = analyzer.expansion(macro_call)?; | 
 |         hir_expand::db::expand_speculative( | 
 |             self.db, | 
 |             macro_file, | 
 |             speculative_args.syntax(), | 
 |             token_to_map, | 
 |         ) | 
 |     } | 
 |  | 
 |     pub fn speculative_expand_raw( | 
 |         &self, | 
 |         macro_file: MacroCallId, | 
 |         speculative_args: &SyntaxNode, | 
 |         token_to_map: SyntaxToken, | 
 |     ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { | 
 |         hir_expand::db::expand_speculative(self.db, macro_file, speculative_args, token_to_map) | 
 |     } | 
 |  | 
 |     /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the | 
 |     /// expansion. `token_to_map` should be a token from the `speculative args` node. | 
 |     pub fn speculative_expand_attr_macro( | 
 |         &self, | 
 |         actual_macro_call: &ast::Item, | 
 |         speculative_args: &ast::Item, | 
 |         token_to_map: SyntaxToken, | 
 |     ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { | 
 |         let macro_call = self.wrap_node_infile(actual_macro_call.clone()); | 
 |         let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?; | 
 |         hir_expand::db::expand_speculative( | 
 |             self.db, | 
 |             macro_call_id, | 
 |             speculative_args.syntax(), | 
 |             token_to_map, | 
 |         ) | 
 |     } | 
 |  | 
 |     pub fn speculative_expand_derive_as_pseudo_attr_macro( | 
 |         &self, | 
 |         actual_macro_call: &ast::Attr, | 
 |         speculative_args: &ast::Attr, | 
 |         token_to_map: SyntaxToken, | 
 |     ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { | 
 |         let attr = self.wrap_node_infile(actual_macro_call.clone()); | 
 |         let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?; | 
 |         let macro_call_id = self.with_ctx(|ctx| { | 
 |             ctx.attr_to_derive_macro_call(attr.with_value(&adt), attr).map(|(_, it, _)| it) | 
 |         })?; | 
 |         hir_expand::db::expand_speculative( | 
 |             self.db, | 
 |             macro_call_id, | 
 |             speculative_args.syntax(), | 
 |             token_to_map, | 
 |         ) | 
 |     } | 
 |  | 
 |     /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, | 
 |     /// and returns the conflicting locals. | 
 |     pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> { | 
 |         let body = self.db.body(to_be_renamed.parent); | 
 |         let resolver = to_be_renamed.parent.resolver(self.db); | 
 |         let starting_expr = | 
 |             body.binding_owners.get(&to_be_renamed.binding_id).copied().unwrap_or(body.body_expr); | 
 |         let mut visitor = RenameConflictsVisitor { | 
 |             body: &body, | 
 |             conflicts: FxHashSet::default(), | 
 |             db: self.db, | 
 |             new_name: Symbol::intern(new_name), | 
 |             old_name: to_be_renamed.name(self.db).symbol().clone(), | 
 |             owner: to_be_renamed.parent, | 
 |             to_be_renamed: to_be_renamed.binding_id, | 
 |             resolver, | 
 |         }; | 
 |         visitor.rename_conflicts(starting_expr); | 
 |         visitor | 
 |             .conflicts | 
 |             .into_iter() | 
 |             .map(|binding_id| Local { parent: to_be_renamed.parent, binding_id }) | 
 |             .collect() | 
 |     } | 
 |  | 
 |     /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string. | 
 |     pub fn as_format_args_parts( | 
 |         &self, | 
 |         string: &ast::String, | 
 |     ) -> Option<Vec<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)>> { | 
 |         let string_start = string.syntax().text_range().start(); | 
 |         let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; | 
 |         self.descend_into_macros_breakable(token, |token, _| { | 
 |             (|| { | 
 |                 let token = token.value; | 
 |                 let string = ast::String::cast(token)?; | 
 |                 let literal = | 
 |                     string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; | 
 |                 let parent = literal.parent()?; | 
 |                 if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { | 
 |                     let source_analyzer = self.analyze_no_infer(format_args.syntax())?; | 
 |                     let format_args = self.wrap_node_infile(format_args); | 
 |                     let res = source_analyzer | 
 |                         .as_format_args_parts(self.db, format_args.as_ref())? | 
 |                         .map(|(range, res)| (range + string_start, res.map(Either::Left))) | 
 |                         .collect(); | 
 |                     Some(res) | 
 |                 } else { | 
 |                     let asm = ast::AsmExpr::cast(parent)?; | 
 |                     let source_analyzer = self.analyze_no_infer(asm.syntax())?; | 
 |                     let line = asm.template().position(|it| *it.syntax() == literal)?; | 
 |                     let asm = self.wrap_node_infile(asm); | 
 |                     let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?; | 
 |                     let res = asm_parts | 
 |                         .get(line)? | 
 |                         .iter() | 
 |                         .map(|&(range, index)| { | 
 |                             ( | 
 |                                 range + string_start, | 
 |                                 Some(Either::Right(InlineAsmOperand { owner, expr, index })), | 
 |                             ) | 
 |                         }) | 
 |                         .collect(); | 
 |                     Some(res) | 
 |                 } | 
 |             })() | 
 |             .map_or(ControlFlow::Continue(()), ControlFlow::Break) | 
 |         }) | 
 |     } | 
 |  | 
 |     /// Retrieves the formatting part of the format_args! template string at the given offset. | 
 |     pub fn check_for_format_args_template( | 
 |         &self, | 
 |         original_token: SyntaxToken, | 
 |         offset: TextSize, | 
 |     ) -> Option<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)> { | 
 |         let string_start = original_token.text_range().start(); | 
 |         let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; | 
 |         self.descend_into_macros_breakable(original_token, |token, _| { | 
 |             (|| { | 
 |                 let token = token.value; | 
 |                 self.resolve_offset_in_format_args( | 
 |                     ast::String::cast(token)?, | 
 |                     offset.checked_sub(string_start)?, | 
 |                 ) | 
 |                 .map(|(range, res)| (range + string_start, res)) | 
 |             })() | 
 |             .map_or(ControlFlow::Continue(()), ControlFlow::Break) | 
 |         }) | 
 |     } | 
 |  | 
 |     fn resolve_offset_in_format_args( | 
 |         &self, | 
 |         string: ast::String, | 
 |         offset: TextSize, | 
 |     ) -> Option<(TextRange, Option<Either<PathResolution, InlineAsmOperand>>)> { | 
 |         debug_assert!(offset <= string.syntax().text_range().len()); | 
 |         let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; | 
 |         let parent = literal.parent()?; | 
 |         if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { | 
 |             let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; | 
 |             let format_args = self.wrap_node_infile(format_args); | 
 |             source_analyzer | 
 |                 .resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) | 
 |                 .map(|(range, res)| (range, res.map(Either::Left))) | 
 |         } else { | 
 |             let asm = ast::AsmExpr::cast(parent)?; | 
 |             let source_analyzer = &self.analyze_no_infer(asm.syntax())?; | 
 |             let line = asm.template().position(|it| *it.syntax() == literal)?; | 
 |             let asm = self.wrap_node_infile(asm); | 
 |             source_analyzer.resolve_offset_in_asm_template(asm.as_ref(), line, offset).map( | 
 |                 |(owner, (expr, range, index))| { | 
 |                     (range, Some(Either::Right(InlineAsmOperand { owner, expr, index }))) | 
 |                 }, | 
 |             ) | 
 |         } | 
 |     } | 
 |  | 
 |     pub fn debug_hir_at(&self, token: SyntaxToken) -> Option<String> { | 
 |         self.analyze_no_infer(&token.parent()?).and_then(|it| { | 
 |             Some(match it.body_or_sig.as_ref()? { | 
 |                 crate::source_analyzer::BodyOrSig::Body { def, body, .. } => { | 
 |                     hir_def::expr_store::pretty::print_body_hir( | 
 |                         self.db, | 
 |                         body, | 
 |                         *def, | 
 |                         it.file_id.edition(self.db), | 
 |                     ) | 
 |                 } | 
 |                 &crate::source_analyzer::BodyOrSig::VariantFields { def, .. } => { | 
 |                     hir_def::expr_store::pretty::print_variant_body_hir( | 
 |                         self.db, | 
 |                         def, | 
 |                         it.file_id.edition(self.db), | 
 |                     ) | 
 |                 } | 
 |                 &crate::source_analyzer::BodyOrSig::Sig { def, .. } => { | 
 |                     hir_def::expr_store::pretty::print_signature( | 
 |                         self.db, | 
 |                         def, | 
 |                         it.file_id.edition(self.db), | 
 |                     ) | 
 |                 } | 
 |             }) | 
 |         }) | 
 |     } | 
 |  | 
 |     /// Maps a node down by mapping its first and last token down. | 
 |     pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> { | 
 |         // This might not be the correct way to do this, but it works for now | 
 |         let mut res = smallvec![]; | 
 |         let tokens = (|| { | 
 |             // FIXME: the trivia skipping should not be necessary | 
 |             let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?; | 
 |             let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?; | 
 |             Some((first, last)) | 
 |         })(); | 
 |         let (first, last) = match tokens { | 
 |             Some(it) => it, | 
 |             None => return res, | 
 |         }; | 
 |         let file = self.find_file(node.syntax()); | 
 |         let Some(file_id) = file.file_id.file_id() else { | 
 |             return res; | 
 |         }; | 
 |  | 
 |         if first == last { | 
 |             // node is just the token, so descend the token | 
 |             self.descend_into_macros_impl( | 
 |                 InRealFile::new(file_id, first), | 
 |                 &mut |InFile { value, .. }, _ctx| { | 
 |                     if let Some(node) = value | 
 |                         .parent_ancestors() | 
 |                         .take_while(|it| it.text_range() == value.text_range()) | 
 |                         .find_map(N::cast) | 
 |                     { | 
 |                         res.push(node) | 
 |                     } | 
 |                     CONTINUE_NO_BREAKS | 
 |                 }, | 
 |             ); | 
 |         } else { | 
 |             // Descend first and last token, then zip them to look for the node they belong to | 
 |             let mut scratch: SmallVec<[_; 1]> = smallvec![]; | 
 |             self.descend_into_macros_impl(InRealFile::new(file_id, first), &mut |token, _ctx| { | 
 |                 scratch.push(token); | 
 |                 CONTINUE_NO_BREAKS | 
 |             }); | 
 |  | 
 |             let mut scratch = scratch.into_iter(); | 
 |             self.descend_into_macros_impl( | 
 |                 InRealFile::new(file_id, last), | 
 |                 &mut |InFile { value: last, file_id: last_fid }, _ctx| { | 
 |                     if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { | 
 |                         if first_fid == last_fid { | 
 |                             if let Some(p) = first.parent() { | 
 |                                 let range = first.text_range().cover(last.text_range()); | 
 |                                 let node = find_root(&p) | 
 |                                     .covering_element(range) | 
 |                                     .ancestors() | 
 |                                     .take_while(|it| it.text_range() == range) | 
 |                                     .find_map(N::cast); | 
 |                                 if let Some(node) = node { | 
 |                                     res.push(node); | 
 |                                 } | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                     CONTINUE_NO_BREAKS | 
 |                 }, | 
 |             ); | 
 |         } | 
 |         res | 
 |     } | 
 |  | 
 |     // FIXME: This isn't quite right wrt to inner attributes | 
 |     /// Does a syntactic traversal to check whether this token might be inside a macro call | 
 |     pub fn might_be_inside_macro_call(&self, token: &SyntaxToken) -> bool { | 
 |         token.parent_ancestors().any(|ancestor| { | 
 |             if ast::MacroCall::can_cast(ancestor.kind()) { | 
 |                 return true; | 
 |             } | 
 |             // Check if it is an item (only items can have macro attributes) that has a non-builtin attribute. | 
 |             let Some(item) = ast::Item::cast(ancestor) else { return false }; | 
 |             item.attrs().any(|attr| { | 
 |                 let Some(meta) = attr.meta() else { return false }; | 
 |                 let Some(path) = meta.path() else { return false }; | 
 |                 if let Some(attr_name) = path.as_single_name_ref() { | 
 |                     let attr_name = attr_name.text(); | 
 |                     let attr_name = Symbol::intern(attr_name.as_str()); | 
 |                     if attr_name == sym::derive { | 
 |                         return true; | 
 |                     } | 
 |                     // We ignore `#[test]` and friends in the def map, so we cannot expand them. | 
 |                     // FIXME: We match by text. This is both hacky and incorrect (people can, and do, create | 
 |                     // other macros named `test`). We cannot fix that unfortunately because we use this method | 
 |                     // for speculative expansion in completion, which we cannot analyze. Fortunately, most macros | 
 |                     // named `test` are test-like, meaning their expansion is not terribly important for IDE. | 
 |                     if attr_name == sym::test | 
 |                         || attr_name == sym::bench | 
 |                         || attr_name == sym::test_case | 
 |                         || find_builtin_attr_idx(&attr_name).is_some() | 
 |                     { | 
 |                         return false; | 
 |                     } | 
 |                 } | 
 |                 let mut segments = path.segments(); | 
 |                 let mut next_segment_text = || segments.next().and_then(|it| it.name_ref()); | 
 |                 // `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`. | 
 |                 if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std")) | 
 |                     && next_segment_text().is_some_and(|it| it.text() == "prelude") | 
 |                     && next_segment_text().is_some() | 
 |                     && next_segment_text() | 
 |                         .is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case")) | 
 |                 { | 
 |                     return false; | 
 |                 } | 
 |                 true | 
 |             }) | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn descend_into_macros_cb( | 
 |         &self, | 
 |         token: SyntaxToken, | 
 |         mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext), | 
 |     ) { | 
 |         if let Ok(token) = self.wrap_token_infile(token).into_real_file() { | 
 |             self.descend_into_macros_impl(token, &mut |t, ctx| { | 
 |                 cb(t, ctx); | 
 |                 CONTINUE_NO_BREAKS | 
 |             }); | 
 |         } | 
 |     } | 
 |  | 
 |     pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { | 
 |         let mut res = smallvec![]; | 
 |         if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { | 
 |             self.descend_into_macros_impl(token, &mut |t, _ctx| { | 
 |                 res.push(t.value); | 
 |                 CONTINUE_NO_BREAKS | 
 |             }); | 
 |         } | 
 |         if res.is_empty() { | 
 |             res.push(token); | 
 |         } | 
 |         res | 
 |     } | 
 |  | 
 |     pub fn descend_into_macros_no_opaque( | 
 |         &self, | 
 |         token: SyntaxToken, | 
 |     ) -> SmallVec<[InFile<SyntaxToken>; 1]> { | 
 |         let mut res = smallvec![]; | 
 |         let token = self.wrap_token_infile(token); | 
 |         if let Ok(token) = token.clone().into_real_file() { | 
 |             self.descend_into_macros_impl(token, &mut |t, ctx| { | 
 |                 if !ctx.is_opaque(self.db) { | 
 |                     // Don't descend into opaque contexts | 
 |                     res.push(t); | 
 |                 } | 
 |                 CONTINUE_NO_BREAKS | 
 |             }); | 
 |         } | 
 |         if res.is_empty() { | 
 |             res.push(token); | 
 |         } | 
 |         res | 
 |     } | 
 |  | 
 |     pub fn descend_into_macros_breakable<T>( | 
 |         &self, | 
 |         token: InRealFile<SyntaxToken>, | 
 |         mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>, | 
 |     ) -> Option<T> { | 
 |         self.descend_into_macros_impl(token.clone(), &mut cb) | 
 |     } | 
 |  | 
 |     /// Descends the token into expansions, returning the tokens that matches the input | 
 |     /// token's [`SyntaxKind`] and text. | 
 |     pub fn descend_into_macros_exact(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { | 
 |         let mut r = smallvec![]; | 
 |         let text = token.text(); | 
 |         let kind = token.kind(); | 
 |  | 
 |         self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }, ctx| { | 
 |             let mapped_kind = value.kind(); | 
 |             let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier(); | 
 |             let matches = (kind == mapped_kind || any_ident_match()) | 
 |                 && text == value.text() | 
 |                 && !ctx.is_opaque(self.db); | 
 |             if matches { | 
 |                 r.push(value); | 
 |             } | 
 |         }); | 
 |         if r.is_empty() { | 
 |             r.push(token); | 
 |         } | 
 |         r | 
 |     } | 
 |  | 
 |     /// Descends the token into expansions, returning the first token that matches the input | 
 |     /// token's [`SyntaxKind`] and text. | 
 |     pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken { | 
 |         let text = token.text(); | 
 |         let kind = token.kind(); | 
 |         if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { | 
 |             self.descend_into_macros_breakable( | 
 |                 token.clone(), | 
 |                 |InFile { value, file_id: _ }, _ctx| { | 
 |                     let mapped_kind = value.kind(); | 
 |                     let any_ident_match = | 
 |                         || kind.is_any_identifier() && value.kind().is_any_identifier(); | 
 |                     let matches = | 
 |                         (kind == mapped_kind || any_ident_match()) && text == value.text(); | 
 |                     if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } | 
 |                 }, | 
 |             ) | 
 |         } else { | 
 |             None | 
 |         } | 
 |         .unwrap_or(token) | 
 |     } | 
 |  | 
 |     fn descend_into_macros_impl<T>( | 
 |         &self, | 
 |         InRealFile { value: token, file_id }: InRealFile<SyntaxToken>, | 
 |         f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>, | 
 |     ) -> Option<T> { | 
 |         let _p = tracing::info_span!("descend_into_macros_impl").entered(); | 
 |  | 
 |         let span = self.db.real_span_map(file_id).span_for_range(token.text_range()); | 
 |  | 
 |         // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack | 
 |         let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { | 
 |             let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { | 
 |                 Some( | 
 |                     ctx.cache | 
 |                         .get_or_insert_expansion(ctx.db, macro_file) | 
 |                         .map_range_down(span)? | 
 |                         .map(SmallVec::<[_; 2]>::from_iter), | 
 |                 ) | 
 |             })?; | 
 |             // we have found a mapping for the token if the vec is non-empty | 
 |             let res = mapped_tokens.is_empty().not().then_some(()); | 
 |             // requeue the tokens we got from mapping our current token down | 
 |             stack.push((HirFileId::from(file_id), mapped_tokens)); | 
 |             res | 
 |         }; | 
 |  | 
 |         // A stack of tokens to process, along with the file they came from | 
 |         // These are tracked to know which macro calls we still have to look into | 
 |         // the tokens themselves aren't that interesting as the span that is being used to map | 
 |         // things down never changes. | 
 |         let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![]; | 
 |         let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id); | 
 |         match include { | 
 |             Some(include) => { | 
 |                 // include! inputs are always from real files, so they only need to be handled once upfront | 
 |                 process_expansion_for_token(&mut stack, include)?; | 
 |             } | 
 |             None => { | 
 |                 stack.push(( | 
 |                     file_id.into(), | 
 |                     smallvec![(token, SyntaxContext::root(file_id.edition(self.db)))], | 
 |                 )); | 
 |             } | 
 |         } | 
 |  | 
 |         let mut m_cache = self.macro_call_cache.borrow_mut(); | 
 |  | 
 |         // Filters out all tokens that contain the given range (usually the macro call), any such | 
 |         // token is redundant as the corresponding macro call has already been processed | 
 |         let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| { | 
 |             tokens.retain(|(t, _): &mut (SyntaxToken, _)| !range.contains_range(t.text_range())) | 
 |         }; | 
 |  | 
 |         while let Some((expansion, ref mut tokens)) = stack.pop() { | 
 |             // Reverse the tokens so we prefer first tokens (to accommodate for popping from the | 
 |             // back) | 
 |             // alternatively we could pop from the front but that would shift the content on every pop | 
 |             tokens.reverse(); | 
 |             while let Some((token, ctx)) = tokens.pop() { | 
 |                 let was_not_remapped = (|| { | 
 |                     // First expand into attribute invocations | 
 |                     let containing_attribute_macro_call = self.with_ctx(|ctx| { | 
 |                         token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { | 
 |                             // Don't force populate the dyn cache for items that don't have an attribute anyways | 
 |                             item.attrs().next()?; | 
 |                             Some((ctx.item_to_macro_call(InFile::new(expansion, &item))?, item)) | 
 |                         }) | 
 |                     }); | 
 |                     if let Some((call_id, item)) = containing_attribute_macro_call { | 
 |                         let attr_id = match self.db.lookup_intern_macro_call(call_id).kind { | 
 |                             hir_expand::MacroCallKind::Attr { invoc_attr_index, .. } => { | 
 |                                 invoc_attr_index.ast_index() | 
 |                             } | 
 |                             _ => 0, | 
 |                         }; | 
 |                         // FIXME: here, the attribute's text range is used to strip away all | 
 |                         // entries from the start of the attribute "list" up the invoking | 
 |                         // attribute. But in | 
 |                         // ``` | 
 |                         // mod foo { | 
 |                         //     #![inner] | 
 |                         // } | 
 |                         // ``` | 
 |                         // we don't wanna strip away stuff in the `mod foo {` range, that is | 
 |                         // here if the id corresponds to an inner attribute we got strip all | 
 |                         // text ranges of the outer ones, and then all of the inner ones up | 
 |                         // to the invoking attribute so that the inbetween is ignored. | 
 |                         let text_range = item.syntax().text_range(); | 
 |                         let start = collect_attrs(&item) | 
 |                             .nth(attr_id) | 
 |                             .map(|attr| match attr.1 { | 
 |                                 Either::Left(it) => it.syntax().text_range().start(), | 
 |                                 Either::Right(it) => it.syntax().text_range().start(), | 
 |                             }) | 
 |                             .unwrap_or_else(|| text_range.start()); | 
 |                         let text_range = TextRange::new(start, text_range.end()); | 
 |                         filter_duplicates(tokens, text_range); | 
 |                         return process_expansion_for_token(&mut stack, call_id); | 
 |                     } | 
 |  | 
 |                     // Then check for token trees, that means we are either in a function-like macro or | 
 |                     // secondary attribute inputs | 
 |                     let tt = token | 
 |                         .parent_ancestors() | 
 |                         .map_while(Either::<ast::TokenTree, ast::Meta>::cast) | 
 |                         .last()?; | 
 |                     match tt { | 
 |                         // function-like macro call | 
 |                         Either::Left(tt) => { | 
 |                             if tt.left_delimiter_token().map_or(false, |it| it == token) { | 
 |                                 return None; | 
 |                             } | 
 |                             if tt.right_delimiter_token().map_or(false, |it| it == token) { | 
 |                                 return None; | 
 |                             } | 
 |                             let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; | 
 |                             let mcall = InFile::new(expansion, macro_call); | 
 |                             let file_id = match m_cache.get(&mcall) { | 
 |                                 Some(&it) => it, | 
 |                                 None => { | 
 |                                     let it = token | 
 |                                         .parent() | 
 |                                         .and_then(|parent| { | 
 |                                             self.analyze_impl( | 
 |                                                 InFile::new(expansion, &parent), | 
 |                                                 None, | 
 |                                                 false, | 
 |                                             ) | 
 |                                         })? | 
 |                                         .expand(self.db, mcall.as_ref())?; | 
 |                                     m_cache.insert(mcall, it); | 
 |                                     it | 
 |                                 } | 
 |                             }; | 
 |                             let text_range = tt.syntax().text_range(); | 
 |                             filter_duplicates(tokens, text_range); | 
 |  | 
 |                             process_expansion_for_token(&mut stack, file_id).or(file_id | 
 |                                 .eager_arg(self.db) | 
 |                                 .and_then(|arg| { | 
 |                                     // also descend into eager expansions | 
 |                                     process_expansion_for_token(&mut stack, arg) | 
 |                                 })) | 
 |                         } | 
 |                         // derive or derive helper | 
 |                         Either::Right(meta) => { | 
 |                             // attribute we failed expansion for earlier, this might be a derive invocation | 
 |                             // or derive helper attribute | 
 |                             let attr = meta.parent_attr()?; | 
 |                             let adt = match attr.syntax().parent().and_then(ast::Adt::cast) { | 
 |                                 Some(adt) => { | 
 |                                     // this might be a derive on an ADT | 
 |                                     let derive_call = self.with_ctx(|ctx| { | 
 |                                         // so try downmapping the token into the pseudo derive expansion | 
 |                                         // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works | 
 |                                         ctx.attr_to_derive_macro_call( | 
 |                                             InFile::new(expansion, &adt), | 
 |                                             InFile::new(expansion, attr.clone()), | 
 |                                         ) | 
 |                                         .map(|(_, call_id, _)| call_id) | 
 |                                     }); | 
 |  | 
 |                                     match derive_call { | 
 |                                         Some(call_id) => { | 
 |                                             // resolved to a derive | 
 |                                             let text_range = attr.syntax().text_range(); | 
 |                                             // remove any other token in this macro input, all their mappings are the | 
 |                                             // same as this | 
 |                                             tokens.retain(|(t, _)| { | 
 |                                                 !text_range.contains_range(t.text_range()) | 
 |                                             }); | 
 |                                             return process_expansion_for_token( | 
 |                                                 &mut stack, call_id, | 
 |                                             ); | 
 |                                         } | 
 |                                         None => Some(adt), | 
 |                                     } | 
 |                                 } | 
 |                                 None => { | 
 |                                     // Otherwise this could be a derive helper on a variant or field | 
 |                                     attr.syntax().ancestors().find_map(ast::Item::cast).and_then( | 
 |                                         |it| match it { | 
 |                                             ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), | 
 |                                             ast::Item::Enum(it) => Some(ast::Adt::Enum(it)), | 
 |                                             ast::Item::Union(it) => Some(ast::Adt::Union(it)), | 
 |                                             _ => None, | 
 |                                         }, | 
 |                                     ) | 
 |                                 } | 
 |                             }?; | 
 |                             if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(expansion, &adt))) { | 
 |                                 return None; | 
 |                             } | 
 |                             let attr_name = | 
 |                                 attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); | 
 |                             // Not an attribute, nor a derive, so it's either an intert attribute or a derive helper | 
 |                             // Try to resolve to a derive helper and downmap | 
 |                             let resolver = &token | 
 |                                 .parent() | 
 |                                 .and_then(|parent| { | 
 |                                     self.analyze_impl(InFile::new(expansion, &parent), None, false) | 
 |                                 })? | 
 |                                 .resolver; | 
 |                             let id = self.db.ast_id_map(expansion).ast_id(&adt); | 
 |                             let helpers = resolver | 
 |                                 .def_map() | 
 |                                 .derive_helpers_in_scope(InFile::new(expansion, id))?; | 
 |  | 
 |                             if !helpers.is_empty() { | 
 |                                 let text_range = attr.syntax().text_range(); | 
 |                                 filter_duplicates(tokens, text_range); | 
 |                             } | 
 |  | 
 |                             let mut res = None; | 
 |                             for (.., derive) in | 
 |                                 helpers.iter().filter(|(helper, ..)| *helper == attr_name) | 
 |                             { | 
 |                                 // as there may be multiple derives registering the same helper | 
 |                                 // name, we gotta make sure to call this for all of them! | 
 |                                 // FIXME: We need to call `f` for all of them as well though! | 
 |                                 res = res.or(process_expansion_for_token(&mut stack, *derive)); | 
 |                             } | 
 |                             res | 
 |                         } | 
 |                     } | 
 |                 })() | 
 |                 .is_none(); | 
 |  | 
 |                 if was_not_remapped { | 
 |                     if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) { | 
 |                         return Some(b); | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         None | 
 |     } | 
 |  | 
 |     // Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop | 
 |     // traversing the inner iterator when it finds a node. | 
 |     // The outer iterator is over the tokens descendants | 
 |     // The inner iterator is the ancestors of a descendant | 
 |     fn descend_node_at_offset( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ { | 
 |         node.token_at_offset(offset) | 
 |             .map(move |token| self.descend_into_macros_exact(token)) | 
 |             .map(|descendants| { | 
 |                 descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it)) | 
 |             }) | 
 |             // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first | 
 |             // See algo::ancestors_at_offset, which uses the same approach | 
 |             .kmerge_by(|left, right| { | 
 |                 left.clone() | 
 |                     .map(|node| node.text_range().len()) | 
 |                     .lt(right.clone().map(|node| node.text_range().len())) | 
 |             }) | 
 |     } | 
 |  | 
 |     /// Attempts to map the node out of macro expanded files returning the original file range. | 
 |     /// If upmapping is not possible, this will fall back to the range of the macro call of the | 
 |     /// macro file the node resides in. | 
 |     pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | 
 |         let node = self.find_file(node); | 
 |         node.original_file_range_rooted(self.db) | 
 |     } | 
 |  | 
 |     /// Attempts to map the node out of macro expanded files returning the original file range. | 
 |     pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> { | 
 |         let node = self.find_file(node); | 
 |         node.original_file_range_opt(self.db).filter(|(_, ctx)| ctx.is_root()).map(TupleExt::head) | 
 |     } | 
 |  | 
 |     /// Attempts to map the node out of macro expanded files. | 
 |     /// This only work for attribute expansions, as other ones do not have nodes as input. | 
 |     pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> { | 
 |         self.wrap_node_infile(node).original_ast_node_rooted(self.db).map( | 
 |             |InRealFile { file_id, value }| { | 
 |                 self.cache(find_root(value.syntax()), file_id.into()); | 
 |                 value | 
 |             }, | 
 |         ) | 
 |     } | 
 |  | 
 |     /// Attempts to map the node out of macro expanded files. | 
 |     /// This only work for attribute expansions, as other ones do not have nodes as input. | 
 |     pub fn original_syntax_node_rooted(&self, node: &SyntaxNode) -> Option<SyntaxNode> { | 
 |         let InFile { file_id, .. } = self.find_file(node); | 
 |         InFile::new(file_id, node).original_syntax_node_rooted(self.db).map( | 
 |             |InRealFile { file_id, value }| { | 
 |                 self.cache(find_root(&value), file_id.into()); | 
 |                 value | 
 |             }, | 
 |         ) | 
 |     } | 
 |  | 
 |     pub fn diagnostics_display_range( | 
 |         &self, | 
 |         src: InFile<SyntaxNodePtr>, | 
 |     ) -> FileRangeWrapper<FileId> { | 
 |         let root = self.parse_or_expand(src.file_id); | 
 |         let node = src.map(|it| it.to_node(&root)); | 
 |         let FileRange { file_id, range } = node.as_ref().original_file_range_rooted(self.db); | 
 |         FileRangeWrapper { file_id: file_id.file_id(self.db), range } | 
 |     } | 
 |  | 
 |     fn token_ancestors_with_macros( | 
 |         &self, | 
 |         token: SyntaxToken, | 
 |     ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ { | 
 |         token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent)) | 
 |     } | 
 |  | 
 |     /// Iterates the ancestors of the given node, climbing up macro expansions while doing so. | 
 |     pub fn ancestors_with_macros( | 
 |         &self, | 
 |         node: SyntaxNode, | 
 |     ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ { | 
 |         let node = self.find_file(&node); | 
 |         iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| { | 
 |             match value.parent() { | 
 |                 Some(parent) => Some(InFile::new(file_id, parent)), | 
 |                 None => { | 
 |                     let macro_file = file_id.macro_file()?; | 
 |  | 
 |                     self.with_ctx(|ctx| { | 
 |                         let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | 
 |                         expansion_info.arg().map(|node| node?.parent()).transpose() | 
 |                     }) | 
 |                 } | 
 |             } | 
 |         }) | 
 |         .map(|it| it.value) | 
 |     } | 
 |  | 
 |     pub fn ancestors_at_offset_with_macros( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> impl Iterator<Item = SyntaxNode> + '_ { | 
 |         node.token_at_offset(offset) | 
 |             .map(|token| self.token_ancestors_with_macros(token)) | 
 |             .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 
 |     } | 
 |  | 
 |     pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> { | 
 |         let text = lifetime.text(); | 
 |         let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| { | 
 |             let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?; | 
 |             gpl.lifetime_params() | 
 |                 .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text)) | 
 |         })?; | 
 |         let src = self.wrap_node_infile(lifetime_param); | 
 |         ToDef::to_def(self, src.as_ref()) | 
 |     } | 
 |  | 
 |     pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> { | 
 |         let src = self.wrap_node_infile(label.clone()); | 
 |         let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?; | 
 |         Some(Label { parent, label_id }) | 
 |     } | 
 |  | 
 |     pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { | 
 |         let analyze = self.analyze(ty.syntax())?; | 
 |         analyze.type_of_type(self.db, ty) | 
 |     } | 
 |  | 
 |     pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> { | 
 |         let parent_ty = path.syntax().parent().and_then(ast::Type::cast)?; | 
 |         let analyze = self.analyze(path.syntax())?; | 
 |         let ty = analyze.store_sm()?.node_type(InFile::new(analyze.file_id, &parent_ty))?; | 
 |         let path = match &analyze.store()?.types[ty] { | 
 |             hir_def::type_ref::TypeRef::Path(path) => path, | 
 |             _ => return None, | 
 |         }; | 
 |         match analyze.resolver.resolve_path_in_type_ns_fully(self.db, path)? { | 
 |             TypeNs::TraitId(trait_id) => Some(trait_id.into()), | 
 |             _ => None, | 
 |         } | 
 |     } | 
 |  | 
 |     pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> { | 
 |         let mutability = |m| match m { | 
 |             hir_ty::Mutability::Not => Mutability::Shared, | 
 |             hir_ty::Mutability::Mut => Mutability::Mut, | 
 |         }; | 
 |  | 
 |         let analyzer = self.analyze(expr.syntax())?; | 
 |  | 
 |         let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?; | 
 |  | 
 |         analyzer.expr_adjustments(expr).map(|it| { | 
 |             it.iter() | 
 |                 .map(|adjust| { | 
 |                     let target = | 
 |                         Type::new_with_resolver(self.db, &analyzer.resolver, adjust.target.clone()); | 
 |                     let kind = match adjust.kind { | 
 |                         hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, | 
 |                         hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { | 
 |                             // FIXME: Should we handle unknown mutability better? | 
 |                             Adjust::Deref(Some(OverloadedDeref( | 
 |                                 m.map(mutability).unwrap_or(Mutability::Shared), | 
 |                             ))) | 
 |                         } | 
 |                         hir_ty::Adjust::Deref(None) => Adjust::Deref(None), | 
 |                         hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { | 
 |                             Adjust::Borrow(AutoBorrow::RawPtr(mutability(m))) | 
 |                         } | 
 |                         hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(_, m)) => { | 
 |                             // FIXME: Handle lifetimes here | 
 |                             Adjust::Borrow(AutoBorrow::Ref(mutability(m))) | 
 |                         } | 
 |                         hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc), | 
 |                     }; | 
 |  | 
 |                     // Update `source_ty` for the next adjustment | 
 |                     let source = mem::replace(&mut source_ty, target.clone()); | 
 |  | 
 |                     Adjustment { source, target, kind } | 
 |                 }) | 
 |                 .collect() | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> { | 
 |         self.analyze(expr.syntax())? | 
 |             .type_of_expr(self.db, expr) | 
 |             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) | 
 |     } | 
 |  | 
 |     pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> { | 
 |         self.analyze(pat.syntax())? | 
 |             .type_of_pat(self.db, pat) | 
 |             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) | 
 |     } | 
 |  | 
 |     /// It also includes the changes that binding mode makes in the type. For example in | 
 |     /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result | 
 |     /// of this function is `&mut Option<T>` | 
 |     pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> { | 
 |         self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat) | 
 |     } | 
 |  | 
 |     pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { | 
 |         self.analyze(param.syntax())?.type_of_self(self.db, param) | 
 |     } | 
 |  | 
 |     pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> { | 
 |         self.analyze(pat.syntax()) | 
 |             .and_then(|it| it.pattern_adjustments(self.db, pat)) | 
 |             .unwrap_or_default() | 
 |     } | 
 |  | 
 |     pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> { | 
 |         self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat) | 
 |     } | 
 |  | 
 |     pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable> { | 
 |         self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call) | 
 |     } | 
 |  | 
 |     pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 
 |         self.analyze(call.syntax())?.resolve_method_call(self.db, call) | 
 |     } | 
 |  | 
 |     /// Attempts to resolve this call expression as a method call falling back to resolving it as a field. | 
 |     pub fn resolve_method_call_fallback( | 
 |         &self, | 
 |         call: &ast::MethodCallExpr, | 
 |     ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> { | 
 |         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) | 
 |     } | 
 |  | 
 |     /// Env is used to derive the trait environment | 
 |     // FIXME: better api for the trait environment | 
 |     pub fn resolve_trait_impl_method( | 
 |         &self, | 
 |         env: Type, | 
 |         trait_: Trait, | 
 |         func: Function, | 
 |         subst: impl IntoIterator<Item = Type>, | 
 |     ) -> Option<Function> { | 
 |         let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None); | 
 |         for s in subst { | 
 |             substs = substs.push(s.ty); | 
 |         } | 
 |         Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into()) | 
 |     } | 
 |  | 
 |     fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> { | 
 |         self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat) | 
 |     } | 
 |  | 
 |     fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> { | 
 |         self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr) | 
 |     } | 
 |  | 
 |     fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> { | 
 |         self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) | 
 |     } | 
 |  | 
 |     fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> { | 
 |         self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) | 
 |     } | 
 |  | 
 |     fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> { | 
 |         self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) | 
 |     } | 
 |  | 
 |     fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> { | 
 |         self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) | 
 |     } | 
 |  | 
 |     fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> { | 
 |         self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) | 
 |     } | 
 |  | 
 |     // This does not resolve the method call to the correct trait impl! | 
 |     // We should probably fix that. | 
 |     pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { | 
 |         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) | 
 |     } | 
 |  | 
 |     pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Either<Field, TupleField>> { | 
 |         self.analyze(field.syntax())?.resolve_field(field) | 
 |     } | 
 |  | 
 |     pub fn resolve_field_fallback( | 
 |         &self, | 
 |         field: &ast::FieldExpr, | 
 |     ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> { | 
 |         self.analyze(field.syntax())?.resolve_field_fallback(self.db, field) | 
 |     } | 
 |  | 
 |     pub fn resolve_record_field( | 
 |         &self, | 
 |         field: &ast::RecordExprField, | 
 |     ) -> Option<(Field, Option<Local>, Type)> { | 
 |         self.resolve_record_field_with_substitution(field) | 
 |             .map(|(field, local, ty, _)| (field, local, ty)) | 
 |     } | 
 |  | 
 |     pub fn resolve_record_field_with_substitution( | 
 |         &self, | 
 |         field: &ast::RecordExprField, | 
 |     ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> { | 
 |         self.analyze(field.syntax())?.resolve_record_field(self.db, field) | 
 |     } | 
 |  | 
 |     pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { | 
 |         self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty)) | 
 |     } | 
 |  | 
 |     pub fn resolve_record_pat_field_with_subst( | 
 |         &self, | 
 |         field: &ast::RecordPatField, | 
 |     ) -> Option<(Field, Type, GenericSubstitution)> { | 
 |         self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field) | 
 |     } | 
 |  | 
 |     // FIXME: Replace this with `resolve_macro_call2` | 
 |     pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> { | 
 |         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); | 
 |         self.resolve_macro_call2(macro_call) | 
 |     } | 
 |  | 
 |     pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option<Macro> { | 
 |         self.with_ctx(|ctx| { | 
 |             ctx.macro_call_to_macro_call(macro_call) | 
 |                 .and_then(|call| macro_call_to_macro_id(ctx, call)) | 
 |                 .map(Into::into) | 
 |         }) | 
 |         .or_else(|| { | 
 |             self.analyze(macro_call.value.syntax())?.resolve_macro_call(self.db, macro_call) | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool { | 
 |         self.resolve_macro_call2(macro_call) | 
 |             .is_some_and(|m| matches!(m.id, MacroId::ProcMacroId(..))) | 
 |     } | 
 |  | 
 |     pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> { | 
 |         let sa = self.analyze(macro_call.syntax())?; | 
 |         self.db | 
 |             .parse_macro_expansion( | 
 |                 sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, | 
 |             ) | 
 |             .value | 
 |             .1 | 
 |             .matched_arm | 
 |     } | 
 |  | 
 |     pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> { | 
 |         let def = DefWithBodyId::from(def); | 
 |         let (body, source_map) = self.db.body_with_source_map(def); | 
 |         let infer = self.db.infer(def); | 
 |         let mut res = FxHashSet::default(); | 
 |         unsafe_operations_for_body(self.db, &infer, def, &body, &mut |node| { | 
 |             if let Ok(node) = source_map.expr_or_pat_syntax(node) { | 
 |                 res.insert(node); | 
 |             } | 
 |         }); | 
 |         res | 
 |     } | 
 |  | 
 |     pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool { | 
 |         let Some(mac) = self.resolve_macro_call(macro_call) else { return false }; | 
 |         if mac.is_asm_or_global_asm(self.db) { | 
 |             return true; | 
 |         } | 
 |  | 
 |         let Some(sa) = self.analyze(macro_call.syntax()) else { return false }; | 
 |         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); | 
 |         match macro_call.map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast)).transpose() { | 
 |             Some(it) => sa.is_unsafe_macro_call_expr(self.db, it.as_ref()), | 
 |             None => false, | 
 |         } | 
 |     } | 
 |  | 
 |     pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> { | 
 |         let item_in_file = self.wrap_node_infile(item.clone()); | 
 |         let id = self.with_ctx(|ctx| { | 
 |             let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?; | 
 |             macro_call_to_macro_id(ctx, macro_call_id) | 
 |         })?; | 
 |         Some(Macro { id }) | 
 |     } | 
 |  | 
 |     pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { | 
 |         self.resolve_path_with_subst(path).map(|(it, _)| it) | 
 |     } | 
 |  | 
 |     pub fn resolve_path_with_subst( | 
 |         &self, | 
 |         path: &ast::Path, | 
 |     ) -> Option<(PathResolution, Option<GenericSubstitution>)> { | 
 |         self.analyze(path.syntax())?.resolve_path(self.db, path) | 
 |     } | 
 |  | 
 |     pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<TypeParam> { | 
 |         self.analyze(name.syntax())?.resolve_use_type_arg(name) | 
 |     } | 
 |  | 
 |     pub fn resolve_mod_path( | 
 |         &self, | 
 |         scope: &SyntaxNode, | 
 |         path: &ModPath, | 
 |     ) -> Option<impl Iterator<Item = ItemInNs>> { | 
 |         let analyze = self.analyze(scope)?; | 
 |         let items = analyze.resolver.resolve_module_path_in_items(self.db, path); | 
 |         Some(items.iter_items().map(|(item, _)| item.into())) | 
 |     } | 
 |  | 
 |     fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { | 
 |         self.analyze(record_lit.syntax())?.resolve_variant(record_lit) | 
 |     } | 
 |  | 
 |     pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> { | 
 |         self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat) | 
 |     } | 
 |  | 
 |     pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { | 
 |         self.analyze(literal.syntax()) | 
 |             .and_then(|it| it.record_literal_missing_fields(self.db, literal)) | 
 |             .unwrap_or_default() | 
 |     } | 
 |  | 
 |     pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { | 
 |         self.analyze(pattern.syntax()) | 
 |             .and_then(|it| it.record_pattern_missing_fields(self.db, pattern)) | 
 |             .unwrap_or_default() | 
 |     } | 
 |  | 
 |     fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T { | 
 |         let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() }; | 
 |         f(&mut ctx) | 
 |     } | 
 |  | 
 |     pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { | 
 |         let src = self.find_file(src.syntax()).with_value(src); | 
 |         T::to_def(self, src) | 
 |     } | 
 |  | 
 |     fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> { | 
 |         self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from) | 
 |     } | 
 |  | 
 |     pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> { | 
 |         self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { | 
 |             db: self.db, | 
 |             file_id, | 
 |             resolver, | 
 |         }) | 
 |     } | 
 |  | 
 |     pub fn scope_at_offset( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> Option<SemanticsScope<'db>> { | 
 |         self.analyze_with_offset_no_infer(node, offset).map( | 
 |             |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { | 
 |                 db: self.db, | 
 |                 file_id, | 
 |                 resolver, | 
 |             }, | 
 |         ) | 
 |     } | 
 |  | 
 |     /// Search for a definition's source and cache its syntax tree | 
 |     pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> | 
 |     where | 
 |         Def::Ast: AstNode, | 
 |     { | 
 |         // FIXME: source call should go through the parse cache | 
 |         let res = def.source(self.db)?; | 
 |         self.cache(find_root(res.value.syntax()), res.file_id); | 
 |         Some(res) | 
 |     } | 
 |  | 
 |     pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> { | 
 |         let container = self.with_ctx(|ctx| ctx.find_container(node))?; | 
 |  | 
 |         match container { | 
 |             ChildContainer::DefWithBodyId(def) => Some(def.into()), | 
 |             _ => None, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns none if the file of the node is not part of a crate. | 
 |     fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> { | 
 |         let node = self.find_file(node); | 
 |         self.analyze_impl(node, None, true) | 
 |     } | 
 |  | 
 |     /// Returns none if the file of the node is not part of a crate. | 
 |     fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> { | 
 |         let node = self.find_file(node); | 
 |         self.analyze_impl(node, None, false) | 
 |     } | 
 |  | 
 |     fn analyze_with_offset_no_infer( | 
 |         &self, | 
 |         node: &SyntaxNode, | 
 |         offset: TextSize, | 
 |     ) -> Option<SourceAnalyzer> { | 
 |         let node = self.find_file(node); | 
 |         self.analyze_impl(node, Some(offset), false) | 
 |     } | 
 |  | 
 |     fn analyze_impl( | 
 |         &self, | 
 |         node: InFile<&SyntaxNode>, | 
 |         offset: Option<TextSize>, | 
 |         // replace this, just make the inference result a `LazyCell` | 
 |         infer_body: bool, | 
 |     ) -> Option<SourceAnalyzer> { | 
 |         let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered(); | 
 |  | 
 |         let container = self.with_ctx(|ctx| ctx.find_container(node))?; | 
 |  | 
 |         let resolver = match container { | 
 |             ChildContainer::DefWithBodyId(def) => { | 
 |                 return Some(if infer_body { | 
 |                     SourceAnalyzer::new_for_body(self.db, def, node, offset) | 
 |                 } else { | 
 |                     SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset) | 
 |                 }); | 
 |             } | 
 |             ChildContainer::VariantId(def) => { | 
 |                 return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset)); | 
 |             } | 
 |             ChildContainer::TraitId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); | 
 |             } | 
 |             ChildContainer::TraitAliasId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); | 
 |             } | 
 |             ChildContainer::ImplId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); | 
 |             } | 
 |             ChildContainer::EnumId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); | 
 |             } | 
 |             ChildContainer::TypeAliasId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); | 
 |             } | 
 |             ChildContainer::GenericDefId(it) => { | 
 |                 return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset)); | 
 |             } | 
 |             ChildContainer::ModuleId(it) => it.resolver(self.db), | 
 |         }; | 
 |         Some(SourceAnalyzer::new_for_resolver(resolver, node)) | 
 |     } | 
 |  | 
 |     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { | 
 |         SourceToDefCache::cache( | 
 |             &mut self.s2d_cache.borrow_mut().root_to_file_cache, | 
 |             root_node, | 
 |             file_id, | 
 |         ); | 
 |     } | 
 |  | 
 |     pub fn assert_contains_node(&self, node: &SyntaxNode) { | 
 |         self.find_file(node); | 
 |     } | 
 |  | 
 |     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> { | 
 |         let cache = self.s2d_cache.borrow(); | 
 |         cache.root_to_file_cache.get(root_node).copied() | 
 |     } | 
 |  | 
 |     fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> { | 
 |         let InFile { file_id, .. } = self.find_file(node.syntax()); | 
 |         InFile::new(file_id, node) | 
 |     } | 
 |  | 
 |     fn wrap_token_infile(&self, token: SyntaxToken) -> InFile<SyntaxToken> { | 
 |         let InFile { file_id, .. } = self.find_file(&token.parent().unwrap()); | 
 |         InFile::new(file_id, token) | 
 |     } | 
 |  | 
 |     /// Wraps the node in a [`InFile`] with the file id it belongs to. | 
 |     fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> { | 
 |         let root_node = find_root(node); | 
 |         let file_id = self.lookup(&root_node).unwrap_or_else(|| { | 
 |             panic!( | 
 |                 "\n\nFailed to lookup {:?} in this Semantics.\n\ | 
 |                  Make sure to only query nodes derived from this instance of Semantics.\n\ | 
 |                  root node:   {:?}\n\ | 
 |                  known nodes: {}\n\n", | 
 |                 node, | 
 |                 root_node, | 
 |                 self.s2d_cache | 
 |                     .borrow() | 
 |                     .root_to_file_cache | 
 |                     .keys() | 
 |                     .map(|it| format!("{it:?}")) | 
 |                     .collect::<Vec<_>>() | 
 |                     .join(", ") | 
 |             ) | 
 |         }); | 
 |         InFile::new(file_id, node) | 
 |     } | 
 |  | 
 |     /// Returns `true` if the `node` is inside an `unsafe` context. | 
 |     pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool { | 
 |         let Some(enclosing_item) = | 
 |             expr.syntax().ancestors().find_map(Either::<ast::Item, ast::Variant>::cast) | 
 |         else { | 
 |             return false; | 
 |         }; | 
 |  | 
 |         let def = match &enclosing_item { | 
 |             Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true, | 
 |             Either::Left(ast::Item::Fn(it)) => { | 
 |                 self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId) | 
 |             } | 
 |             Either::Left(ast::Item::Const(it)) => { | 
 |                 self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId) | 
 |             } | 
 |             Either::Left(ast::Item::Static(it)) => { | 
 |                 self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId) | 
 |             } | 
 |             Either::Left(_) => None, | 
 |             Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId), | 
 |         }; | 
 |         let Some(def) = def else { return false }; | 
 |         let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax()); | 
 |  | 
 |         let (body, source_map) = self.db.body_with_source_map(def); | 
 |  | 
 |         let file_id = self.find_file(expr.syntax()).file_id; | 
 |  | 
 |         let Some(mut parent) = expr.syntax().parent() else { return false }; | 
 |         loop { | 
 |             if &parent == enclosing_node { | 
 |                 break false; | 
 |             } | 
 |  | 
 |             if let Some(parent) = ast::Expr::cast(parent.clone()) { | 
 |                 if let Some(ExprOrPatId::ExprId(expr_id)) = | 
 |                     source_map.node_expr(InFile { file_id, value: &parent }) | 
 |                 { | 
 |                     if let Expr::Unsafe { .. } = body[expr_id] { | 
 |                         break true; | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             let Some(parent_) = parent.parent() else { break false }; | 
 |             parent = parent_; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | // FIXME This can't be the best way to do this | 
 | fn macro_call_to_macro_id( | 
 |     ctx: &mut SourceToDefCtx<'_, '_>, | 
 |     macro_call_id: MacroCallId, | 
 | ) -> Option<MacroId> { | 
 |     let db: &dyn ExpandDatabase = ctx.db; | 
 |     let loc = db.lookup_intern_macro_call(macro_call_id); | 
 |  | 
 |     match loc.def.ast_id() { | 
 |         Either::Left(it) => { | 
 |             let node = match it.file_id { | 
 |                 HirFileId::FileId(file_id) => { | 
 |                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) | 
 |                 } | 
 |                 HirFileId::MacroFile(macro_file) => { | 
 |                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | 
 |                     it.to_ptr(db).to_node(&expansion_info.expanded().value) | 
 |                 } | 
 |             }; | 
 |             ctx.macro_to_def(InFile::new(it.file_id, &node)) | 
 |         } | 
 |         Either::Right(it) => { | 
 |             let node = match it.file_id { | 
 |                 HirFileId::FileId(file_id) => { | 
 |                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) | 
 |                 } | 
 |                 HirFileId::MacroFile(macro_file) => { | 
 |                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | 
 |                     it.to_ptr(db).to_node(&expansion_info.expanded().value) | 
 |                 } | 
 |             }; | 
 |             ctx.proc_macro_to_def(InFile::new(it.file_id, &node)) | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | pub trait ToDef: AstNode + Clone { | 
 |     type Def; | 
 |     fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option<Self::Def>; | 
 | } | 
 |  | 
 | macro_rules! to_def_impls { | 
 |     ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( | 
 |         impl ToDef for $ast { | 
 |             type Def = $def; | 
 |             fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option<Self::Def> { | 
 |                 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) | 
 |             } | 
 |         } | 
 |     )*} | 
 | } | 
 |  | 
 | to_def_impls![ | 
 |     (crate::Module, ast::Module, module_to_def), | 
 |     (crate::Module, ast::SourceFile, source_file_to_def), | 
 |     (crate::Struct, ast::Struct, struct_to_def), | 
 |     (crate::Enum, ast::Enum, enum_to_def), | 
 |     (crate::Union, ast::Union, union_to_def), | 
 |     (crate::Trait, ast::Trait, trait_to_def), | 
 |     (crate::TraitAlias, ast::TraitAlias, trait_alias_to_def), | 
 |     (crate::Impl, ast::Impl, impl_to_def), | 
 |     (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), | 
 |     (crate::Const, ast::Const, const_to_def), | 
 |     (crate::Static, ast::Static, static_to_def), | 
 |     (crate::Function, ast::Fn, fn_to_def), | 
 |     (crate::Field, ast::RecordField, record_field_to_def), | 
 |     (crate::Field, ast::TupleField, tuple_field_to_def), | 
 |     (crate::Variant, ast::Variant, enum_variant_to_def), | 
 |     (crate::TypeParam, ast::TypeParam, type_param_to_def), | 
 |     (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 
 |     (crate::ConstParam, ast::ConstParam, const_param_to_def), | 
 |     (crate::GenericParam, ast::GenericParam, generic_param_to_def), | 
 |     (crate::Macro, ast::Macro, macro_to_def), | 
 |     (crate::Local, ast::IdentPat, bind_pat_to_def), | 
 |     (crate::Local, ast::SelfParam, self_param_to_def), | 
 |     (crate::Label, ast::Label, label_to_def), | 
 |     (crate::Adt, ast::Adt, adt_to_def), | 
 |     (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), | 
 |     (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def), | 
 |     (crate::ExternBlock, ast::ExternBlock, extern_block_to_def), | 
 |     (MacroCallId, ast::MacroCall, macro_call_to_macro_call), | 
 | ]; | 
 |  | 
 | fn find_root(node: &SyntaxNode) -> SyntaxNode { | 
 |     node.ancestors().last().unwrap() | 
 | } | 
 |  | 
 | /// `SemanticsScope` encapsulates the notion of a scope (the set of visible | 
 | /// names) at a particular program point. | 
 | /// | 
 | /// It is a bit tricky, as scopes do not really exist inside the compiler. | 
 | /// Rather, the compiler directly computes for each reference the definition it | 
 | /// refers to. It might transiently compute the explicit scope map while doing | 
 | /// so, but, generally, this is not something left after the analysis. | 
 | /// | 
 | /// However, we do very much need explicit scopes for IDE purposes -- | 
 | /// completion, at its core, lists the contents of the current scope. The notion | 
 | /// of scope is also useful to answer questions like "what would be the meaning | 
 | /// of this piece of code if we inserted it into this position?". | 
 | /// | 
 | /// So `SemanticsScope` is constructed from a specific program point (a syntax | 
 | /// node or just a raw offset) and provides access to the set of visible names | 
 | /// on a somewhat best-effort basis. | 
 | /// | 
 | /// Note that if you are wondering "what does this specific existing name mean?", | 
 | /// you'd better use the `resolve_` family of methods. | 
 | #[derive(Debug)] | 
 | pub struct SemanticsScope<'a> { | 
 |     pub db: &'a dyn HirDatabase, | 
 |     file_id: HirFileId, | 
 |     resolver: Resolver, | 
 | } | 
 |  | 
 | impl SemanticsScope<'_> { | 
 |     pub fn module(&self) -> Module { | 
 |         Module { id: self.resolver.module() } | 
 |     } | 
 |  | 
 |     pub fn krate(&self) -> Crate { | 
 |         Crate { id: self.resolver.krate() } | 
 |     } | 
 |  | 
 |     pub fn containing_function(&self) -> Option<Function> { | 
 |         self.resolver.body_owner().and_then(|owner| match owner { | 
 |             DefWithBodyId::FunctionId(id) => Some(id.into()), | 
 |             _ => None, | 
 |         }) | 
 |     } | 
 |  | 
 |     pub(crate) fn resolver(&self) -> &Resolver { | 
 |         &self.resolver | 
 |     } | 
 |  | 
 |     /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type | 
 |     pub fn visible_traits(&self) -> VisibleTraits { | 
 |         let resolver = &self.resolver; | 
 |         VisibleTraits(resolver.traits_in_scope(self.db)) | 
 |     } | 
 |  | 
 |     /// Calls the passed closure `f` on all names in scope. | 
 |     pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { | 
 |         let scope = self.resolver.names_in_scope(self.db); | 
 |         for (name, entries) in scope { | 
 |             for entry in entries { | 
 |                 let def = match entry { | 
 |                     resolver::ScopeDef::ModuleDef(it) => ScopeDef::ModuleDef(it.into()), | 
 |                     resolver::ScopeDef::Unknown => ScopeDef::Unknown, | 
 |                     resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), | 
 |                     resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), | 
 |                     resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), | 
 |                     resolver::ScopeDef::Local(binding_id) => match self.resolver.body_owner() { | 
 |                         Some(parent) => ScopeDef::Local(Local { parent, binding_id }), | 
 |                         None => continue, | 
 |                     }, | 
 |                     resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() { | 
 |                         Some(parent) => ScopeDef::Label(Label { parent, label_id }), | 
 |                         None => continue, | 
 |                     }, | 
 |                 }; | 
 |                 f(name.clone(), def) | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /// Resolve a path as-if it was written at the given scope. This is | 
 |     /// necessary a heuristic, as it doesn't take hygiene into account. | 
 |     pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> { | 
 |         let mut kind = PathKind::Plain; | 
 |         let mut segments = vec![]; | 
 |         let mut first = true; | 
 |         for segment in ast_path.segments() { | 
 |             if first { | 
 |                 first = false; | 
 |                 if segment.coloncolon_token().is_some() { | 
 |                     kind = PathKind::Abs; | 
 |                 } | 
 |             } | 
 |  | 
 |             let Some(k) = segment.kind() else { continue }; | 
 |             match k { | 
 |                 ast::PathSegmentKind::Name(name_ref) => segments.push(name_ref.as_name()), | 
 |                 ast::PathSegmentKind::Type { .. } => continue, | 
 |                 ast::PathSegmentKind::SelfTypeKw => { | 
 |                     segments.push(Name::new_symbol_root(sym::Self_.clone())) | 
 |                 } | 
 |                 ast::PathSegmentKind::SelfKw => kind = PathKind::Super(0), | 
 |                 ast::PathSegmentKind::SuperKw => match kind { | 
 |                     PathKind::Super(s) => kind = PathKind::Super(s + 1), | 
 |                     PathKind::Plain => kind = PathKind::Super(1), | 
 |                     PathKind::Crate | PathKind::Abs | PathKind::DollarCrate(_) => continue, | 
 |                 }, | 
 |                 ast::PathSegmentKind::CrateKw => kind = PathKind::Crate, | 
 |             } | 
 |         } | 
 |  | 
 |         resolve_hir_path( | 
 |             self.db, | 
 |             &self.resolver, | 
 |             &Path::BarePath(Interned::new(ModPath::from_segments(kind, segments))), | 
 |             name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())), | 
 |             None, | 
 |         ) | 
 |     } | 
 |  | 
 |     pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> + use<> { | 
 |         let items = self.resolver.resolve_module_path_in_items(self.db, path); | 
 |         items.iter_items().map(|(item, _)| item.into()) | 
 |     } | 
 |  | 
 |     /// Iterates over associated types that may be specified after the given path (using | 
 |     /// `Ty::Assoc` syntax). | 
 |     pub fn assoc_type_shorthand_candidates<R>( | 
 |         &self, | 
 |         resolution: &PathResolution, | 
 |         mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>, | 
 |     ) -> Option<R> { | 
 |         let def = self.resolver.generic_def()?; | 
 |         hir_ty::associated_type_shorthand_candidates( | 
 |             self.db, | 
 |             def, | 
 |             resolution.in_type_ns()?, | 
 |             |name, id| cb(name, id.into()), | 
 |         ) | 
 |     } | 
 |  | 
 |     pub fn generic_def(&self) -> Option<crate::GenericDef> { | 
 |         self.resolver.generic_def().map(|id| id.into()) | 
 |     } | 
 |  | 
 |     pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ { | 
 |         self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id })) | 
 |     } | 
 |  | 
 |     pub fn extern_crate_decls(&self) -> impl Iterator<Item = Name> + '_ { | 
 |         self.resolver.extern_crate_decls_in_scope(self.db) | 
 |     } | 
 |  | 
 |     pub fn has_same_self_type(&self, other: &SemanticsScope<'_>) -> bool { | 
 |         self.resolver.impl_def() == other.resolver.impl_def() | 
 |     } | 
 | } | 
 |  | 
 | #[derive(Debug)] | 
 | pub struct VisibleTraits(pub FxHashSet<TraitId>); | 
 |  | 
 | impl ops::Deref for VisibleTraits { | 
 |     type Target = FxHashSet<TraitId>; | 
 |  | 
 |     fn deref(&self) -> &Self::Target { | 
 |         &self.0 | 
 |     } | 
 | } | 
 |  | 
 | struct RenameConflictsVisitor<'a> { | 
 |     db: &'a dyn HirDatabase, | 
 |     owner: DefWithBodyId, | 
 |     resolver: Resolver, | 
 |     body: &'a Body, | 
 |     to_be_renamed: BindingId, | 
 |     new_name: Symbol, | 
 |     old_name: Symbol, | 
 |     conflicts: FxHashSet<BindingId>, | 
 | } | 
 |  | 
 | impl RenameConflictsVisitor<'_> { | 
 |     fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) { | 
 |         if let Path::BarePath(path) = path { | 
 |             if let Some(name) = path.as_ident() { | 
 |                 if *name.symbol() == self.new_name { | 
 |                     if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed( | 
 |                         self.db, | 
 |                         name, | 
 |                         path, | 
 |                         self.body.expr_or_pat_path_hygiene(node), | 
 |                         self.to_be_renamed, | 
 |                     ) { | 
 |                         self.conflicts.insert(conflicting); | 
 |                     } | 
 |                 } else if *name.symbol() == self.old_name { | 
 |                     if let Some(conflicting) = | 
 |                         self.resolver.rename_will_conflict_with_another_variable( | 
 |                             self.db, | 
 |                             name, | 
 |                             path, | 
 |                             self.body.expr_or_pat_path_hygiene(node), | 
 |                             &self.new_name, | 
 |                             self.to_be_renamed, | 
 |                         ) | 
 |                     { | 
 |                         self.conflicts.insert(conflicting); | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     fn rename_conflicts(&mut self, expr: ExprId) { | 
 |         match &self.body[expr] { | 
 |             Expr::Path(path) => { | 
 |                 let guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr); | 
 |                 self.resolve_path(expr.into(), path); | 
 |                 self.resolver.reset_to_guard(guard); | 
 |             } | 
 |             &Expr::Assignment { target, .. } => { | 
 |                 let guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr); | 
 |                 self.body.walk_pats(target, &mut |pat| { | 
 |                     if let Pat::Path(path) = &self.body[pat] { | 
 |                         self.resolve_path(pat.into(), path); | 
 |                     } | 
 |                 }); | 
 |                 self.resolver.reset_to_guard(guard); | 
 |             } | 
 |             _ => {} | 
 |         } | 
 |  | 
 |         self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr)); | 
 |     } | 
 | } |