mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Auto merge of #142567 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
		
						commit
						01ccbcf4a8
					
				
					 131 changed files with 4777 additions and 3492 deletions
				
			
		|  | @ -18,6 +18,7 @@ extend-ignore-re = [ | |||
|     "INOUT", | ||||
|     "optin", | ||||
|     "=Pn", | ||||
|     "\\[[0-9A-F]{4},",  # AstId hex hashes | ||||
|     # ignore `// spellchecker:off` until `// spellchecker:on` | ||||
|     "(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on", | ||||
| ] | ||||
|  |  | |||
							
								
								
									
										567
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										567
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										44
									
								
								Cargo.toml
									
										
									
									
									
								
							
							
						
						
									
										44
									
								
								Cargo.toml
									
										
									
									
									
								
							|  | @ -87,11 +87,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } | |||
| vfs = { path = "./crates/vfs", version = "0.0.0" } | ||||
| edition = { path = "./crates/edition", version = "0.0.0" } | ||||
| 
 | ||||
| ra-ap-rustc_lexer = { version = "0.113", default-features = false } | ||||
| ra-ap-rustc_parse_format = { version = "0.113", default-features = false } | ||||
| ra-ap-rustc_index = { version = "0.113", default-features = false } | ||||
| ra-ap-rustc_abi = { version = "0.113", default-features = false } | ||||
| ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false } | ||||
| ra-ap-rustc_lexer = { version = "0.116", default-features = false } | ||||
| ra-ap-rustc_parse_format = { version = "0.116", default-features = false } | ||||
| ra-ap-rustc_index = { version = "0.116", default-features = false } | ||||
| ra-ap-rustc_abi = { version = "0.116", default-features = false } | ||||
| ra-ap-rustc_pattern_analysis = { version = "0.116", default-features = false } | ||||
| 
 | ||||
| # local crates that aren't published to crates.io. These should not have versions. | ||||
| 
 | ||||
|  | @ -101,24 +101,24 @@ la-arena = { version = "0.3.1" } | |||
| lsp-server = { version = "0.7.8" } | ||||
| 
 | ||||
| # non-local crates | ||||
| anyhow = "1.0.97" | ||||
| anyhow = "1.0.98" | ||||
| arrayvec = "0.7.6" | ||||
| bitflags = "2.9.0" | ||||
| cargo_metadata = "0.19.2" | ||||
| camino = "1.1.9" | ||||
| chalk-solve = { version = "0.102.0", default-features = false } | ||||
| chalk-ir = "0.102.0" | ||||
| chalk-recursive = { version = "0.102.0", default-features = false } | ||||
| chalk-derive = "0.102.0" | ||||
| bitflags = "2.9.1" | ||||
| cargo_metadata = "0.20.0" | ||||
| camino = "1.1.10" | ||||
| chalk-solve = { version = "0.103.0", default-features = false } | ||||
| chalk-ir = "0.103.0" | ||||
| chalk-recursive = { version = "0.103.0", default-features = false } | ||||
| chalk-derive = "0.103.0" | ||||
| crossbeam-channel = "0.5.15" | ||||
| dissimilar = "1.0.10" | ||||
| dot = "0.1.4" | ||||
| either = "1.15.0" | ||||
| expect-test = "1.5.1" | ||||
| indexmap = { version = "2.8.0", features = ["serde"] } | ||||
| indexmap = { version = "2.9.0", features = ["serde"] } | ||||
| itertools = "0.14.0" | ||||
| libc = "0.2.171" | ||||
| libloading = "0.8.6" | ||||
| libc = "0.2.172" | ||||
| libloading = "0.8.8" | ||||
| memmap2 = "0.9.5" | ||||
| nohash-hasher = "0.2.0" | ||||
| oorandom = "11.1.5" | ||||
|  | @ -129,20 +129,22 @@ object = { version = "0.36.7", default-features = false, features = [ | |||
|   "macho", | ||||
|   "pe", | ||||
| ] } | ||||
| process-wrap = { version = "8.2.0", features = ["std"] } | ||||
| process-wrap = { version = "8.2.1", features = ["std"] } | ||||
| pulldown-cmark-to-cmark = "10.0.4" | ||||
| pulldown-cmark = { version = "0.9.6", default-features = false } | ||||
| rayon = "1.10.0" | ||||
| rowan = "=0.15.15" | ||||
| salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] } | ||||
| # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work | ||||
| # on impls without it | ||||
| salsa = { version = "0.22.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] } | ||||
| salsa-macros = "0.22.0" | ||||
| semver = "1.0.26" | ||||
| serde = { version = "1.0.219" } | ||||
| serde_derive = { version = "1.0.219" } | ||||
| serde_json = "1.0.140" | ||||
| rustc-hash = "2.1.1" | ||||
| rustc-literal-escaper = "0.0.2" | ||||
| smallvec = { version = "1.14.0", features = [ | ||||
| rustc-literal-escaper = "0.0.3" | ||||
| smallvec = { version = "1.15.1", features = [ | ||||
|   "const_new", | ||||
|   "union", | ||||
|   "const_generics", | ||||
|  | @ -166,7 +168,7 @@ xshell = "0.2.7" | |||
| # We need to freeze the version of the crate, as the raw-api feature is considered unstable | ||||
| dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } | ||||
| # We need to freeze the version of the crate, as it needs to match with dashmap | ||||
| hashbrown = { version = "0.14.0", features = [ | ||||
| hashbrown = { version = "0.14.*", features = [ | ||||
|   "inline-more", | ||||
| ], default-features = false } | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,12 +20,10 @@ use span::Edition; | |||
| use triomphe::Arc; | ||||
| use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet}; | ||||
| 
 | ||||
| use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb}; | ||||
| use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb}; | ||||
| 
 | ||||
| pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>; | ||||
| 
 | ||||
| type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||||
| pub struct SourceRootId(pub u32); | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,6 +28,8 @@ use syntax::{Parse, SyntaxError, ast}; | |||
| use triomphe::Arc; | ||||
| pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}; | ||||
| 
 | ||||
| pub type FxIndexSet<T> = indexmap::IndexSet<T, rustc_hash::FxBuildHasher>; | ||||
| 
 | ||||
| #[macro_export] | ||||
| macro_rules! impl_intern_key { | ||||
|     ($id:ident, $loc:ident) => { | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ rustc-hash.workspace = true | |||
| tracing.workspace = true | ||||
| smallvec.workspace = true | ||||
| triomphe.workspace = true | ||||
| rustc_apfloat = "0.2.2" | ||||
| rustc_apfloat = "0.2.3" | ||||
| text-size.workspace = true | ||||
| salsa.workspace = true | ||||
| salsa-macros.workspace = true | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ use intern::{Symbol, sym}; | |||
| use la_arena::{ArenaMap, Idx, RawIdx}; | ||||
| use mbe::DelimiterKind; | ||||
| use rustc_abi::ReprOptions; | ||||
| use span::AstIdNode; | ||||
| use syntax::{ | ||||
|     AstPtr, | ||||
|     ast::{self, HasAttrs}, | ||||
|  | @ -22,10 +23,10 @@ use triomphe::Arc; | |||
| use tt::iter::{TtElement, TtIter}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, | ||||
|     AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, | ||||
|     VariantId, | ||||
|     db::DefDatabase, | ||||
|     item_tree::{AttrOwner, FieldParent, ItemTreeNode}, | ||||
|     item_tree::block_item_tree_query, | ||||
|     lang_item::LangItem, | ||||
|     nameres::{ModuleOrigin, ModuleSource}, | ||||
|     src::{HasChildSource, HasSource}, | ||||
|  | @ -42,6 +43,15 @@ pub struct AttrsWithOwner { | |||
| } | ||||
| 
 | ||||
| impl Attrs { | ||||
|     pub fn new( | ||||
|         db: &dyn DefDatabase, | ||||
|         owner: &dyn ast::HasAttrs, | ||||
|         span_map: SpanMapRef<'_>, | ||||
|         cfg_options: &CfgOptions, | ||||
|     ) -> Self { | ||||
|         Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&self, id: AttrId) -> Option<&Attr> { | ||||
|         (**self).iter().find(|attr| attr.id == id) | ||||
|     } | ||||
|  | @ -94,44 +104,64 @@ impl Attrs { | |||
|         v: VariantId, | ||||
|     ) -> Arc<ArenaMap<LocalFieldId, Attrs>> { | ||||
|         let _p = tracing::info_span!("fields_attrs_query").entered(); | ||||
|         // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
 | ||||
|         let mut res = ArenaMap::default(); | ||||
|         let item_tree; | ||||
|         let (parent, fields, krate) = match v { | ||||
|         let (fields, file_id, krate) = match v { | ||||
|             VariantId::EnumVariantId(it) => { | ||||
|                 let loc = it.lookup(db); | ||||
|                 let krate = loc.parent.lookup(db).container.krate; | ||||
|                 item_tree = loc.id.item_tree(db); | ||||
|                 let variant = &item_tree[loc.id.value]; | ||||
|                 (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate) | ||||
|                 let source = loc.source(db); | ||||
|                 (source.value.field_list(), source.file_id, krate) | ||||
|             } | ||||
|             VariantId::StructId(it) => { | ||||
|                 let loc = it.lookup(db); | ||||
|                 let krate = loc.container.krate; | ||||
|                 item_tree = loc.id.item_tree(db); | ||||
|                 let struct_ = &item_tree[loc.id.value]; | ||||
|                 (FieldParent::Struct(loc.id.value), &struct_.fields, krate) | ||||
|                 let source = loc.source(db); | ||||
|                 (source.value.field_list(), source.file_id, krate) | ||||
|             } | ||||
|             VariantId::UnionId(it) => { | ||||
|                 let loc = it.lookup(db); | ||||
|                 let krate = loc.container.krate; | ||||
|                 item_tree = loc.id.item_tree(db); | ||||
|                 let union_ = &item_tree[loc.id.value]; | ||||
|                 (FieldParent::Union(loc.id.value), &union_.fields, krate) | ||||
|                 let source = loc.source(db); | ||||
|                 ( | ||||
|                     source.value.record_field_list().map(ast::FieldList::RecordFieldList), | ||||
|                     source.file_id, | ||||
|                     krate, | ||||
|                 ) | ||||
|             } | ||||
|         }; | ||||
|         let Some(fields) = fields else { | ||||
|             return Arc::new(res); | ||||
|         }; | ||||
| 
 | ||||
|         let cfg_options = krate.cfg_options(db); | ||||
|         let span_map = db.span_map(file_id); | ||||
| 
 | ||||
|         match fields { | ||||
|             ast::FieldList::RecordFieldList(fields) => { | ||||
|                 let mut idx = 0; | ||||
|         for (id, _field) in fields.iter().enumerate() { | ||||
|             let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id)); | ||||
|             if attrs.is_cfg_enabled(cfg_options) { | ||||
|                 for field in fields.fields() { | ||||
|                     let attrs = | ||||
|                         Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); | ||||
|                     if attrs.is_cfg_enabled(cfg_options).is_ok() { | ||||
|                         res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); | ||||
|                         idx += 1; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             ast::FieldList::TupleFieldList(fields) => { | ||||
|                 let mut idx = 0; | ||||
|                 for field in fields.fields() { | ||||
|                     let attrs = | ||||
|                         Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); | ||||
|                     if attrs.is_cfg_enabled(cfg_options).is_ok() { | ||||
|                         res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); | ||||
|                         idx += 1; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         res.shrink_to_fit(); | ||||
|         Arc::new(res) | ||||
|     } | ||||
| } | ||||
|  | @ -167,11 +197,10 @@ impl Attrs { | |||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | ||||
|         match self.cfg() { | ||||
|             None => true, | ||||
|             Some(cfg) => cfg_options.check(&cfg) != Some(false), | ||||
|         } | ||||
|     pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> { | ||||
|         self.cfgs().try_for_each(|cfg| { | ||||
|             if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|  | @ -488,61 +517,59 @@ impl AttrsWithOwner { | |||
|     pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | ||||
|         let _p = tracing::info_span!("attrs_query").entered(); | ||||
|         // FIXME: this should use `Trace` to avoid duplication in `source_map` below
 | ||||
|         let raw_attrs = match def { | ||||
|         match def { | ||||
|             AttrDefId::ModuleId(module) => { | ||||
|                 let def_map = module.def_map(db); | ||||
|                 let mod_data = &def_map[module.local_id]; | ||||
| 
 | ||||
|                 match mod_data.origin { | ||||
|                     ModuleOrigin::File { definition, declaration_tree_id, .. } => { | ||||
|                 let raw_attrs = match mod_data.origin { | ||||
|                     ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => { | ||||
|                         let decl_attrs = declaration_tree_id | ||||
|                             .item_tree(db) | ||||
|                             .raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into())) | ||||
|                             .raw_attrs(declaration.upcast()) | ||||
|                             .clone(); | ||||
|                         let tree = db.file_item_tree(definition.into()); | ||||
|                         let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); | ||||
|                         let def_attrs = tree.top_level_raw_attrs().clone(); | ||||
|                         decl_attrs.merge(def_attrs) | ||||
|                     } | ||||
|                     ModuleOrigin::CrateRoot { definition } => { | ||||
|                         let tree = db.file_item_tree(definition.into()); | ||||
|                         tree.raw_attrs(AttrOwner::TopLevel).clone() | ||||
|                         tree.top_level_raw_attrs().clone() | ||||
|                     } | ||||
|                     ModuleOrigin::Inline { definition_tree_id, definition } => { | ||||
|                         definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone() | ||||
|                     } | ||||
|                     ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id | ||||
|                         .item_tree(db) | ||||
|                         .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) | ||||
|                         .clone(), | ||||
|                     ModuleOrigin::BlockExpr { id, .. } => { | ||||
|                         let tree = db.block_item_tree(id); | ||||
|                         tree.raw_attrs(AttrOwner::TopLevel).clone() | ||||
|                         let tree = block_item_tree_query(db, id); | ||||
|                         tree.top_level_raw_attrs().clone() | ||||
|                     } | ||||
|                 }; | ||||
|                 Attrs::expand_cfg_attr(db, module.krate, raw_attrs) | ||||
|             } | ||||
|             } | ||||
|             AttrDefId::FieldId(it) => { | ||||
|                 return db.fields_attrs(it.parent)[it.local_id].clone(); | ||||
|             } | ||||
|             AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(), | ||||
|             AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::AdtId(it) => match it { | ||||
|                 AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 AdtId::StructId(it) => attrs_from_ast_id_loc(db, it), | ||||
|                 AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it), | ||||
|                 AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             }, | ||||
|             AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::MacroId(it) => match it { | ||||
|                 MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it), | ||||
|                 MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it), | ||||
|                 MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it), | ||||
|                 MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             }, | ||||
|             AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::GenericParamId(it) => match it { | ||||
|                 GenericParamId::ConstParamId(it) => { | ||||
|                     let src = it.parent().child_source(db); | ||||
|                     // FIXME: We should be never getting `None` here.
 | ||||
|                     return Attrs(match src.value.get(it.local_id()) { | ||||
|                     Attrs(match src.value.get(it.local_id()) { | ||||
|                         Some(val) => RawAttrs::new_expanded( | ||||
|                             db, | ||||
|                             val, | ||||
|  | @ -550,12 +577,12 @@ impl AttrsWithOwner { | |||
|                             def.krate(db).cfg_options(db), | ||||
|                         ), | ||||
|                         None => RawAttrs::EMPTY, | ||||
|                     }); | ||||
|                     }) | ||||
|                 } | ||||
|                 GenericParamId::TypeParamId(it) => { | ||||
|                     let src = it.parent().child_source(db); | ||||
|                     // FIXME: We should be never getting `None` here.
 | ||||
|                     return Attrs(match src.value.get(it.local_id()) { | ||||
|                     Attrs(match src.value.get(it.local_id()) { | ||||
|                         Some(val) => RawAttrs::new_expanded( | ||||
|                             db, | ||||
|                             val, | ||||
|  | @ -563,12 +590,12 @@ impl AttrsWithOwner { | |||
|                             def.krate(db).cfg_options(db), | ||||
|                         ), | ||||
|                         None => RawAttrs::EMPTY, | ||||
|                     }); | ||||
|                     }) | ||||
|                 } | ||||
|                 GenericParamId::LifetimeParamId(it) => { | ||||
|                     let src = it.parent.child_source(db); | ||||
|                     // FIXME: We should be never getting `None` here.
 | ||||
|                     return Attrs(match src.value.get(it.local_id) { | ||||
|                     Attrs(match src.value.get(it.local_id) { | ||||
|                         Some(val) => RawAttrs::new_expanded( | ||||
|                             db, | ||||
|                             val, | ||||
|  | @ -576,16 +603,13 @@ impl AttrsWithOwner { | |||
|                             def.krate(db).cfg_options(db), | ||||
|                         ), | ||||
|                         None => RawAttrs::EMPTY, | ||||
|                     }); | ||||
|                     }) | ||||
|                 } | ||||
|             }, | ||||
|             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it), | ||||
|             AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), | ||||
|         }; | ||||
| 
 | ||||
|         let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db)); | ||||
|         Attrs(attrs) | ||||
|             AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it), | ||||
|             AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { | ||||
|  | @ -787,14 +811,15 @@ fn any_has_attrs<'db>( | |||
|     id.lookup(db).source(db).map(ast::AnyHasAttrs::new) | ||||
| } | ||||
| 
 | ||||
| fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( | ||||
| fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>( | ||||
|     db: &(dyn DefDatabase + 'db), | ||||
|     lookup: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = N>>, | ||||
| ) -> RawAttrs { | ||||
|     let id = lookup.lookup(db).item_tree_id(); | ||||
|     let tree = id.item_tree(db); | ||||
|     let attr_owner = N::attr_owner(id.value); | ||||
|     tree.raw_attrs(attr_owner).clone() | ||||
|     lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Ast = N> + HasModule>, | ||||
| ) -> Attrs { | ||||
|     let loc = lookup.lookup(db); | ||||
|     let source = loc.source(db); | ||||
|     let span_map = db.span_map(source.file_id); | ||||
|     let cfg_options = loc.krate(db).cfg_options(db); | ||||
|     Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options)) | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn fields_attrs_source_map( | ||||
|  |  | |||
|  | @ -1,18 +1,20 @@ | |||
| //! Defines database & queries for name resolution.
 | ||||
| use base_db::{Crate, RootQueryDb, SourceDatabase}; | ||||
| use either::Either; | ||||
| use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase}; | ||||
| use hir_expand::{ | ||||
|     EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, | ||||
|     db::ExpandDatabase, | ||||
| }; | ||||
| use intern::sym; | ||||
| use la_arena::ArenaMap; | ||||
| use syntax::{AstPtr, ast}; | ||||
| use thin_vec::ThinVec; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, | ||||
|     AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, | ||||
|     EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, | ||||
|     FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, | ||||
|     MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, | ||||
|     FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, | ||||
|     MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, | ||||
|     StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, | ||||
|     TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, | ||||
|     attr::{Attrs, AttrsWithOwner}, | ||||
|  | @ -21,17 +23,13 @@ use crate::{ | |||
|     }, | ||||
|     hir::generics::GenericParams, | ||||
|     import_map::ImportMap, | ||||
|     item_tree::{AttrOwner, ItemTree}, | ||||
|     item_tree::{ItemTree, file_item_tree_query}, | ||||
|     lang_item::{self, LangItem}, | ||||
|     nameres::{ | ||||
|         assoc::{ImplItems, TraitItems}, | ||||
|         crate_def_map, | ||||
|         diagnostics::DefDiagnostics, | ||||
|     }, | ||||
|     nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics}, | ||||
|     signatures::{ | ||||
|         ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature, | ||||
|         InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature, | ||||
|         TraitSignature, TypeAliasSignature, UnionSignature, VariantFields, | ||||
|         ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, | ||||
|         StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature, | ||||
|         VariantFields, | ||||
|     }, | ||||
|     tt, | ||||
|     visibility::{self, Visibility}, | ||||
|  | @ -93,9 +91,6 @@ pub trait InternDatabase: RootQueryDb { | |||
|     #[salsa::interned] | ||||
|     fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; | ||||
|     // // endregion: items
 | ||||
| 
 | ||||
|     #[salsa::interned] | ||||
|     fn intern_block(&self, loc: BlockLoc) -> BlockId; | ||||
| } | ||||
| 
 | ||||
| #[query_group::query_group] | ||||
|  | @ -105,11 +100,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { | |||
|     fn expand_proc_attr_macros(&self) -> bool; | ||||
| 
 | ||||
|     /// Computes an [`ItemTree`] for the given file or macro expansion.
 | ||||
|     #[salsa::invoke(ItemTree::file_item_tree_query)] | ||||
|     fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; | ||||
| 
 | ||||
|     #[salsa::invoke(ItemTree::block_item_tree_query)] | ||||
|     fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>; | ||||
|     #[salsa::invoke(file_item_tree_query)] | ||||
|     #[salsa::transparent] | ||||
|     fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree; | ||||
| 
 | ||||
|     /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
 | ||||
|     #[salsa::invoke(macro_def)] | ||||
|  | @ -123,24 +116,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { | |||
|         id: VariantId, | ||||
|     ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>); | ||||
| 
 | ||||
|     #[salsa::tracked] | ||||
|     fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> { | ||||
|         self.enum_variants_with_diagnostics(id).0 | ||||
|     } | ||||
| 
 | ||||
|     #[salsa::invoke(EnumVariants::enum_variants_query)] | ||||
|     fn enum_variants_with_diagnostics( | ||||
|         &self, | ||||
|         id: EnumId, | ||||
|     ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>); | ||||
| 
 | ||||
|     #[salsa::transparent] | ||||
|     #[salsa::invoke(ImplItems::impl_items_query)] | ||||
|     fn impl_items(&self, e: ImplId) -> Arc<ImplItems>; | ||||
| 
 | ||||
|     #[salsa::invoke(ImplItems::impl_items_with_diagnostics_query)] | ||||
|     fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc<ImplItems>, DefDiagnostics); | ||||
| 
 | ||||
|     #[salsa::transparent] | ||||
|     #[salsa::invoke(TraitItems::trait_items_query)] | ||||
|     fn trait_items(&self, e: TraitId) -> Arc<TraitItems>; | ||||
|  | @ -323,16 +298,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { | |||
|     #[salsa::invoke(visibility::field_visibilities_query)] | ||||
|     fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>; | ||||
| 
 | ||||
|     // FIXME: unify function_visibility and const_visibility?
 | ||||
| 
 | ||||
|     #[salsa::invoke(visibility::function_visibility_query)] | ||||
|     fn function_visibility(&self, def: FunctionId) -> Visibility; | ||||
| 
 | ||||
|     #[salsa::invoke(visibility::const_visibility_query)] | ||||
|     fn const_visibility(&self, def: ConstId) -> Visibility; | ||||
| 
 | ||||
|     #[salsa::invoke(visibility::type_alias_visibility_query)] | ||||
|     fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility; | ||||
|     #[salsa::invoke(visibility::assoc_visibility_query)] | ||||
|     fn assoc_visibility(&self, def: AssocItemId) -> Visibility; | ||||
| 
 | ||||
|     // endregion:visibilities
 | ||||
| 
 | ||||
|  | @ -368,7 +335,7 @@ fn include_macro_invoc( | |||
| fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { | ||||
|     let file = crate_id.data(db).root_file_id(db); | ||||
|     let item_tree = db.file_item_tree(file.into()); | ||||
|     let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); | ||||
|     let attrs = item_tree.top_level_raw_attrs(); | ||||
|     for attr in &**attrs { | ||||
|         match attr.path().as_ident() { | ||||
|             Some(ident) if *ident == sym::no_std => return true, | ||||
|  | @ -399,10 +366,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { | |||
| } | ||||
| 
 | ||||
| fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { | ||||
|     use hir_expand::InFile; | ||||
| 
 | ||||
|     use crate::{Lookup, MacroDefKind, MacroExpander}; | ||||
| 
 | ||||
|     let kind = |expander, file_id, m| { | ||||
|         let in_file = InFile::new(file_id, m); | ||||
|         match expander { | ||||
|  | @ -418,11 +381,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { | |||
|         MacroId::Macro2Id(it) => { | ||||
|             let loc: Macro2Loc = it.lookup(db); | ||||
| 
 | ||||
|             let item_tree = loc.id.item_tree(db); | ||||
|             let makro = &item_tree[loc.id.value]; | ||||
|             MacroDefId { | ||||
|                 krate: loc.container.krate, | ||||
|                 kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), | ||||
|                 kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), | ||||
|                 local_inner: false, | ||||
|                 allow_internal_unsafe: loc.allow_internal_unsafe, | ||||
|                 edition: loc.edition, | ||||
|  | @ -431,11 +392,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { | |||
|         MacroId::MacroRulesId(it) => { | ||||
|             let loc: MacroRulesLoc = it.lookup(db); | ||||
| 
 | ||||
|             let item_tree = loc.id.item_tree(db); | ||||
|             let makro = &item_tree[loc.id.value]; | ||||
|             MacroDefId { | ||||
|                 krate: loc.container.krate, | ||||
|                 kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), | ||||
|                 kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), | ||||
|                 local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), | ||||
|                 allow_internal_unsafe: loc | ||||
|                     .flags | ||||
|  | @ -446,15 +405,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { | |||
|         MacroId::ProcMacroId(it) => { | ||||
|             let loc = it.lookup(db); | ||||
| 
 | ||||
|             let item_tree = loc.id.item_tree(db); | ||||
|             let makro = &item_tree[loc.id.value]; | ||||
|             MacroDefId { | ||||
|                 krate: loc.container.krate, | ||||
|                 kind: MacroDefKind::ProcMacro( | ||||
|                     InFile::new(loc.id.file_id(), makro.ast_id), | ||||
|                     loc.expander, | ||||
|                     loc.kind, | ||||
|                 ), | ||||
|                 kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), | ||||
|                 local_inner: false, | ||||
|                 allow_internal_unsafe: false, | ||||
|                 edition: loc.edition, | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ use base_db::Crate; | |||
| use cfg::CfgOptions; | ||||
| use drop_bomb::DropBomb; | ||||
| use hir_expand::AstId; | ||||
| use hir_expand::span_map::SpanMapRef; | ||||
| use hir_expand::{ | ||||
|     ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, | ||||
|     eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, | ||||
|  | @ -223,9 +224,15 @@ impl Expander { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub(super) fn ast_id_map(&self) -> &AstIdMap { | ||||
|         &self.ast_id_map | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub(super) fn span_map(&self) -> SpanMapRef<'_> { | ||||
|         self.span_map.as_ref() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  |  | |||
|  | @ -7,12 +7,14 @@ mod path; | |||
| 
 | ||||
| use std::mem; | ||||
| 
 | ||||
| use base_db::FxIndexSet; | ||||
| use cfg::CfgOptions; | ||||
| use either::Either; | ||||
| use hir_expand::{ | ||||
|     HirFileId, InFile, Lookup, MacroDefId, | ||||
|     HirFileId, InFile, Intern, MacroDefId, | ||||
|     mod_path::tool_path, | ||||
|     name::{AsName, Name}, | ||||
|     span_map::SpanMapRef, | ||||
| }; | ||||
| use intern::{Symbol, sym}; | ||||
| use rustc_hash::FxHashMap; | ||||
|  | @ -30,8 +32,8 @@ use triomphe::Arc; | |||
| use tt::TextRange; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc, | ||||
|     MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, | ||||
|     AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, | ||||
|     ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, | ||||
|     builtin_type::BuiltinUint, | ||||
|     db::DefDatabase, | ||||
|     expr_store::{ | ||||
|  | @ -65,8 +67,6 @@ use crate::{ | |||
| 
 | ||||
| pub use self::path::hir_segment_to_ast_segment; | ||||
| 
 | ||||
| type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; | ||||
| 
 | ||||
| pub(super) fn lower_body( | ||||
|     db: &dyn DefDatabase, | ||||
|     owner: DefWithBodyId, | ||||
|  | @ -564,6 +564,11 @@ impl ExprCollector<'_> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub(crate) fn span_map(&self) -> SpanMapRef<'_> { | ||||
|         self.expander.span_map() | ||||
|     } | ||||
| 
 | ||||
|     pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { | ||||
|         // FIXME: Keyword check?
 | ||||
|         let lifetime_ref = match &*lifetime.text() { | ||||
|  | @ -2141,26 +2146,10 @@ impl ExprCollector<'_> { | |||
|         block: ast::BlockExpr, | ||||
|         mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr, | ||||
|     ) -> ExprId { | ||||
|         let block_has_items = { | ||||
|             let statement_has_item = block.statements().any(|stmt| match stmt { | ||||
|                 ast::Stmt::Item(_) => true, | ||||
|                 // Macro calls can be both items and expressions. The syntax library always treats
 | ||||
|                 // them as expressions here, so we undo that.
 | ||||
|                 ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))), | ||||
|                 _ => false, | ||||
|             }); | ||||
|             statement_has_item | ||||
|                 || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_))) | ||||
|                 || (block.may_carry_attributes() && block.attrs().next().is_some()) | ||||
|         }; | ||||
| 
 | ||||
|         let block_id = if block_has_items { | ||||
|             let file_local_id = self.expander.ast_id_map().ast_id(&block); | ||||
|         let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| { | ||||
|             let ast_id = self.expander.in_file(file_local_id); | ||||
|             Some(self.db.intern_block(BlockLoc { ast_id, module: self.module })) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
|             BlockLoc { ast_id, module: self.module }.intern(self.db) | ||||
|         }); | ||||
| 
 | ||||
|         let (module, def_map) = | ||||
|             match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) { | ||||
|  | @ -2260,11 +2249,8 @@ impl ExprCollector<'_> { | |||
|                     match resolved.take_values() { | ||||
|                         Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), | ||||
|                         Some(ModuleDefId::EnumVariantId(variant)) | ||||
|                             if { | ||||
|                                 let loc = variant.lookup(self.db); | ||||
|                                 let tree = loc.item_tree_id().item_tree(self.db); | ||||
|                                 tree[loc.id.value].shape != FieldsShape::Record | ||||
|                             } => | ||||
|                         // FIXME: This can cause a cycle if the user is writing invalid code
 | ||||
|                             if self.db.variant_fields(variant.into()).shape != FieldsShape::Record => | ||||
|                         { | ||||
|                             (None, Pat::Path(name.into())) | ||||
|                         } | ||||
|  |  | |||
|  | @ -9,9 +9,10 @@ use std::{ | |||
| use hir_expand::{Lookup, mod_path::PathKind}; | ||||
| use itertools::Itertools; | ||||
| use span::Edition; | ||||
| use syntax::ast::HasName; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId, | ||||
|     AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId, | ||||
|     expr_store::path::{GenericArg, GenericArgs}, | ||||
|     hir::{ | ||||
|         Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement, | ||||
|  | @ -19,6 +20,7 @@ use crate::{ | |||
|     }, | ||||
|     lang_item::LangItemTarget, | ||||
|     signatures::{FnFlags, FunctionSignature, StructSignature}, | ||||
|     src::HasSource, | ||||
|     type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef}, | ||||
| }; | ||||
| use crate::{LifetimeParamId, signatures::StructFlags}; | ||||
|  | @ -48,6 +50,17 @@ pub enum LineFormat { | |||
|     Indentation, | ||||
| } | ||||
| 
 | ||||
| fn item_name<Id, Loc>(db: &dyn DefDatabase, id: Id, default: &str) -> String | ||||
| where | ||||
|     Id: Lookup<Database = dyn DefDatabase, Data = Loc>, | ||||
|     Loc: HasSource, | ||||
|     Loc::Value: ast::HasName, | ||||
| { | ||||
|     let loc = id.lookup(db); | ||||
|     let source = loc.source(db); | ||||
|     source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string()) | ||||
| } | ||||
| 
 | ||||
| pub fn print_body_hir( | ||||
|     db: &dyn DefDatabase, | ||||
|     body: &Body, | ||||
|  | @ -55,31 +68,14 @@ pub fn print_body_hir( | |||
|     edition: Edition, | ||||
| ) -> String { | ||||
|     let header = match owner { | ||||
|         DefWithBodyId::FunctionId(it) => { | ||||
|             it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition))) | ||||
|         } | ||||
|         DefWithBodyId::StaticId(it) => it | ||||
|             .lookup(db) | ||||
|             .id | ||||
|             .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))), | ||||
|         DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { | ||||
|             format!( | ||||
|                 "const {} = ", | ||||
|                 match &it.name { | ||||
|                     Some(name) => name.display(db, edition).to_string(), | ||||
|                     None => "_".to_owned(), | ||||
|                 } | ||||
|             ) | ||||
|         }), | ||||
|         DefWithBodyId::VariantId(it) => { | ||||
|             let loc = it.lookup(db); | ||||
|             let enum_loc = loc.parent.lookup(db); | ||||
|             format!( | ||||
|         DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")), | ||||
|         DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")), | ||||
|         DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")), | ||||
|         DefWithBodyId::VariantId(it) => format!( | ||||
|             "enum {}::{}", | ||||
|                 enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), | ||||
|                 loc.id.item_tree(db)[loc.id.value].name.display(db, edition), | ||||
|             ) | ||||
|         } | ||||
|             item_name(db, it.lookup(db).parent, "<missing>"), | ||||
|             item_name(db, it, "<missing>") | ||||
|         ), | ||||
|     }; | ||||
| 
 | ||||
|     let mut p = Printer { | ||||
|  | @ -116,22 +112,13 @@ pub fn print_body_hir( | |||
| 
 | ||||
| pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String { | ||||
|     let header = match owner { | ||||
|         VariantId::StructId(it) => { | ||||
|             it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition))) | ||||
|         } | ||||
|         VariantId::EnumVariantId(enum_variant_id) => { | ||||
|             let loc = enum_variant_id.lookup(db); | ||||
|             let enum_loc = loc.parent.lookup(db); | ||||
|             format!( | ||||
|         VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")), | ||||
|         VariantId::EnumVariantId(it) => format!( | ||||
|             "enum {}::{}", | ||||
|                 enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), | ||||
|                 loc.id.item_tree(db)[loc.id.value].name.display(db, edition), | ||||
|             ) | ||||
|         } | ||||
|         VariantId::UnionId(union_id) => union_id | ||||
|             .lookup(db) | ||||
|             .id | ||||
|             .resolved(db, |it| format!("union {}", it.name.display(db, edition))), | ||||
|             item_name(db, it.lookup(db).parent, "<missing>"), | ||||
|             item_name(db, it, "<missing>") | ||||
|         ), | ||||
|         VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")), | ||||
|     }; | ||||
| 
 | ||||
|     let fields = db.variant_fields(owner); | ||||
|  | @ -154,9 +141,11 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E | |||
|         let FieldData { name, type_ref, visibility, is_unsafe } = data; | ||||
|         match visibility { | ||||
|             crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => { | ||||
|                 w!(p, "{}", interned.display(db, p.edition)) | ||||
|                 w!(p, "pub(in {})", interned.display(db, p.edition)) | ||||
|             } | ||||
|             crate::item_tree::RawVisibility::Public => w!(p, "pub "), | ||||
|             crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "), | ||||
|             crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "), | ||||
|         } | ||||
|         if *is_unsafe { | ||||
|             w!(p, "unsafe "); | ||||
|  | @ -1089,10 +1078,7 @@ impl Printer<'_> { | |||
|             w!(self, "builtin#lang("); | ||||
|             macro_rules! write_name { | ||||
|                 ($it:ident) => {{ | ||||
|                     let loc = $it.lookup(self.db); | ||||
|                     let tree = loc.item_tree_id().item_tree(self.db); | ||||
|                     let name = &tree[loc.id.value].name; | ||||
|                     w!(self, "{}", name.display(self.db, self.edition)); | ||||
|                     w!(self, "{}", item_name(self.db, $it, "<missing>")); | ||||
|                 }}; | ||||
|             } | ||||
|             match *it { | ||||
|  |  | |||
|  | @ -189,8 +189,8 @@ fn f() { | |||
| } | ||||
|     "#,
 | ||||
|         expect![[r#" | ||||
|             BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) } | ||||
|             BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) } | ||||
|             BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::<ModuleData>(1) } | ||||
|             BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) } | ||||
|             crate scope | ||||
|         "#]],
 | ||||
|     ); | ||||
|  | @ -397,7 +397,6 @@ fn main() { | |||
| fn underscore_import() { | ||||
|     // This used to panic, because the default (private) visibility inside block expressions would
 | ||||
|     // point into the containing `DefMap`, which visibilities should never be able to do.
 | ||||
|     cov_mark::check!(adjust_vis_in_block_def_map); | ||||
|     check_at( | ||||
|         r#" | ||||
| mod m { | ||||
|  | @ -457,7 +456,6 @@ fn foo() { | |||
| #[test] | ||||
| fn is_visible_from_same_def_map() { | ||||
|     // Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481
 | ||||
|     cov_mark::check!(is_visible_from_same_block_def_map); | ||||
|     check_at( | ||||
|         r#" | ||||
| fn outer() { | ||||
|  |  | |||
|  | @ -137,7 +137,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt | |||
|         let loc = variant.lookup(ctx.db); | ||||
|         if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) { | ||||
|             path.push_segment( | ||||
|                 ctx.db.enum_variants(loc.parent).variants[loc.index as usize].1.clone(), | ||||
|                 loc.parent.enum_variants(ctx.db).variants[loc.index as usize].1.clone(), | ||||
|             ); | ||||
|             return Some(path); | ||||
|         } | ||||
|  | @ -615,6 +615,7 @@ fn find_local_import_locations( | |||
|                         cov_mark::hit!(discount_private_imports); | ||||
|                         false | ||||
|                     } | ||||
|                     Visibility::PubCrate(_) => true, | ||||
|                     Visibility::Public => true, | ||||
|                 }; | ||||
| 
 | ||||
|  | @ -1286,7 +1287,6 @@ $0 | |||
| 
 | ||||
|     #[test] | ||||
|     fn explicit_private_imports_crate() { | ||||
|         cov_mark::check!(explicit_private_imports); | ||||
|         check_found_path( | ||||
|             r#" | ||||
| //- /main.rs
 | ||||
|  |  | |||
|  | @ -13,13 +13,14 @@ use smallvec::{SmallVec, smallvec}; | |||
| use span::Edition; | ||||
| use stdx::format_to; | ||||
| use syntax::ast; | ||||
| use thin_vec::ThinVec; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId, | ||||
|     LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, | ||||
|     db::DefDatabase, | ||||
|     per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem}, | ||||
|     visibility::{Visibility, VisibilityExplicitness}, | ||||
|     visibility::Visibility, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Debug, Default)] | ||||
|  | @ -155,22 +156,21 @@ pub struct ItemScope { | |||
| 
 | ||||
|     /// The defs declared in this scope. Each def has a single scope where it is
 | ||||
|     /// declared.
 | ||||
|     declarations: Vec<ModuleDefId>, | ||||
|     declarations: ThinVec<ModuleDefId>, | ||||
| 
 | ||||
|     impls: Vec<ImplId>, | ||||
|     #[allow(clippy::box_collection)] | ||||
|     extern_blocks: Option<Box<Vec<ExternBlockId>>>, | ||||
|     unnamed_consts: Vec<ConstId>, | ||||
|     impls: ThinVec<ImplId>, | ||||
|     extern_blocks: ThinVec<ExternBlockId>, | ||||
|     unnamed_consts: ThinVec<ConstId>, | ||||
|     /// Traits imported via `use Trait as _;`.
 | ||||
|     unnamed_trait_imports: FxHashMap<TraitId, Item<()>>, | ||||
|     unnamed_trait_imports: ThinVec<(TraitId, Item<()>)>, | ||||
| 
 | ||||
|     // the resolutions of the imports of this scope
 | ||||
|     use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>, | ||||
|     use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>, | ||||
|     use_imports_macros: FxHashMap<ImportOrExternCrate, ImportOrDef>, | ||||
| 
 | ||||
|     use_decls: Vec<UseId>, | ||||
|     extern_crate_decls: Vec<ExternCrateId>, | ||||
|     use_decls: ThinVec<UseId>, | ||||
|     extern_crate_decls: ThinVec<ExternCrateId>, | ||||
|     /// Macros visible in current module in legacy textual scope
 | ||||
|     ///
 | ||||
|     /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
 | ||||
|  | @ -183,7 +183,7 @@ pub struct ItemScope { | |||
|     /// Module scoped macros will be inserted into `items` instead of here.
 | ||||
|     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
 | ||||
|     // be all resolved to the last one defined if shadowing happens.
 | ||||
|     legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>, | ||||
|     legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 2]>>, | ||||
|     /// The attribute macro invocations in this scope.
 | ||||
|     attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>, | ||||
|     /// The macro invocations in this scope.
 | ||||
|  | @ -198,7 +198,7 @@ struct DeriveMacroInvocation { | |||
|     attr_id: AttrId, | ||||
|     /// The `#[derive]` call
 | ||||
|     attr_call_id: MacroCallId, | ||||
|     derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>, | ||||
|     derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>, | ||||
| } | ||||
| 
 | ||||
| pub(crate) static BUILTIN_SCOPE: LazyLock<FxIndexMap<Name, PerNs>> = LazyLock::new(|| { | ||||
|  | @ -322,7 +322,7 @@ impl ItemScope { | |||
|     } | ||||
| 
 | ||||
|     pub fn extern_blocks(&self) -> impl Iterator<Item = ExternBlockId> + '_ { | ||||
|         self.extern_blocks.iter().flat_map(|it| it.iter()).copied() | ||||
|         self.extern_blocks.iter().copied() | ||||
|     } | ||||
| 
 | ||||
|     pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ { | ||||
|  | @ -435,7 +435,7 @@ impl ItemScope { | |||
|                 ModuleDefId::TraitId(t) => Some(t), | ||||
|                 _ => None, | ||||
|             }) | ||||
|             .chain(self.unnamed_trait_imports.keys().copied()) | ||||
|             .chain(self.unnamed_trait_imports.iter().map(|&(t, _)| t)) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ { | ||||
|  | @ -476,7 +476,7 @@ impl ItemScope { | |||
|     } | ||||
| 
 | ||||
|     pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) { | ||||
|         self.extern_blocks.get_or_insert_default().push(extern_block); | ||||
|         self.extern_blocks.push(extern_block); | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) { | ||||
|  | @ -564,7 +564,7 @@ impl ItemScope { | |||
| 
 | ||||
|     // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
 | ||||
|     pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { | ||||
|         self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis) | ||||
|         self.unnamed_trait_imports.iter().find(|&&(t, _)| t == tr).map(|(_, trait_)| trait_.vis) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn push_unnamed_trait( | ||||
|  | @ -573,7 +573,7 @@ impl ItemScope { | |||
|         vis: Visibility, | ||||
|         import: Option<ImportId>, | ||||
|     ) { | ||||
|         self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import }); | ||||
|         self.unnamed_trait_imports.push((tr, Item { def: (), vis, import })); | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn push_res_with_import( | ||||
|  | @ -720,33 +720,19 @@ impl ItemScope { | |||
|     } | ||||
| 
 | ||||
|     /// Marks everything that is not a procedural macro as private to `this_module`.
 | ||||
|     pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { | ||||
|     pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) { | ||||
|         self.types | ||||
|             .values_mut() | ||||
|             .map(|def| &mut def.vis) | ||||
|             .chain(self.values.values_mut().map(|def| &mut def.vis)) | ||||
|             .chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis)) | ||||
|             .for_each(|vis| match vis { | ||||
|                 &mut Visibility::Module(_, visibility_explicitness) => { | ||||
|                     *vis = Visibility::Module(this_module, visibility_explicitness) | ||||
|                 } | ||||
|                 Visibility::Public => { | ||||
|                     *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit) | ||||
|                 } | ||||
|             }); | ||||
|             .chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis)) | ||||
|             .for_each(|vis| *vis = Visibility::PubCrate(krate)); | ||||
| 
 | ||||
|         for mac in self.macros.values_mut() { | ||||
|             if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) { | ||||
|                 continue; | ||||
|             } | ||||
|             match mac.vis { | ||||
|                 Visibility::Module(_, visibility_explicitness) => { | ||||
|                     mac.vis = Visibility::Module(this_module, visibility_explicitness) | ||||
|                 } | ||||
|                 Visibility::Public => { | ||||
|                     mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit) | ||||
|                 } | ||||
|             } | ||||
|             mac.vis = Visibility::PubCrate(krate) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -817,9 +803,7 @@ impl ItemScope { | |||
|             macro_invocations, | ||||
|             extern_blocks, | ||||
|         } = self; | ||||
|         if let Some(it) = extern_blocks { | ||||
|             it.shrink_to_fit(); | ||||
|         } | ||||
|         extern_blocks.shrink_to_fit(); | ||||
|         types.shrink_to_fit(); | ||||
|         values.shrink_to_fit(); | ||||
|         macros.shrink_to_fit(); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -2,42 +2,40 @@ | |||
| 
 | ||||
| use std::{cell::OnceCell, collections::hash_map::Entry}; | ||||
| 
 | ||||
| use base_db::FxIndexSet; | ||||
| use hir_expand::{ | ||||
|     HirFileId, | ||||
|     mod_path::PathKind, | ||||
|     name::AsName, | ||||
|     span_map::{SpanMap, SpanMapRef}, | ||||
| }; | ||||
| use intern::{Symbol, sym}; | ||||
| use la_arena::Arena; | ||||
| use span::{AstIdMap, SyntaxContext}; | ||||
| use span::{AstIdMap, FileAstId, SyntaxContext}; | ||||
| use syntax::{ | ||||
|     AstNode, | ||||
|     ast::{self, HasModuleItem, HasName, IsString}, | ||||
|     ast::{self, HasModuleItem, HasName}, | ||||
| }; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     db::DefDatabase, | ||||
|     item_tree::{ | ||||
|         AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent, | ||||
|         FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree, | ||||
|         ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range, | ||||
|         RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, | ||||
|         TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness, | ||||
|         BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, | ||||
|         ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, | ||||
|         ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem, | ||||
|         Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, | ||||
|         VisibilityExplicitness, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| fn id<N>(index: Idx<N>) -> FileItemTreeId<N> { | ||||
|     FileItemTreeId(index) | ||||
| } | ||||
| 
 | ||||
| pub(super) struct Ctx<'a> { | ||||
|     db: &'a dyn DefDatabase, | ||||
|     tree: ItemTree, | ||||
|     source_ast_id_map: Arc<AstIdMap>, | ||||
|     span_map: OnceCell<SpanMap>, | ||||
|     file: HirFileId, | ||||
|     top_level: Vec<ModItemId>, | ||||
|     visibilities: FxIndexSet<RawVisibility>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Ctx<'a> { | ||||
|  | @ -48,6 +46,8 @@ impl<'a> Ctx<'a> { | |||
|             source_ast_id_map: db.ast_id_map(file), | ||||
|             file, | ||||
|             span_map: OnceCell::new(), | ||||
|             visibilities: FxIndexSet::default(), | ||||
|             top_level: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -56,13 +56,14 @@ impl<'a> Ctx<'a> { | |||
|     } | ||||
| 
 | ||||
|     pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { | ||||
|         self.tree.top_level = | ||||
|             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); | ||||
|         self.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); | ||||
|         self.tree.vis.arena = self.visibilities.into_iter().collect(); | ||||
|         self.tree.top_level = self.top_level.into_boxed_slice(); | ||||
|         self.tree | ||||
|     } | ||||
| 
 | ||||
|     pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree { | ||||
|         self.tree.top_level = stmts | ||||
|         self.top_level = stmts | ||||
|             .statements() | ||||
|             .filter_map(|stmt| { | ||||
|                 match stmt { | ||||
|  | @ -86,17 +87,19 @@ impl<'a> Ctx<'a> { | |||
|             if let Some(call) = tail_macro.macro_call() { | ||||
|                 cov_mark::hit!(macro_stmt_with_trailing_macro_expr); | ||||
|                 if let Some(mod_item) = self.lower_mod_item(&call.into()) { | ||||
|                     self.tree.top_level.push(mod_item); | ||||
|                     self.top_level.push(mod_item); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         self.tree.vis.arena = self.visibilities.into_iter().collect(); | ||||
|         self.tree.top_level = self.top_level.into_boxed_slice(); | ||||
|         self.tree | ||||
|     } | ||||
| 
 | ||||
|     pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree { | ||||
|         self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map())); | ||||
|         self.tree.top_level = block | ||||
|         self.tree.top_attrs = RawAttrs::new(self.db, block, self.span_map()); | ||||
|         self.top_level = block | ||||
|             .statements() | ||||
|             .filter_map(|stmt| match stmt { | ||||
|                 ast::Stmt::Item(item) => self.lower_mod_item(&item), | ||||
|  | @ -112,20 +115,17 @@ impl<'a> Ctx<'a> { | |||
|         if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() { | ||||
|             if let Some(call) = expr.macro_call() { | ||||
|                 if let Some(mod_item) = self.lower_mod_item(&call.into()) { | ||||
|                     self.tree.top_level.push(mod_item); | ||||
|                     self.top_level.push(mod_item); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         self.tree.vis.arena = self.visibilities.into_iter().collect(); | ||||
|         self.tree.top_level = self.top_level.into_boxed_slice(); | ||||
|         self.tree | ||||
|     } | ||||
| 
 | ||||
|     fn data(&mut self) -> &mut ItemTreeData { | ||||
|         self.tree.data_mut() | ||||
|     } | ||||
| 
 | ||||
|     fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> { | ||||
|         let mod_item: ModItem = match item { | ||||
|     fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItemId> { | ||||
|         let mod_item: ModItemId = match item { | ||||
|             ast::Item::Struct(ast) => self.lower_struct(ast)?.into(), | ||||
|             ast::Item::Union(ast) => self.lower_union(ast)?.into(), | ||||
|             ast::Item::Enum(ast) => self.lower_enum(ast)?.into(), | ||||
|  | @ -145,12 +145,12 @@ impl<'a> Ctx<'a> { | |||
|             ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), | ||||
|         }; | ||||
|         let attrs = RawAttrs::new(self.db, item, self.span_map()); | ||||
|         self.add_attrs(mod_item.into(), attrs); | ||||
|         self.add_attrs(mod_item.ast_id(), attrs); | ||||
| 
 | ||||
|         Some(mod_item) | ||||
|     } | ||||
| 
 | ||||
|     fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { | ||||
|     fn add_attrs(&mut self, item: FileAstId<ast::Item>, attrs: RawAttrs) { | ||||
|         if !attrs.is_empty() { | ||||
|             match self.tree.attrs.entry(item) { | ||||
|                 Entry::Occupied(mut entry) => { | ||||
|  | @ -163,208 +163,78 @@ impl<'a> Ctx<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option<AssocItem> { | ||||
|         let item: AssocItem = match item_node { | ||||
|             ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into), | ||||
|             ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), | ||||
|             ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()), | ||||
|             ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||||
|         }?; | ||||
|         let attrs = RawAttrs::new(self.db, item_node, self.span_map()); | ||||
|         self.add_attrs( | ||||
|             match item { | ||||
|                 AssocItem::Function(it) => AttrOwner::ModItem(ModItem::Function(it)), | ||||
|                 AssocItem::TypeAlias(it) => AttrOwner::ModItem(ModItem::TypeAlias(it)), | ||||
|                 AssocItem::Const(it) => AttrOwner::ModItem(ModItem::Const(it)), | ||||
|                 AssocItem::MacroCall(it) => AttrOwner::ModItem(ModItem::MacroCall(it)), | ||||
|             }, | ||||
|             attrs, | ||||
|         ); | ||||
|         Some(item) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { | ||||
|     fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<ItemTreeAstId<Struct>> { | ||||
|         let visibility = self.lower_visibility(strukt); | ||||
|         let name = strukt.name()?.as_name(); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(strukt); | ||||
|         let (fields, kind, attrs) = self.lower_fields(&strukt.kind()); | ||||
|         let res = Struct { name, visibility, fields, shape: kind, ast_id }; | ||||
|         let id = id(self.data().structs.alloc(res)); | ||||
|         let shape = adt_shape(strukt.kind()); | ||||
|         let res = Struct { name, visibility, shape }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Struct(res)); | ||||
| 
 | ||||
|         for (idx, attr) in attrs { | ||||
|             self.add_attrs( | ||||
|                 AttrOwner::Field( | ||||
|                     FieldParent::Struct(id), | ||||
|                     Idx::from_raw(RawIdx::from_u32(idx as u32)), | ||||
|                 ), | ||||
|                 attr, | ||||
|             ); | ||||
|         } | ||||
|         Some(id) | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_fields( | ||||
|         &mut self, | ||||
|         strukt_kind: &ast::StructKind, | ||||
|     ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) { | ||||
|         match strukt_kind { | ||||
|             ast::StructKind::Record(it) => { | ||||
|                 let mut fields = vec![]; | ||||
|                 let mut attrs = vec![]; | ||||
| 
 | ||||
|                 for (i, field) in it.fields().enumerate() { | ||||
|                     let data = self.lower_record_field(&field); | ||||
|                     fields.push(data); | ||||
|                     let attr = RawAttrs::new(self.db, &field, self.span_map()); | ||||
|                     if !attr.is_empty() { | ||||
|                         attrs.push((i, attr)) | ||||
|                     } | ||||
|                 } | ||||
|                 (fields.into(), FieldsShape::Record, attrs) | ||||
|             } | ||||
|             ast::StructKind::Tuple(it) => { | ||||
|                 let mut fields = vec![]; | ||||
|                 let mut attrs = vec![]; | ||||
| 
 | ||||
|                 for (i, field) in it.fields().enumerate() { | ||||
|                     let data = self.lower_tuple_field(i, &field); | ||||
|                     fields.push(data); | ||||
|                     let attr = RawAttrs::new(self.db, &field, self.span_map()); | ||||
|                     if !attr.is_empty() { | ||||
|                         attrs.push((i, attr)) | ||||
|                     } | ||||
|                 } | ||||
|                 (fields.into(), FieldsShape::Tuple, attrs) | ||||
|             } | ||||
|             ast::StructKind::Unit => (Box::default(), FieldsShape::Unit, Vec::default()), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn lower_record_field(&mut self, field: &ast::RecordField) -> Field { | ||||
|         let name = match field.name() { | ||||
|             Some(name) => name.as_name(), | ||||
|             None => Name::missing(), | ||||
|         }; | ||||
|         let visibility = self.lower_visibility(field); | ||||
| 
 | ||||
|         Field { name, visibility, is_unsafe: field.unsafe_token().is_some() } | ||||
|     } | ||||
| 
 | ||||
|     fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field { | ||||
|         let name = Name::new_tuple_field(idx); | ||||
|         let visibility = self.lower_visibility(field); | ||||
|         Field { name, visibility, is_unsafe: false } | ||||
|     } | ||||
| 
 | ||||
|     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> { | ||||
|     fn lower_union(&mut self, union: &ast::Union) -> Option<ItemTreeAstId<Union>> { | ||||
|         let visibility = self.lower_visibility(union); | ||||
|         let name = union.name()?.as_name(); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(union); | ||||
|         let (fields, _, attrs) = match union.record_field_list() { | ||||
|             Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), | ||||
|             None => (Box::default(), FieldsShape::Record, Vec::default()), | ||||
|         }; | ||||
|         let res = Union { name, visibility, fields, ast_id }; | ||||
|         let id = id(self.data().unions.alloc(res)); | ||||
|         for (idx, attr) in attrs { | ||||
|             self.add_attrs( | ||||
|                 AttrOwner::Field( | ||||
|                     FieldParent::Union(id), | ||||
|                     Idx::from_raw(RawIdx::from_u32(idx as u32)), | ||||
|                 ), | ||||
|                 attr, | ||||
|             ); | ||||
|         } | ||||
|         Some(id) | ||||
|         let res = Union { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> { | ||||
|     fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<ItemTreeAstId<Enum>> { | ||||
|         let visibility = self.lower_visibility(enum_); | ||||
|         let name = enum_.name()?.as_name(); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(enum_); | ||||
|         let variants = match &enum_.variant_list() { | ||||
|             Some(variant_list) => self.lower_variants(variant_list), | ||||
|             None => { | ||||
|                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) | ||||
|             } | ||||
|         }; | ||||
|         let res = Enum { name, visibility, variants, ast_id }; | ||||
|         let id = id(self.data().enums.alloc(res)); | ||||
|         Some(id) | ||||
|         let res = Enum { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> { | ||||
|         let start = self.next_variant_idx(); | ||||
|         for variant in variants.variants() { | ||||
|             let idx = self.lower_variant(&variant); | ||||
|             self.add_attrs(id(idx).into(), RawAttrs::new(self.db, &variant, self.span_map())); | ||||
|         } | ||||
|         let end = self.next_variant_idx(); | ||||
|         FileItemTreeId(start)..FileItemTreeId(end) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> { | ||||
|         let name = match variant.name() { | ||||
|             Some(name) => name.as_name(), | ||||
|             None => Name::missing(), | ||||
|         }; | ||||
|         let (fields, kind, attrs) = self.lower_fields(&variant.kind()); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(variant); | ||||
|         let res = Variant { name, fields, shape: kind, ast_id }; | ||||
|         let id = self.data().variants.alloc(res); | ||||
|         for (idx, attr) in attrs { | ||||
|             self.add_attrs( | ||||
|                 AttrOwner::Field( | ||||
|                     FieldParent::EnumVariant(FileItemTreeId(id)), | ||||
|                     Idx::from_raw(RawIdx::from_u32(idx as u32)), | ||||
|                 ), | ||||
|                 attr, | ||||
|             ); | ||||
|         } | ||||
|         id | ||||
|     } | ||||
| 
 | ||||
|     fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> { | ||||
|     fn lower_function(&mut self, func: &ast::Fn) -> Option<ItemTreeAstId<Function>> { | ||||
|         let visibility = self.lower_visibility(func); | ||||
|         let name = func.name()?.as_name(); | ||||
| 
 | ||||
|         let ast_id = self.source_ast_id_map.ast_id(func); | ||||
| 
 | ||||
|         let res = Function { name, visibility, ast_id }; | ||||
|         let res = Function { name, visibility }; | ||||
| 
 | ||||
|         let id = id(self.data().functions.alloc(res)); | ||||
|         Some(id) | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_type_alias( | ||||
|         &mut self, | ||||
|         type_alias: &ast::TypeAlias, | ||||
|     ) -> Option<FileItemTreeId<TypeAlias>> { | ||||
|     ) -> Option<ItemTreeAstId<TypeAlias>> { | ||||
|         let name = type_alias.name()?.as_name(); | ||||
|         let visibility = self.lower_visibility(type_alias); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(type_alias); | ||||
|         let res = TypeAlias { name, visibility, ast_id }; | ||||
|         let id = id(self.data().type_aliases.alloc(res)); | ||||
|         Some(id) | ||||
|         let res = TypeAlias { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> { | ||||
|     fn lower_static(&mut self, static_: &ast::Static) -> Option<ItemTreeAstId<Static>> { | ||||
|         let name = static_.name()?.as_name(); | ||||
|         let visibility = self.lower_visibility(static_); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(static_); | ||||
|         let res = Static { name, visibility, ast_id }; | ||||
|         Some(id(self.data().statics.alloc(res))) | ||||
|         let res = Static { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> { | ||||
|     fn lower_const(&mut self, konst: &ast::Const) -> ItemTreeAstId<Const> { | ||||
|         let name = konst.name().map(|it| it.as_name()); | ||||
|         let visibility = self.lower_visibility(konst); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(konst); | ||||
|         let res = Const { name, visibility, ast_id }; | ||||
|         id(self.data().consts.alloc(res)) | ||||
|         let res = Const { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res)); | ||||
|         ast_id | ||||
|     } | ||||
| 
 | ||||
|     fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { | ||||
|     fn lower_module(&mut self, module: &ast::Module) -> Option<ItemTreeAstId<Mod>> { | ||||
|         let name = module.name()?.as_name(); | ||||
|         let visibility = self.lower_visibility(module); | ||||
|         let kind = if module.semicolon_token().is_some() { | ||||
|  | @ -381,70 +251,59 @@ impl<'a> Ctx<'a> { | |||
|             } | ||||
|         }; | ||||
|         let ast_id = self.source_ast_id_map.ast_id(module); | ||||
|         let res = Mod { name, visibility, kind, ast_id }; | ||||
|         Some(id(self.data().mods.alloc(res))) | ||||
|         let res = Mod { name, visibility, kind }; | ||||
|         self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> { | ||||
|     fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<ItemTreeAstId<Trait>> { | ||||
|         let name = trait_def.name()?.as_name(); | ||||
|         let visibility = self.lower_visibility(trait_def); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(trait_def); | ||||
| 
 | ||||
|         let items = trait_def | ||||
|             .assoc_item_list() | ||||
|             .into_iter() | ||||
|             .flat_map(|list| list.assoc_items()) | ||||
|             .filter_map(|item_node| self.lower_assoc_item(&item_node)) | ||||
|             .collect(); | ||||
| 
 | ||||
|         let def = Trait { name, visibility, items, ast_id }; | ||||
|         let id = id(self.data().traits.alloc(def)); | ||||
|         Some(id) | ||||
|         let def = Trait { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_trait_alias( | ||||
|         &mut self, | ||||
|         trait_alias_def: &ast::TraitAlias, | ||||
|     ) -> Option<FileItemTreeId<TraitAlias>> { | ||||
|     ) -> Option<ItemTreeAstId<TraitAlias>> { | ||||
|         let name = trait_alias_def.name()?.as_name(); | ||||
|         let visibility = self.lower_visibility(trait_alias_def); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); | ||||
| 
 | ||||
|         let alias = TraitAlias { name, visibility, ast_id }; | ||||
|         let id = id(self.data().trait_aliases.alloc(alias)); | ||||
|         Some(id) | ||||
|         let alias = TraitAlias { name, visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> { | ||||
|     fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId<Impl> { | ||||
|         let ast_id = self.source_ast_id_map.ast_id(impl_def); | ||||
|         // We cannot use `assoc_items()` here as that does not include macro calls.
 | ||||
|         let items = impl_def | ||||
|             .assoc_item_list() | ||||
|             .into_iter() | ||||
|             .flat_map(|it| it.assoc_items()) | ||||
|             .filter_map(|item| self.lower_assoc_item(&item)) | ||||
|             .collect(); | ||||
|         // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
 | ||||
|         // type alias rather than a type parameter, so this is handled by the resolver.
 | ||||
|         let res = Impl { items, ast_id }; | ||||
|         id(self.data().impls.alloc(res)) | ||||
|         let res = Impl {}; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res)); | ||||
|         ast_id | ||||
|     } | ||||
| 
 | ||||
|     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> { | ||||
|     fn lower_use(&mut self, use_item: &ast::Use) -> Option<ItemTreeAstId<Use>> { | ||||
|         let visibility = self.lower_visibility(use_item); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(use_item); | ||||
|         let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| { | ||||
|             self.span_map().span_for_range(range).ctx | ||||
|         })?; | ||||
| 
 | ||||
|         let res = Use { visibility, ast_id, use_tree }; | ||||
|         Some(id(self.data().uses.alloc(res))) | ||||
|         let res = Use { visibility, use_tree }; | ||||
|         self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_extern_crate( | ||||
|         &mut self, | ||||
|         extern_crate: &ast::ExternCrate, | ||||
|     ) -> Option<FileItemTreeId<ExternCrate>> { | ||||
|     ) -> Option<ItemTreeAstId<ExternCrate>> { | ||||
|         let name = extern_crate.name_ref()?.as_name(); | ||||
|         let alias = extern_crate.rename().map(|a| { | ||||
|             a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||||
|  | @ -452,11 +311,12 @@ impl<'a> Ctx<'a> { | |||
|         let visibility = self.lower_visibility(extern_crate); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(extern_crate); | ||||
| 
 | ||||
|         let res = ExternCrate { name, alias, visibility, ast_id }; | ||||
|         Some(id(self.data().extern_crates.alloc(res))) | ||||
|         let res = ExternCrate { name, alias, visibility }; | ||||
|         self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | ||||
|     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<ItemTreeAstId<MacroCall>> { | ||||
|         let span_map = self.span_map(); | ||||
|         let path = m.path()?; | ||||
|         let range = path.syntax().text_range(); | ||||
|  | @ -465,31 +325,33 @@ impl<'a> Ctx<'a> { | |||
|         })?); | ||||
|         let ast_id = self.source_ast_id_map.ast_id(m); | ||||
|         let expand_to = hir_expand::ExpandTo::from_call_site(m); | ||||
|         let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx }; | ||||
|         Some(id(self.data().macro_calls.alloc(res))) | ||||
|         let res = MacroCall { path, expand_to, ctxt: span_map.span_for_range(range).ctx }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroCall(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> { | ||||
|     fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<ItemTreeAstId<MacroRules>> { | ||||
|         let name = m.name()?; | ||||
|         let ast_id = self.source_ast_id_map.ast_id(m); | ||||
| 
 | ||||
|         let res = MacroRules { name: name.as_name(), ast_id }; | ||||
|         Some(id(self.data().macro_rules.alloc(res))) | ||||
|         let res = MacroRules { name: name.as_name() }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<Macro2>> { | ||||
|     fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<ItemTreeAstId<Macro2>> { | ||||
|         let name = m.name()?; | ||||
| 
 | ||||
|         let ast_id = self.source_ast_id_map.ast_id(m); | ||||
|         let visibility = self.lower_visibility(m); | ||||
| 
 | ||||
|         let res = Macro2 { name: name.as_name(), ast_id, visibility }; | ||||
|         Some(id(self.data().macro_defs.alloc(res))) | ||||
|         let res = Macro2 { name: name.as_name(), visibility }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res)); | ||||
|         Some(ast_id) | ||||
|     } | ||||
| 
 | ||||
|     fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> { | ||||
|     fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> ItemTreeAstId<ExternBlock> { | ||||
|         let ast_id = self.source_ast_id_map.ast_id(block); | ||||
|         let abi = block.abi().map(lower_abi); | ||||
|         let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| { | ||||
|             list.extern_items() | ||||
|                 .filter_map(|item| { | ||||
|  | @ -497,42 +359,44 @@ impl<'a> Ctx<'a> { | |||
|                     // (in other words, the knowledge that they're in an extern block must not be used).
 | ||||
|                     // This is because an extern block can contain macros whose ItemTree's top-level items
 | ||||
|                     // should be considered to be in an extern block too.
 | ||||
|                     let mod_item: ModItem = match &item { | ||||
|                     let mod_item: ModItemId = match &item { | ||||
|                         ast::ExternItem::Fn(ast) => self.lower_function(ast)?.into(), | ||||
|                         ast::ExternItem::Static(ast) => self.lower_static(ast)?.into(), | ||||
|                         ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(ty)?.into(), | ||||
|                         ast::ExternItem::MacroCall(call) => self.lower_macro_call(call)?.into(), | ||||
|                     }; | ||||
|                     let attrs = RawAttrs::new(self.db, &item, self.span_map()); | ||||
|                     self.add_attrs(mod_item.into(), attrs); | ||||
|                     self.add_attrs(mod_item.ast_id(), attrs); | ||||
|                     Some(mod_item) | ||||
|                 }) | ||||
|                 .collect() | ||||
|         }); | ||||
| 
 | ||||
|         let res = ExternBlock { abi, ast_id, children }; | ||||
|         id(self.data().extern_blocks.alloc(res)) | ||||
|         let res = ExternBlock { children }; | ||||
|         self.tree.small_data.insert(ast_id.upcast(), SmallModItem::ExternBlock(res)); | ||||
|         ast_id | ||||
|     } | ||||
| 
 | ||||
|     fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId { | ||||
|         let vis = visibility_from_ast(self.db, item.visibility(), &mut |range| { | ||||
|             self.span_map().span_for_range(range).ctx | ||||
|         }); | ||||
|         self.data().vis.alloc(vis) | ||||
|         match &vis { | ||||
|             RawVisibility::Public => RawVisibilityId::PUB, | ||||
|             RawVisibility::Module(path, explicitness) if path.segments().is_empty() => { | ||||
|                 match (path.kind, explicitness) { | ||||
|                     (PathKind::SELF, VisibilityExplicitness::Explicit) => { | ||||
|                         RawVisibilityId::PRIV_EXPLICIT | ||||
|                     } | ||||
| 
 | ||||
|     fn next_variant_idx(&self) -> Idx<Variant> { | ||||
|         Idx::from_raw(RawIdx::from( | ||||
|             self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), | ||||
|         )) | ||||
|                     (PathKind::SELF, VisibilityExplicitness::Implicit) => { | ||||
|                         RawVisibilityId::PRIV_IMPLICIT | ||||
|                     } | ||||
|                     (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, | ||||
|                     _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32), | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| fn lower_abi(abi: ast::Abi) -> Symbol { | ||||
|     match abi.abi_string() { | ||||
|         Some(tok) => Symbol::intern(tok.text_without_quotes()), | ||||
|         // `extern` default to be `extern "C"`.
 | ||||
|         _ => sym::C, | ||||
|             _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -561,17 +425,15 @@ impl UseTreeLowering<'_> { | |||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|             self.mapping.alloc(tree.clone()); | ||||
|             let list = use_tree_list | ||||
|                 .use_trees() | ||||
|                 .filter_map(|tree| self.lower_use_tree(tree, span_for_range)) | ||||
|                 .collect(); | ||||
| 
 | ||||
|             Some( | ||||
|                 self.use_tree( | ||||
|                     UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list }, | ||||
|                     tree, | ||||
|                 ), | ||||
|             ) | ||||
|             Some(UseTree { | ||||
|                 kind: UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list }, | ||||
|             }) | ||||
|         } else { | ||||
|             let is_glob = tree.star_token().is_some(); | ||||
|             let path = match tree.path() { | ||||
|  | @ -590,22 +452,19 @@ impl UseTreeLowering<'_> { | |||
|                     if path.is_none() { | ||||
|                         cov_mark::hit!(glob_enum_group); | ||||
|                     } | ||||
|                     Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree)) | ||||
|                     self.mapping.alloc(tree.clone()); | ||||
|                     Some(UseTree { kind: UseTreeKind::Glob { path: path.map(Interned::new) } }) | ||||
|                 } | ||||
|                 // Globs can't be renamed
 | ||||
|                 (_, Some(_), true) | (None, None, false) => None, | ||||
|                 // `bla::{ as Name}` is invalid
 | ||||
|                 (None, Some(_), false) => None, | ||||
|                 (Some(path), alias, false) => Some( | ||||
|                     self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree), | ||||
|                 ), | ||||
|                 (Some(path), alias, false) => { | ||||
|                     self.mapping.alloc(tree.clone()); | ||||
|                     Some(UseTree { kind: UseTreeKind::Single { path: Interned::new(path), alias } }) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree { | ||||
|         let index = self.mapping.alloc(ast); | ||||
|         UseTree { index, kind } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -626,7 +485,7 @@ fn private_vis() -> RawVisibility { | |||
|     ) | ||||
| } | ||||
| 
 | ||||
| fn visibility_from_ast( | ||||
| pub(crate) fn visibility_from_ast( | ||||
|     db: &dyn DefDatabase, | ||||
|     node: Option<ast::Visibility>, | ||||
|     span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, | ||||
|  | @ -647,3 +506,11 @@ fn visibility_from_ast( | |||
|     }; | ||||
|     RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit) | ||||
| } | ||||
| 
 | ||||
| fn adt_shape(kind: StructKind) -> FieldsShape { | ||||
|     match kind { | ||||
|         StructKind::Record(_) => FieldsShape::Record, | ||||
|         StructKind::Tuple(_) => FieldsShape::Tuple, | ||||
|         StructKind::Unit => FieldsShape::Unit, | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -2,15 +2,13 @@ | |||
| 
 | ||||
| use std::fmt::{self, Write}; | ||||
| 
 | ||||
| use la_arena::{Idx, RawIdx}; | ||||
| use span::{Edition, ErasedFileAstId}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     item_tree::{ | ||||
|         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent, | ||||
|         FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod, | ||||
|         ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, | ||||
|         Union, Use, UseTree, UseTreeKind, Variant, | ||||
|         Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree, | ||||
|         Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static, | ||||
|         Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, | ||||
|     }, | ||||
|     visibility::RawVisibility, | ||||
| }; | ||||
|  | @ -19,9 +17,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Ed | |||
|     let mut p = | ||||
|         Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition }; | ||||
| 
 | ||||
|     if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) { | ||||
|         p.print_attrs(attrs, true, "\n"); | ||||
|     } | ||||
|     p.print_attrs(&tree.top_attrs, true, "\n"); | ||||
|     p.blank(); | ||||
| 
 | ||||
|     for item in tree.top_level_items() { | ||||
|  | @ -103,8 +99,8 @@ impl Printer<'_> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) { | ||||
|         if let Some(attrs) = self.tree.attrs.get(&of.into()) { | ||||
|     fn print_attrs_of(&mut self, of: ModItemId, separated_by: &str) { | ||||
|         if let Some(attrs) = self.tree.attrs.get(&of.ast_id()) { | ||||
|             self.print_attrs(attrs, false, separated_by); | ||||
|         } | ||||
|     } | ||||
|  | @ -112,50 +108,22 @@ impl Printer<'_> { | |||
|     fn print_visibility(&mut self, vis: RawVisibilityId) { | ||||
|         match &self.tree[vis] { | ||||
|             RawVisibility::Module(path, _expl) => { | ||||
|                 w!(self, "pub({}) ", path.display(self.db, self.edition)) | ||||
|                 w!(self, "pub(in {}) ", path.display(self.db, self.edition)) | ||||
|             } | ||||
|             RawVisibility::Public => w!(self, "pub "), | ||||
|             RawVisibility::PubCrate => w!(self, "pub(crate) "), | ||||
|             RawVisibility::PubSelf(_) => w!(self, "pub(self) "), | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { | ||||
|         let edition = self.edition; | ||||
|     fn print_fields(&mut self, kind: FieldsShape) { | ||||
|         match kind { | ||||
|             FieldsShape::Record => { | ||||
|                 self.whitespace(); | ||||
|                 w!(self, "{{"); | ||||
|                 self.indented(|this| { | ||||
|                     for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { | ||||
|                         this.print_attrs_of( | ||||
|                             AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), | ||||
|                             "\n", | ||||
|                         ); | ||||
|                         this.print_visibility(*visibility); | ||||
|                         if *is_unsafe { | ||||
|                             w!(this, "unsafe "); | ||||
|                         } | ||||
| 
 | ||||
|                         wln!(this, "{},", name.display(self.db, edition)); | ||||
|                     } | ||||
|                 }); | ||||
|                 w!(self, "}}"); | ||||
|                 w!(self, "{{ ... }}"); | ||||
|             } | ||||
|             FieldsShape::Tuple => { | ||||
|                 w!(self, "("); | ||||
|                 self.indented(|this| { | ||||
|                     for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { | ||||
|                         this.print_attrs_of( | ||||
|                             AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), | ||||
|                             "\n", | ||||
|                         ); | ||||
|                         this.print_visibility(*visibility); | ||||
|                         if *is_unsafe { | ||||
|                             w!(this, "unsafe "); | ||||
|                         } | ||||
|                         wln!(this, "{},", name.display(self.db, edition)); | ||||
|                     } | ||||
|                 }); | ||||
|                 w!(self, ")"); | ||||
|                 w!(self, "(...)"); | ||||
|             } | ||||
|             FieldsShape::Unit => {} | ||||
|         } | ||||
|  | @ -191,20 +159,20 @@ impl Printer<'_> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn print_mod_item(&mut self, item: ModItem) { | ||||
|     fn print_mod_item(&mut self, item: ModItemId) { | ||||
|         self.print_attrs_of(item, "\n"); | ||||
| 
 | ||||
|         match item { | ||||
|             ModItem::Use(it) => { | ||||
|                 let Use { visibility, use_tree, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Use(ast_id) => { | ||||
|                 let Use { visibility, use_tree } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "use "); | ||||
|                 self.print_use_tree(use_tree); | ||||
|                 wln!(self, ";"); | ||||
|             } | ||||
|             ModItem::ExternCrate(it) => { | ||||
|                 let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::ExternCrate(ast_id) => { | ||||
|                 let ExternCrate { name, alias, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "extern crate {}", name.display(self.db, self.edition)); | ||||
|  | @ -213,14 +181,10 @@ impl Printer<'_> { | |||
|                 } | ||||
|                 wln!(self, ";"); | ||||
|             } | ||||
|             ModItem::ExternBlock(it) => { | ||||
|                 let ExternBlock { abi, ast_id, children } = &self.tree[it]; | ||||
|             ModItemId::ExternBlock(ast_id) => { | ||||
|                 let ExternBlock { children } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 w!(self, "extern "); | ||||
|                 if let Some(abi) = abi { | ||||
|                     w!(self, "\"{}\" ", abi); | ||||
|                 } | ||||
|                 w!(self, "{{"); | ||||
|                 w!(self, "extern {{"); | ||||
|                 self.indented(|this| { | ||||
|                     for child in &**children { | ||||
|                         this.print_mod_item(*child); | ||||
|  | @ -228,52 +192,40 @@ impl Printer<'_> { | |||
|                 }); | ||||
|                 wln!(self, "}}"); | ||||
|             } | ||||
|             ModItem::Function(it) => { | ||||
|                 let Function { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Function(ast_id) => { | ||||
|                 let Function { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 wln!(self, "fn {};", name.display(self.db, self.edition)); | ||||
|             } | ||||
|             ModItem::Struct(it) => { | ||||
|                 let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Struct(ast_id) => { | ||||
|                 let Struct { visibility, name, shape: kind } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "struct {}", name.display(self.db, self.edition)); | ||||
|                 self.print_fields(FieldParent::Struct(it), *kind, fields); | ||||
|                 self.print_fields(*kind); | ||||
|                 if matches!(kind, FieldsShape::Record) { | ||||
|                     wln!(self); | ||||
|                 } else { | ||||
|                     wln!(self, ";"); | ||||
|                 } | ||||
|             } | ||||
|             ModItem::Union(it) => { | ||||
|                 let Union { name, visibility, fields, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Union(ast_id) => { | ||||
|                 let Union { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "union {}", name.display(self.db, self.edition)); | ||||
|                 self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields); | ||||
|                 self.print_fields(FieldsShape::Record); | ||||
|                 wln!(self); | ||||
|             } | ||||
|             ModItem::Enum(it) => { | ||||
|                 let Enum { name, visibility, variants, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Enum(ast_id) => { | ||||
|                 let Enum { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "enum {}", name.display(self.db, self.edition)); | ||||
|                 let edition = self.edition; | ||||
|                 self.indented(|this| { | ||||
|                     for variant in FileItemTreeId::range_iter(variants.clone()) { | ||||
|                         let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; | ||||
|                         this.print_ast_id(ast_id.erase()); | ||||
|                         this.print_attrs_of(variant, "\n"); | ||||
|                         w!(this, "{}", name.display(self.db, edition)); | ||||
|                         this.print_fields(FieldParent::EnumVariant(variant), *kind, fields); | ||||
|                         wln!(this, ","); | ||||
|                 w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition)); | ||||
|             } | ||||
|                 }); | ||||
|                 wln!(self, "}}"); | ||||
|             } | ||||
|             ModItem::Const(it) => { | ||||
|                 let Const { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Const(ast_id) => { | ||||
|                 let Const { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "const "); | ||||
|  | @ -283,8 +235,8 @@ impl Printer<'_> { | |||
|                 } | ||||
|                 wln!(self, " = _;"); | ||||
|             } | ||||
|             ModItem::Static(it) => { | ||||
|                 let Static { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Static(ast_id) => { | ||||
|                 let Static { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "static "); | ||||
|  | @ -292,45 +244,33 @@ impl Printer<'_> { | |||
|                 w!(self, " = _;"); | ||||
|                 wln!(self); | ||||
|             } | ||||
|             ModItem::Trait(it) => { | ||||
|                 let Trait { name, visibility, items, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Trait(ast_id) => { | ||||
|                 let Trait { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "trait {} {{", name.display(self.db, self.edition)); | ||||
|                 self.indented(|this| { | ||||
|                     for item in &**items { | ||||
|                         this.print_mod_item((*item).into()); | ||||
|                 w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); | ||||
|             } | ||||
|                 }); | ||||
|                 wln!(self, "}}"); | ||||
|             } | ||||
|             ModItem::TraitAlias(it) => { | ||||
|                 let TraitAlias { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::TraitAlias(ast_id) => { | ||||
|                 let TraitAlias { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); | ||||
|             } | ||||
|             ModItem::Impl(it) => { | ||||
|                 let Impl { items, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Impl(ast_id) => { | ||||
|                 let Impl {} = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 w!(self, "impl {{"); | ||||
|                 self.indented(|this| { | ||||
|                     for item in &**items { | ||||
|                         this.print_mod_item((*item).into()); | ||||
|                 w!(self, "impl {{ ... }}"); | ||||
|             } | ||||
|                 }); | ||||
|                 wln!(self, "}}"); | ||||
|             } | ||||
|             ModItem::TypeAlias(it) => { | ||||
|                 let TypeAlias { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::TypeAlias(ast_id) => { | ||||
|                 let TypeAlias { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "type {}", name.display(self.db, self.edition)); | ||||
|                 w!(self, ";"); | ||||
|                 wln!(self); | ||||
|             } | ||||
|             ModItem::Mod(it) => { | ||||
|                 let Mod { name, visibility, kind, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Mod(ast_id) => { | ||||
|                 let Mod { name, visibility, kind } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 w!(self, "mod {}", name.display(self.db, self.edition)); | ||||
|  | @ -349,24 +289,24 @@ impl Printer<'_> { | |||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             ModItem::MacroCall(it) => { | ||||
|                 let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it]; | ||||
|             ModItemId::MacroCall(ast_id) => { | ||||
|                 let MacroCall { path, expand_to, ctxt } = &self.tree[ast_id]; | ||||
|                 let _ = writeln!( | ||||
|                     self, | ||||
|                     "// AstId: {:?}, SyntaxContextId: {}, ExpandTo: {:?}", | ||||
|                     ast_id.erase().into_raw(), | ||||
|                     "// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}", | ||||
|                     ast_id.erase(), | ||||
|                     ctxt, | ||||
|                     expand_to | ||||
|                 ); | ||||
|                 wln!(self, "{}!(...);", path.display(self.db, self.edition)); | ||||
|             } | ||||
|             ModItem::MacroRules(it) => { | ||||
|                 let MacroRules { name, ast_id } = &self.tree[it]; | ||||
|             ModItemId::MacroRules(ast_id) => { | ||||
|                 let MacroRules { name } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition)); | ||||
|             } | ||||
|             ModItem::Macro2(it) => { | ||||
|                 let Macro2 { name, visibility, ast_id } = &self.tree[it]; | ||||
|             ModItemId::Macro2(ast_id) => { | ||||
|                 let Macro2 { name, visibility } = &self.tree[ast_id]; | ||||
|                 self.print_ast_id(ast_id.erase()); | ||||
|                 self.print_visibility(*visibility); | ||||
|                 wln!(self, "macro {} {{ ... }}", name.display(self.db, self.edition)); | ||||
|  | @ -377,7 +317,7 @@ impl Printer<'_> { | |||
|     } | ||||
| 
 | ||||
|     fn print_ast_id(&mut self, ast_id: ErasedFileAstId) { | ||||
|         wln!(self, "// AstId: {:?}", ast_id.into_raw()); | ||||
|         wln!(self, "// AstId: {ast_id:#?}"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,23 +35,23 @@ use a::{c, d::{e}}; | |||
|             #![no_std] | ||||
|             #![doc = " another file comment"] | ||||
| 
 | ||||
|             // AstId: 1
 | ||||
|             // AstId: ExternCrate[5A82, 0]
 | ||||
|             pub(self) extern crate self as renamed; | ||||
| 
 | ||||
|             // AstId: 2
 | ||||
|             pub(super) extern crate bli; | ||||
|             // AstId: ExternCrate[7E1C, 0]
 | ||||
|             pub(in super) extern crate bli; | ||||
| 
 | ||||
|             // AstId: 3
 | ||||
|             // AstId: Use[0000, 0]
 | ||||
|             pub use crate::path::{nested, items as renamed, Trait as _}; | ||||
| 
 | ||||
|             // AstId: 4
 | ||||
|             // AstId: Use[0000, 1]
 | ||||
|             pub(self) use globs::*; | ||||
| 
 | ||||
|             #[doc = " docs on import"] | ||||
|             // AstId: 5
 | ||||
|             // AstId: Use[0000, 2]
 | ||||
|             pub(self) use crate::{A, B}; | ||||
| 
 | ||||
|             // AstId: 6
 | ||||
|             // AstId: Use[0000, 3]
 | ||||
|             pub(self) use a::{c, d::{e}}; | ||||
|         "##]],
 | ||||
|     ); | ||||
|  | @ -73,23 +73,23 @@ extern "C" { | |||
|     fn ex_fn(); | ||||
| } | ||||
|         "#,
 | ||||
|         expect![[r##" | ||||
|         expect![[r#" | ||||
|             #[on_extern_block] | ||||
|             // AstId: 1
 | ||||
|             extern "C" { | ||||
|             // AstId: ExternBlock[0000, 0]
 | ||||
|             extern { | ||||
|                 #[on_extern_type] | ||||
|                 // AstId: 2
 | ||||
|                 // AstId: TypeAlias[9FDF, 0]
 | ||||
|                 pub(self) type ExType; | ||||
| 
 | ||||
|                 #[on_extern_static] | ||||
|                 // AstId: 3
 | ||||
|                 // AstId: Static[43C1, 0]
 | ||||
|                 pub(self) static EX_STATIC = _; | ||||
| 
 | ||||
|                 #[on_extern_fn] | ||||
|                 // AstId: 4
 | ||||
|                 // AstId: Fn[452D, 0]
 | ||||
|                 pub(self) fn ex_fn; | ||||
|             } | ||||
|         "##]],
 | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  | @ -124,44 +124,21 @@ enum E { | |||
| } | ||||
|         "#,
 | ||||
|         expect![[r#" | ||||
|             // AstId: 1
 | ||||
|             // AstId: Struct[DFF3, 0]
 | ||||
|             pub(self) struct Unit; | ||||
| 
 | ||||
|             #[derive(Debug)] | ||||
|             // AstId: 2
 | ||||
|             pub(self) struct Struct { | ||||
|                 #[doc = " fld docs"] | ||||
|                 pub(self) fld, | ||||
|             } | ||||
|             // AstId: Struct[C7A1, 0]
 | ||||
|             pub(self) struct Struct { ... } | ||||
| 
 | ||||
|             // AstId: 3
 | ||||
|             pub(self) struct Tuple( | ||||
|                 #[attr] | ||||
|                 pub(self) 0, | ||||
|             ); | ||||
|             // AstId: Struct[DAC2, 0]
 | ||||
|             pub(self) struct Tuple(...); | ||||
| 
 | ||||
|             // AstId: 4
 | ||||
|             pub(self) union Ize { | ||||
|                 pub(self) a, | ||||
|                 pub(self) b, | ||||
|             } | ||||
|             // AstId: Union[2DBB, 0]
 | ||||
|             pub(self) union Ize { ... } | ||||
| 
 | ||||
|             // AstId: 5
 | ||||
|             pub(self) enum E | ||||
|                 // AstId: 6
 | ||||
|                 #[doc = " comment on Unit"] | ||||
|                 Unit, | ||||
|                 // AstId: 7
 | ||||
|                 #[doc = " comment on Tuple"] | ||||
|                 Tuple( | ||||
|                     pub(self) 0, | ||||
|                 ), | ||||
|                 // AstId: 8
 | ||||
|                 Struct { | ||||
|                     #[doc = " comment on a: u8"] | ||||
|                     pub(self) a, | ||||
|                 }, | ||||
|             } | ||||
|             // AstId: Enum[7FF8, 0]
 | ||||
|             pub(self) enum E { ... } | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
|  | @ -185,25 +162,19 @@ trait Tr: SuperTrait + 'lifetime { | |||
| } | ||||
|         "#,
 | ||||
|         expect![[r#" | ||||
|             // AstId: 1
 | ||||
|             // AstId: Static[B393, 0]
 | ||||
|             pub static ST = _; | ||||
| 
 | ||||
|             // AstId: 2
 | ||||
|             // AstId: Const[B309, 0]
 | ||||
|             pub(self) const _ = _; | ||||
| 
 | ||||
|             #[attr] | ||||
|             #[inner_attr_in_fn] | ||||
|             // AstId: 3
 | ||||
|             // AstId: Fn[75E3, 0]
 | ||||
|             pub(self) fn f; | ||||
| 
 | ||||
|             // AstId: 4
 | ||||
|             pub(self) trait Tr { | ||||
|                 // AstId: 6
 | ||||
|                 pub(self) type Assoc; | ||||
| 
 | ||||
|                 // AstId: 7
 | ||||
|                 pub(self) fn method; | ||||
|             } | ||||
|             // AstId: Trait[2998, 0]
 | ||||
|             pub(self) trait Tr { ... } | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
|  | @ -226,16 +197,16 @@ mod outline; | |||
|         expect![[r##" | ||||
|             #[doc = " outer"] | ||||
|             #[doc = " inner"] | ||||
|             // AstId: 1
 | ||||
|             // AstId: Module[CF93, 0]
 | ||||
|             pub(self) mod inline { | ||||
|                 // AstId: 3
 | ||||
|                 // AstId: Use[0000, 0]
 | ||||
|                 pub(self) use super::*; | ||||
| 
 | ||||
|                 // AstId: 4
 | ||||
|                 // AstId: Fn[1B26, 0]
 | ||||
|                 pub(self) fn fn_in_module; | ||||
|             } | ||||
| 
 | ||||
|             // AstId: 2
 | ||||
|             // AstId: Module[8994, 0]
 | ||||
|             pub(self) mod outline; | ||||
|         "##]],
 | ||||
|     ); | ||||
|  | @ -254,13 +225,13 @@ pub macro m2() {} | |||
| m!(); | ||||
|         "#,
 | ||||
|         expect![[r#" | ||||
|             // AstId: 1
 | ||||
|             // AstId: MacroRules[88CE, 0]
 | ||||
|             macro_rules! m { ... } | ||||
| 
 | ||||
|             // AstId: 2
 | ||||
|             // AstId: MacroDef[DC34, 0]
 | ||||
|             pub macro m2 { ... } | ||||
| 
 | ||||
|             // AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items
 | ||||
|             // AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
 | ||||
|             m!(...); | ||||
|         "#]],
 | ||||
|     ); | ||||
|  | @ -273,7 +244,7 @@ fn pub_self() { | |||
| pub(self) struct S; | ||||
|         "#,
 | ||||
|         expect![[r#" | ||||
|             // AstId: 1
 | ||||
|             // AstId: Struct[42E2, 0]
 | ||||
|             pub(self) struct S; | ||||
|         "#]],
 | ||||
|     ) | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt | |||
|     for (_, module_data) in crate_def_map.modules() { | ||||
|         for impl_def in module_data.scope.impls() { | ||||
|             lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); | ||||
|             for &(_, assoc) in db.impl_items(impl_def).items.iter() { | ||||
|             for &(_, assoc) in impl_def.impl_items(db).items.iter() { | ||||
|                 match assoc { | ||||
|                     AssocItemId::FunctionId(f) => { | ||||
|                         lang_items.collect_lang_item(db, f, LangItemTarget::Function) | ||||
|  | @ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt | |||
|                 } | ||||
|                 ModuleDefId::AdtId(AdtId::EnumId(e)) => { | ||||
|                     lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); | ||||
|                     db.enum_variants(e).variants.iter().for_each(|&(id, _)| { | ||||
|                     e.enum_variants(db).variants.iter().for_each(|&(id, _, _)| { | ||||
|                         lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); | ||||
|                     }); | ||||
|                 } | ||||
|  | @ -377,6 +377,7 @@ language_item_table! { | |||
|     AsyncFnMut,              sym::async_fn_mut,        async_fn_mut_trait,         Target::Trait,          GenericRequirement::Exact(1); | ||||
|     AsyncFnOnce,             sym::async_fn_once,       async_fn_once_trait,        Target::Trait,          GenericRequirement::Exact(1); | ||||
| 
 | ||||
|     AsyncFnOnceOutput,       sym::async_fn_once_output,async_fn_once_output,       Target::AssocTy,        GenericRequirement::None; | ||||
|     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None; | ||||
| 
 | ||||
|     Future,                  sym::future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0); | ||||
|  |  | |||
|  | @ -49,8 +49,9 @@ pub mod find_path; | |||
| pub mod import_map; | ||||
| pub mod visibility; | ||||
| 
 | ||||
| use intern::{Interned, sym}; | ||||
| use intern::{Interned, Symbol, sym}; | ||||
| pub use rustc_abi as layout; | ||||
| use thin_vec::ThinVec; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| pub use crate::signatures::LocalFieldId; | ||||
|  | @ -74,12 +75,11 @@ use hir_expand::{ | |||
|     name::Name, | ||||
|     proc_macro::{CustomProcMacroExpander, ProcMacroKind}, | ||||
| }; | ||||
| use item_tree::ExternBlock; | ||||
| use la_arena::Idx; | ||||
| use nameres::DefMap; | ||||
| use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; | ||||
| use stdx::impl_from; | ||||
| use syntax::ast; | ||||
| use syntax::{AstNode, ast}; | ||||
| 
 | ||||
| pub use hir_expand::{Intern, Lookup, tt}; | ||||
| 
 | ||||
|  | @ -88,12 +88,11 @@ use crate::{ | |||
|     builtin_type::BuiltinType, | ||||
|     db::DefDatabase, | ||||
|     hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, | ||||
|     item_tree::{ | ||||
|         Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, | ||||
|         Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, | ||||
|     nameres::{ | ||||
|         LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map, | ||||
|         diagnostics::DefDiagnostics, | ||||
|     }, | ||||
|     nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, | ||||
|     signatures::VariantFields, | ||||
|     signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, | ||||
| }; | ||||
| 
 | ||||
| type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>; | ||||
|  | @ -113,70 +112,111 @@ pub struct ImportPathConfig { | |||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct ItemLoc<N: ItemTreeNode> { | ||||
| pub struct ItemLoc<N: AstIdNode> { | ||||
|     pub container: ModuleId, | ||||
|     pub id: ItemTreeId<N>, | ||||
|     pub id: AstId<N>, | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Clone for ItemLoc<N> { | ||||
| impl<N: AstIdNode> Clone for ItemLoc<N> { | ||||
|     fn clone(&self) -> Self { | ||||
|         *self | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Copy for ItemLoc<N> {} | ||||
| impl<N: AstIdNode> Copy for ItemLoc<N> {} | ||||
| 
 | ||||
| impl<N: ItemTreeNode> PartialEq for ItemLoc<N> { | ||||
| impl<N: AstIdNode> PartialEq for ItemLoc<N> { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.container == other.container && self.id == other.id | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Eq for ItemLoc<N> {} | ||||
| impl<N: AstIdNode> Eq for ItemLoc<N> {} | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Hash for ItemLoc<N> { | ||||
| impl<N: AstIdNode> Hash for ItemLoc<N> { | ||||
|     fn hash<H: Hasher>(&self, state: &mut H) { | ||||
|         self.container.hash(state); | ||||
|         self.id.hash(state); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: AstIdNode> HasModule for ItemLoc<N> { | ||||
|     #[inline] | ||||
|     fn module(&self, _db: &dyn DefDatabase) -> ModuleId { | ||||
|         self.container | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct AssocItemLoc<N: ItemTreeNode> { | ||||
| pub struct AssocItemLoc<N: AstIdNode> { | ||||
|     // FIXME: Store this as an erased `salsa::Id` to save space
 | ||||
|     pub container: ItemContainerId, | ||||
|     pub id: ItemTreeId<N>, | ||||
|     pub id: AstId<N>, | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Clone for AssocItemLoc<N> { | ||||
| impl<N: AstIdNode> Clone for AssocItemLoc<N> { | ||||
|     fn clone(&self) -> Self { | ||||
|         *self | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {} | ||||
| impl<N: AstIdNode> Copy for AssocItemLoc<N> {} | ||||
| 
 | ||||
| impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> { | ||||
| impl<N: AstIdNode> PartialEq for AssocItemLoc<N> { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.container == other.container && self.id == other.id | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {} | ||||
| impl<N: AstIdNode> Eq for AssocItemLoc<N> {} | ||||
| 
 | ||||
| impl<N: ItemTreeNode> Hash for AssocItemLoc<N> { | ||||
| impl<N: AstIdNode> Hash for AssocItemLoc<N> { | ||||
|     fn hash<H: Hasher>(&self, state: &mut H) { | ||||
|         self.container.hash(state); | ||||
|         self.id.hash(state); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait ItemTreeLoc { | ||||
| impl<N: AstIdNode> HasModule for AssocItemLoc<N> { | ||||
|     #[inline] | ||||
|     fn module(&self, db: &dyn DefDatabase) -> ModuleId { | ||||
|         self.container.module(db) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait AstIdLoc { | ||||
|     type Container; | ||||
|     type Id; | ||||
|     fn item_tree_id(&self) -> ItemTreeId<Self::Id>; | ||||
|     type Ast: AstNode; | ||||
|     fn ast_id(&self) -> AstId<Self::Ast>; | ||||
|     fn container(&self) -> Self::Container; | ||||
| } | ||||
| 
 | ||||
| impl<N: AstIdNode> AstIdLoc for ItemLoc<N> { | ||||
|     type Container = ModuleId; | ||||
|     type Ast = N; | ||||
|     #[inline] | ||||
|     fn ast_id(&self) -> AstId<Self::Ast> { | ||||
|         self.id | ||||
|     } | ||||
|     #[inline] | ||||
|     fn container(&self) -> Self::Container { | ||||
|         self.container | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<N: AstIdNode> AstIdLoc for AssocItemLoc<N> { | ||||
|     type Container = ItemContainerId; | ||||
|     type Ast = N; | ||||
|     #[inline] | ||||
|     fn ast_id(&self) -> AstId<Self::Ast> { | ||||
|         self.id | ||||
|     } | ||||
|     #[inline] | ||||
|     fn container(&self) -> Self::Container { | ||||
|         self.container | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_intern { | ||||
|     ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { | ||||
|         impl_intern_key!($id, $loc); | ||||
|  | @ -186,74 +226,103 @@ macro_rules! impl_intern { | |||
| 
 | ||||
| macro_rules! impl_loc { | ||||
|     ($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => { | ||||
|         impl ItemTreeLoc for $loc { | ||||
|         impl AstIdLoc for $loc { | ||||
|             type Container = $container_type; | ||||
|             type Id = $id_ty; | ||||
|             fn item_tree_id(&self) -> ItemTreeId<Self::Id> { | ||||
|             type Ast = ast::$id_ty; | ||||
|             fn ast_id(&self) -> AstId<Self::Ast> { | ||||
|                 self.$id | ||||
|             } | ||||
|             fn container(&self) -> Self::Container { | ||||
|                 self.$container | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl HasModule for $loc { | ||||
|             #[inline] | ||||
|             fn module(&self, db: &dyn DefDatabase) -> ModuleId { | ||||
|                 self.$container.module(db) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| type FunctionLoc = AssocItemLoc<Function>; | ||||
| type FunctionLoc = AssocItemLoc<ast::Fn>; | ||||
| impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); | ||||
| impl_loc!(FunctionLoc, id: Function, container: ItemContainerId); | ||||
| 
 | ||||
| type StructLoc = ItemLoc<Struct>; | ||||
| type StructLoc = ItemLoc<ast::Struct>; | ||||
| impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); | ||||
| impl_loc!(StructLoc, id: Struct, container: ModuleId); | ||||
| 
 | ||||
| pub type UnionLoc = ItemLoc<Union>; | ||||
| pub type UnionLoc = ItemLoc<ast::Union>; | ||||
| impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); | ||||
| impl_loc!(UnionLoc, id: Union, container: ModuleId); | ||||
| 
 | ||||
| pub type EnumLoc = ItemLoc<Enum>; | ||||
| pub type EnumLoc = ItemLoc<ast::Enum>; | ||||
| impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); | ||||
| impl_loc!(EnumLoc, id: Enum, container: ModuleId); | ||||
| 
 | ||||
| type ConstLoc = AssocItemLoc<Const>; | ||||
| impl EnumId { | ||||
|     #[inline] | ||||
|     pub fn enum_variants(self, db: &dyn DefDatabase) -> &EnumVariants { | ||||
|         &self.enum_variants_with_diagnostics(db).0 | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub fn enum_variants_with_diagnostics( | ||||
|         self, | ||||
|         db: &dyn DefDatabase, | ||||
|     ) -> &(EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) { | ||||
|         EnumVariants::of(db, self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| type ConstLoc = AssocItemLoc<ast::Const>; | ||||
| impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); | ||||
| impl_loc!(ConstLoc, id: Const, container: ItemContainerId); | ||||
| 
 | ||||
| pub type StaticLoc = AssocItemLoc<Static>; | ||||
| pub type StaticLoc = AssocItemLoc<ast::Static>; | ||||
| impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); | ||||
| impl_loc!(StaticLoc, id: Static, container: ItemContainerId); | ||||
| 
 | ||||
| pub type TraitLoc = ItemLoc<Trait>; | ||||
| pub type TraitLoc = ItemLoc<ast::Trait>; | ||||
| impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); | ||||
| impl_loc!(TraitLoc, id: Trait, container: ModuleId); | ||||
| 
 | ||||
| pub type TraitAliasLoc = ItemLoc<TraitAlias>; | ||||
| pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>; | ||||
| impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); | ||||
| impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId); | ||||
| 
 | ||||
| type TypeAliasLoc = AssocItemLoc<TypeAlias>; | ||||
| type TypeAliasLoc = AssocItemLoc<ast::TypeAlias>; | ||||
| impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); | ||||
| impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId); | ||||
| 
 | ||||
| type ImplLoc = ItemLoc<Impl>; | ||||
| type ImplLoc = ItemLoc<ast::Impl>; | ||||
| impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); | ||||
| impl_loc!(ImplLoc, id: Impl, container: ModuleId); | ||||
| 
 | ||||
| type UseLoc = ItemLoc<Use>; | ||||
| impl ImplId { | ||||
|     #[inline] | ||||
|     pub fn impl_items(self, db: &dyn DefDatabase) -> &ImplItems { | ||||
|         &self.impl_items_with_diagnostics(db).0 | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, DefDiagnostics) { | ||||
|         ImplItems::of(db, self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| type UseLoc = ItemLoc<ast::Use>; | ||||
| impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); | ||||
| impl_loc!(UseLoc, id: Use, container: ModuleId); | ||||
| 
 | ||||
| type ExternCrateLoc = ItemLoc<ExternCrate>; | ||||
| type ExternCrateLoc = ItemLoc<ast::ExternCrate>; | ||||
| impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate); | ||||
| impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId); | ||||
| 
 | ||||
| type ExternBlockLoc = ItemLoc<ExternBlock>; | ||||
| type ExternBlockLoc = ItemLoc<ast::ExternBlock>; | ||||
| impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block); | ||||
| impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId); | ||||
| 
 | ||||
| #[salsa::tracked] | ||||
| impl ExternBlockId { | ||||
|     #[salsa::tracked] | ||||
|     pub fn abi(self, db: &dyn DefDatabase) -> Option<Symbol> { | ||||
|         signatures::extern_block_abi(db, self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct EnumVariantLoc { | ||||
|     pub id: ItemTreeId<Variant>, | ||||
|     pub id: AstId<ast::Variant>, | ||||
|     pub parent: EnumId, | ||||
|     pub index: u32, | ||||
| } | ||||
|  | @ -262,18 +331,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); | |||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct Macro2Loc { | ||||
|     pub container: ModuleId, | ||||
|     pub id: ItemTreeId<Macro2>, | ||||
|     pub id: AstId<ast::MacroDef>, | ||||
|     pub expander: MacroExpander, | ||||
|     pub allow_internal_unsafe: bool, | ||||
|     pub edition: Edition, | ||||
| } | ||||
| impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2); | ||||
| impl_loc!(Macro2Loc, id: Macro2, container: ModuleId); | ||||
| impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId); | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct MacroRulesLoc { | ||||
|     pub container: ModuleId, | ||||
|     pub id: ItemTreeId<MacroRules>, | ||||
|     pub id: AstId<ast::MacroRules>, | ||||
|     pub expander: MacroExpander, | ||||
|     pub flags: MacroRulesLocFlags, | ||||
|     pub edition: Edition, | ||||
|  | @ -301,13 +370,13 @@ pub enum MacroExpander { | |||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct ProcMacroLoc { | ||||
|     pub container: CrateRootModuleId, | ||||
|     pub id: ItemTreeId<Function>, | ||||
|     pub id: AstId<ast::Fn>, | ||||
|     pub expander: CustomProcMacroExpander, | ||||
|     pub kind: ProcMacroKind, | ||||
|     pub edition: Edition, | ||||
| } | ||||
| impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro); | ||||
| impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId); | ||||
| impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId); | ||||
| 
 | ||||
| #[derive(Debug, Hash, PartialEq, Eq, Clone)] | ||||
| pub struct BlockLoc { | ||||
|  | @ -315,7 +384,26 @@ pub struct BlockLoc { | |||
|     /// The containing module.
 | ||||
|     pub module: ModuleId, | ||||
| } | ||||
| impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); | ||||
| #[salsa_macros::tracked(debug)] | ||||
| #[derive(PartialOrd, Ord)] | ||||
| pub struct BlockIdLt<'db> { | ||||
|     pub loc: BlockLoc, | ||||
| } | ||||
| pub type BlockId = BlockIdLt<'static>; | ||||
| impl hir_expand::Intern for BlockLoc { | ||||
|     type Database = dyn DefDatabase; | ||||
|     type ID = BlockId; | ||||
|     fn intern(self, db: &Self::Database) -> Self::ID { | ||||
|         unsafe { std::mem::transmute::<BlockIdLt<'_>, BlockId>(BlockIdLt::new(db, self)) } | ||||
|     } | ||||
| } | ||||
| impl hir_expand::Lookup for BlockId { | ||||
|     type Database = dyn DefDatabase; | ||||
|     type Data = BlockLoc; | ||||
|     fn lookup(&self, db: &Self::Database) -> Self::Data { | ||||
|         self.loc(db) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// A `ModuleId` that is always a crate's root module.
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
|  | @ -338,6 +426,18 @@ impl CrateRootModuleId { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl HasModule for CrateRootModuleId { | ||||
|     #[inline] | ||||
|     fn module(&self, _db: &dyn DefDatabase) -> ModuleId { | ||||
|         ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn krate(&self, _db: &dyn DefDatabase) -> Crate { | ||||
|         self.krate | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialEq<ModuleId> for CrateRootModuleId { | ||||
|     fn eq(&self, other: &ModuleId) -> bool { | ||||
|         other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate | ||||
|  | @ -466,11 +566,19 @@ impl ModuleId { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl HasModule for ModuleId { | ||||
|     #[inline] | ||||
|     fn module(&self, _db: &dyn DefDatabase) -> ModuleId { | ||||
|         *self | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// An ID of a module, **local** to a `DefMap`.
 | ||||
| pub type LocalModuleId = Idx<nameres::ModuleData>; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct FieldId { | ||||
|     // FIXME: Store this as an erased `salsa::Id` to save space
 | ||||
|     pub parent: VariantId, | ||||
|     pub local_id: LocalFieldId, | ||||
| } | ||||
|  | @ -486,6 +594,7 @@ pub struct TupleFieldId { | |||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||||
| pub struct TypeOrConstParamId { | ||||
|     // FIXME: Store this as an erased `salsa::Id` to save space
 | ||||
|     pub parent: GenericDefId, | ||||
|     pub local_id: LocalTypeOrConstParamId, | ||||
| } | ||||
|  | @ -544,6 +653,7 @@ impl From<ConstParamId> for TypeOrConstParamId { | |||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||||
| pub struct LifetimeParamId { | ||||
|     // FIXME: Store this as an erased `salsa::Id` to save space
 | ||||
|     pub parent: GenericDefId, | ||||
|     pub local_id: LocalLifetimeParamId, | ||||
| } | ||||
|  | @ -642,15 +752,10 @@ impl GeneralConstId { | |||
|     pub fn name(self, db: &dyn DefDatabase) -> String { | ||||
|         match self { | ||||
|             GeneralConstId::StaticId(it) => { | ||||
|                 let loc = it.lookup(db); | ||||
|                 let tree = loc.item_tree_id().item_tree(db); | ||||
|                 let name = tree[loc.id.value].name.display(db, Edition::CURRENT); | ||||
|                 name.to_string() | ||||
|                 db.static_signature(it).name.display(db, Edition::CURRENT).to_string() | ||||
|             } | ||||
|             GeneralConstId::ConstId(const_id) => { | ||||
|                 let loc = const_id.lookup(db); | ||||
|                 let tree = loc.item_tree_id().item_tree(db); | ||||
|                 tree[loc.id.value].name.as_ref().map_or_else( | ||||
|                 db.const_signature(const_id).name.as_ref().map_or_else( | ||||
|                     || "_".to_owned(), | ||||
|                     |name| name.display(db, Edition::CURRENT).to_string(), | ||||
|                 ) | ||||
|  | @ -692,7 +797,7 @@ impl DefWithBodyId { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)] | ||||
| pub enum AssocItemId { | ||||
|     FunctionId(FunctionId), | ||||
|     ConstId(ConstId), | ||||
|  | @ -768,8 +873,8 @@ impl GenericDefId { | |||
|             GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), | ||||
|             GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), | ||||
|             GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), | ||||
|             GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), | ||||
|             GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None), | ||||
|             GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None), | ||||
|             GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -935,9 +1040,9 @@ impl VariantId { | |||
| 
 | ||||
|     pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { | ||||
|         match self { | ||||
|             VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(), | ||||
|             VariantId::StructId(it) => it.lookup(db).id.file_id(), | ||||
|             VariantId::UnionId(it) => it.lookup(db).id.file_id(), | ||||
|             VariantId::EnumVariantId(it) => it.lookup(db).id.file_id, | ||||
|             VariantId::StructId(it) => it.lookup(db).id.file_id, | ||||
|             VariantId::UnionId(it) => it.lookup(db).id.file_id, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -977,7 +1082,7 @@ pub trait HasModule { | |||
| 
 | ||||
| impl<N, ItemId> HasModule for ItemId | ||||
| where | ||||
|     N: ItemTreeNode, | ||||
|     N: AstIdNode, | ||||
|     ItemId: Lookup<Database = dyn DefDatabase, Data = ItemLoc<N>> + Copy, | ||||
| { | ||||
|     #[inline] | ||||
|  | @ -1003,7 +1108,7 @@ where | |||
| #[inline] | ||||
| fn module_for_assoc_item_loc<'db>( | ||||
|     db: &(dyn 'db + DefDatabase), | ||||
|     id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl ItemTreeNode>>, | ||||
|     id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl AstIdNode>>, | ||||
| ) -> ModuleId { | ||||
|     id.lookup(db).container.module(db) | ||||
| } | ||||
|  | @ -1245,7 +1350,7 @@ pub struct SyntheticSyntax; | |||
| // Crate authors can opt their type out of completions in some cases.
 | ||||
| // This is done with the `#[rust_analyzer::completions(...)]` attribute.
 | ||||
| //
 | ||||
| // All completeable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
 | ||||
| // All completable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
 | ||||
| // which causes the thing to get excluded from flyimport completion. It will still
 | ||||
| // be completed when in scope. This is analogous to the setting `rust-analyzer.completion.autoimport.exclude`
 | ||||
| // with `"type": "always"`.
 | ||||
|  |  | |||
|  | @ -35,9 +35,9 @@ macro_rules! f { | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| struct#0:1@58..64#14336# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#14336# | ||||
|     map#0:1@86..89#14336#:#0:1@89..90#14336# #0:1@89..90#14336#::#0:1@91..93#14336#std#0:1@93..96#14336#::#0:1@96..98#14336#collections#0:1@98..109#14336#::#0:1@109..111#14336#HashSet#0:1@111..118#14336#<#0:1@118..119#14336#(#0:1@119..120#14336#)#0:1@120..121#14336#>#0:1@121..122#14336#,#0:1@122..123#14336# | ||||
| }#0:1@132..133#14336# | ||||
| struct#0:MacroRules[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336# | ||||
|     map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336# | ||||
| }#0:MacroRules[8C8E, 0]@132..133#14336# | ||||
| "#]],
 | ||||
|     ); | ||||
| } | ||||
|  | @ -75,12 +75,12 @@ macro_rules! f { | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| fn#0:2@30..32#ROOT2024# main#0:2@33..37#ROOT2024#(#0:2@37..38#ROOT2024#)#0:2@38..39#ROOT2024# {#0:2@40..41#ROOT2024# | ||||
|     1#0:2@50..51#ROOT2024#;#0:2@51..52#ROOT2024# | ||||
|     1.0#0:2@61..64#ROOT2024#;#0:2@64..65#ROOT2024# | ||||
|     (#0:2@74..75#ROOT2024#(#0:2@75..76#ROOT2024#1#0:2@76..77#ROOT2024#,#0:2@77..78#ROOT2024# )#0:2@78..79#ROOT2024#,#0:2@79..80#ROOT2024# )#0:2@80..81#ROOT2024#.#0:2@81..82#ROOT2024#0#0:2@82..85#ROOT2024#.#0:2@82..85#ROOT2024#0#0:2@82..85#ROOT2024#;#0:2@85..86#ROOT2024# | ||||
|     let#0:2@95..98#ROOT2024# x#0:2@99..100#ROOT2024# =#0:2@101..102#ROOT2024# 1#0:2@103..104#ROOT2024#;#0:2@104..105#ROOT2024# | ||||
| }#0:2@110..111#ROOT2024# | ||||
| fn#0:MacroCall[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024# | ||||
|     1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024# | ||||
|     1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024# | ||||
|     (#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024# | ||||
|     let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024# | ||||
| }#0:MacroCall[D499, 0]@110..111#ROOT2024# | ||||
| 
 | ||||
| 
 | ||||
| "#]],
 | ||||
|  | @ -171,7 +171,7 @@ fn main(foo: ()) { | |||
|     } | ||||
| 
 | ||||
|     fn main(foo: ()) { | ||||
|         /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#ROOT2024#; | ||||
|         /* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -197,7 +197,7 @@ macro_rules! mk_struct { | |||
| #[macro_use] | ||||
| mod foo; | ||||
| 
 | ||||
| struct#1:1@59..65#14336# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#14336#u32#0:2@41..44#ROOT2024#)#1:1@74..75#14336#;#1:1@75..76#14336# | ||||
| struct#1:MacroRules[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336# | ||||
| "#]],
 | ||||
|     ); | ||||
| } | ||||
|  | @ -2029,3 +2029,25 @@ fn f() { | |||
|     "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn lifetime_repeat() { | ||||
|     check( | ||||
|         r#" | ||||
| macro_rules! m { | ||||
|     ($($x:expr)'a*) => (stringify!($($x)'b*)); | ||||
| } | ||||
| fn f() { | ||||
|     let _ = m!(0 'a 1 'a 2); | ||||
| } | ||||
|     "#,
 | ||||
|         expect![[r#" | ||||
| macro_rules! m { | ||||
|     ($($x:expr)'a*) => (stringify!($($x)'b*)); | ||||
| } | ||||
| fn f() { | ||||
|     let _ = stringify!(0 'b 1 'b 2); | ||||
| } | ||||
|     "#]],
 | ||||
|     ); | ||||
| } | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ macro_rules! m { | |||
|     ($(x),*) => (); | ||||
|     ($(x)_*) => (); | ||||
|     ($(x)i*) => (); | ||||
|     ($(x)'a*) => (); | ||||
|     ($(x)'_*) => (); | ||||
|     ($($i:ident)*) => ($_); | ||||
|     ($($true:ident)*) => ($true); | ||||
|     ($($false:ident)*) => ($false); | ||||
|  | @ -28,6 +30,8 @@ macro_rules! m { | |||
|     ($(x),*) => (); | ||||
|     ($(x)_*) => (); | ||||
|     ($(x)i*) => (); | ||||
|     ($(x)'a*) => (); | ||||
|     ($(x)'_*) => (); | ||||
|     ($($i:ident)*) => ($_); | ||||
|     ($($true:ident)*) => ($true); | ||||
|     ($($false:ident)*) => ($false); | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ mod builtin_fn_macro; | |||
| mod mbe; | ||||
| mod proc_macros; | ||||
| 
 | ||||
| use std::{iter, ops::Range, sync}; | ||||
| use std::{any::TypeId, iter, ops::Range, sync}; | ||||
| 
 | ||||
| use base_db::RootQueryDb; | ||||
| use expect_test::Expect; | ||||
|  | @ -302,14 +302,15 @@ fn pretty_print_macro_expansion( | |||
|             (_, T!['{']) => " ", | ||||
|             (T![;] | T!['{'] | T!['}'], _) => "\n", | ||||
|             (_, T!['}']) => "\n", | ||||
|             (IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ", | ||||
|             _ if prev_kind.is_keyword(Edition::CURRENT) | ||||
|                 && curr_kind.is_keyword(Edition::CURRENT) => | ||||
|             _ if (prev_kind.is_any_identifier() | ||||
|                 || prev_kind == LIFETIME_IDENT | ||||
|                 || prev_kind.is_literal()) | ||||
|                 && (curr_kind.is_any_identifier() | ||||
|                     || curr_kind == LIFETIME_IDENT | ||||
|                     || curr_kind.is_literal()) => | ||||
|             { | ||||
|                 " " | ||||
|             } | ||||
|             (IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ", | ||||
|             (_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ", | ||||
|             (T![>], IDENT) => " ", | ||||
|             (T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ", | ||||
|             (T![->], _) | (_, T![->]) => " ", | ||||
|  | @ -380,4 +381,8 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { | |||
|             panic!("got invalid macro input: {:?}", parse.errors()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { | ||||
|         other.type_id() == TypeId::of::<Self>() | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -181,9 +181,9 @@ fn foo(&self) { | |||
|     self.0. 1; | ||||
| } | ||||
| 
 | ||||
| fn#0:1@45..47#ROOT2024# foo#0:1@48..51#ROOT2024#(#0:1@51..52#ROOT2024#�:1@52..53#ROOT2024#self#0:1@53..57#ROOT2024# )#0:1@57..58#ROOT2024# {#0:1@59..60#ROOT2024# | ||||
|     self#0:1@65..69#ROOT2024# .#0:1@69..70#ROOT2024#0#0:1@70..71#ROOT2024#.#0:1@71..72#ROOT2024#1#0:1@73..74#ROOT2024#;#0:1@74..75#ROOT2024# | ||||
| }#0:1@76..77#ROOT2024#"#]],
 | ||||
| fn#0:Fn[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#�:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024# | ||||
|     self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024# | ||||
| }#0:Fn[4D85, 0]@76..77#ROOT2024#"#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -62,8 +62,8 @@ use std::ops::Deref; | |||
| 
 | ||||
| use base_db::Crate; | ||||
| use hir_expand::{ | ||||
|     EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath, | ||||
|     name::Name, proc_macro::ProcMacroKind, | ||||
|     EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name, | ||||
|     proc_macro::ProcMacroKind, | ||||
| }; | ||||
| use intern::Symbol; | ||||
| use itertools::Itertools; | ||||
|  | @ -80,7 +80,7 @@ use crate::{ | |||
|     LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, | ||||
|     db::DefDatabase, | ||||
|     item_scope::{BuiltinShadowMode, ItemScope}, | ||||
|     item_tree::{ItemTreeId, Mod, TreeId}, | ||||
|     item_tree::TreeId, | ||||
|     nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, | ||||
|     per_ns::PerNs, | ||||
|     visibility::{Visibility, VisibilityExplicitness}, | ||||
|  | @ -171,12 +171,10 @@ pub struct DefMap { | |||
|     /// ExternCrateId being None implies it being imported from the general prelude import.
 | ||||
|     macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>, | ||||
| 
 | ||||
|     // FIXME: AstId's are fairly unstable
 | ||||
|     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
 | ||||
|     /// attributes.
 | ||||
|     // FIXME: Figure out a better way for the IDE layer to resolve these?
 | ||||
|     derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>, | ||||
|     // FIXME: AstId's are fairly unstable
 | ||||
|     /// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
 | ||||
|     pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>, | ||||
| 
 | ||||
|  | @ -191,7 +189,7 @@ pub struct DefMap { | |||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||||
| struct DefMapCrateData { | ||||
|     /// Side table for resolving derive helpers.
 | ||||
|     exported_derives: FxHashMap<MacroDefId, Box<[Name]>>, | ||||
|     exported_derives: FxHashMap<MacroId, Box<[Name]>>, | ||||
|     fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>, | ||||
| 
 | ||||
|     /// Custom attributes registered with `#![register_attr]`.
 | ||||
|  | @ -291,11 +289,11 @@ pub enum ModuleOrigin { | |||
|     File { | ||||
|         is_mod_rs: bool, | ||||
|         declaration: FileAstId<ast::Module>, | ||||
|         declaration_tree_id: ItemTreeId<Mod>, | ||||
|         declaration_tree_id: TreeId, | ||||
|         definition: EditionedFileId, | ||||
|     }, | ||||
|     Inline { | ||||
|         definition_tree_id: ItemTreeId<Mod>, | ||||
|         definition_tree_id: TreeId, | ||||
|         definition: FileAstId<ast::Module>, | ||||
|     }, | ||||
|     /// Pseudo-module introduced by a block scope (contains only inner items).
 | ||||
|  |  | |||
|  | @ -1,14 +1,28 @@ | |||
| //! Expansion of associated items
 | ||||
| 
 | ||||
| use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name}; | ||||
| use syntax::ast; | ||||
| use std::mem; | ||||
| 
 | ||||
| use cfg::CfgOptions; | ||||
| use hir_expand::{ | ||||
|     AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, | ||||
|     mod_path::ModPath, | ||||
|     name::{AsName, Name}, | ||||
|     span_map::SpanMap, | ||||
| }; | ||||
| use intern::Interned; | ||||
| use span::AstIdMap; | ||||
| use syntax::{ | ||||
|     AstNode, | ||||
|     ast::{self, HasModuleItem, HasName}, | ||||
| }; | ||||
| use thin_vec::ThinVec; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, | ||||
|     ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc, | ||||
|     attr::Attrs, | ||||
|     db::DefDatabase, | ||||
|     item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, | ||||
|     macro_call_as_call_id, | ||||
|     nameres::{ | ||||
|         DefMap, LocalDefMap, MacroSubNs, | ||||
|  | @ -20,9 +34,8 @@ use crate::{ | |||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct TraitItems { | ||||
|     pub items: Box<[(Name, AssocItemId)]>, | ||||
|     // box it as the vec is usually empty anyways
 | ||||
|     // FIXME: AstIds are rather unstable...
 | ||||
|     pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, | ||||
|     // `ThinVec` as the vec is usually empty anyways
 | ||||
|     pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, | ||||
| } | ||||
| 
 | ||||
| impl TraitItems { | ||||
|  | @ -35,12 +48,12 @@ impl TraitItems { | |||
|         db: &dyn DefDatabase, | ||||
|         tr: TraitId, | ||||
|     ) -> (Arc<TraitItems>, DefDiagnostics) { | ||||
|         let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); | ||||
|         let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db); | ||||
| 
 | ||||
|         let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr)); | ||||
|         let item_tree = tree_id.item_tree(db); | ||||
|         let (items, macro_calls, diagnostics) = | ||||
|             collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items); | ||||
|         let collector = | ||||
|             AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id); | ||||
|         let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); | ||||
|         let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); | ||||
| 
 | ||||
|         (Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics)) | ||||
|     } | ||||
|  | @ -76,41 +89,36 @@ impl TraitItems { | |||
|     } | ||||
| 
 | ||||
|     pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ { | ||||
|         self.macro_calls.iter().flat_map(|it| it.iter()).copied() | ||||
|         self.macro_calls.iter().copied() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub struct ImplItems { | ||||
|     pub items: Box<[(Name, AssocItemId)]>, | ||||
|     // box it as the vec is usually empty anyways
 | ||||
|     // FIXME: AstIds are rather unstable...
 | ||||
|     pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, | ||||
|     // `ThinVec` as the vec is usually empty anyways
 | ||||
|     pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, | ||||
| } | ||||
| 
 | ||||
| #[salsa::tracked] | ||||
| impl ImplItems { | ||||
|     #[salsa::tracked(returns(ref))] | ||||
|     pub fn of(db: &dyn DefDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) { | ||||
|         let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered(); | ||||
|         let ItemLoc { container: module_id, id: ast_id } = id.lookup(db); | ||||
| 
 | ||||
|         let collector = | ||||
|             AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id), ast_id.file_id); | ||||
|         let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); | ||||
|         let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); | ||||
| 
 | ||||
|         (ImplItems { items, macro_calls }, DefDiagnostics::new(diagnostics)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ImplItems { | ||||
|     #[inline] | ||||
|     pub(crate) fn impl_items_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplItems> { | ||||
|         db.impl_items_with_diagnostics(id).0 | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn impl_items_with_diagnostics_query( | ||||
|         db: &dyn DefDatabase, | ||||
|         id: ImplId, | ||||
|     ) -> (Arc<ImplItems>, DefDiagnostics) { | ||||
|         let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered(); | ||||
|         let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); | ||||
| 
 | ||||
|         let collector = AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id)); | ||||
|         let item_tree = tree_id.item_tree(db); | ||||
|         let (items, macro_calls, diagnostics) = | ||||
|             collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items); | ||||
| 
 | ||||
|         (Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ { | ||||
|         self.macro_calls.iter().flat_map(|it| it.iter()).copied() | ||||
|         self.macro_calls.iter().copied() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -119,67 +127,73 @@ struct AssocItemCollector<'a> { | |||
|     module_id: ModuleId, | ||||
|     def_map: &'a DefMap, | ||||
|     local_def_map: &'a LocalDefMap, | ||||
|     ast_id_map: Arc<AstIdMap>, | ||||
|     span_map: SpanMap, | ||||
|     cfg_options: &'a CfgOptions, | ||||
|     file_id: HirFileId, | ||||
|     diagnostics: Vec<DefDiagnostic>, | ||||
|     container: ItemContainerId, | ||||
| 
 | ||||
|     depth: usize, | ||||
|     items: Vec<(Name, AssocItemId)>, | ||||
|     macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>, | ||||
|     macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> AssocItemCollector<'a> { | ||||
|     fn new(db: &'a dyn DefDatabase, module_id: ModuleId, container: ItemContainerId) -> Self { | ||||
|     fn new( | ||||
|         db: &'a dyn DefDatabase, | ||||
|         module_id: ModuleId, | ||||
|         container: ItemContainerId, | ||||
|         file_id: HirFileId, | ||||
|     ) -> Self { | ||||
|         let (def_map, local_def_map) = module_id.local_def_map(db); | ||||
|         Self { | ||||
|             db, | ||||
|             module_id, | ||||
|             def_map, | ||||
|             local_def_map, | ||||
|             ast_id_map: db.ast_id_map(file_id), | ||||
|             span_map: db.span_map(file_id), | ||||
|             cfg_options: module_id.krate.cfg_options(db), | ||||
|             file_id, | ||||
|             container, | ||||
|             items: Vec::new(), | ||||
| 
 | ||||
|             depth: 0, | ||||
|             macro_calls: Vec::new(), | ||||
|             macro_calls: ThinVec::new(), | ||||
|             diagnostics: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn collect( | ||||
|         mut self, | ||||
|         item_tree: &ItemTree, | ||||
|         tree_id: TreeId, | ||||
|         assoc_items: &[AssocItem], | ||||
|     ) -> ( | ||||
|         Box<[(Name, AssocItemId)]>, | ||||
|         Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, | ||||
|         Vec<DefDiagnostic>, | ||||
|     ) { | ||||
|         self.items.reserve(assoc_items.len()); | ||||
|         for &item in assoc_items { | ||||
|             self.collect_item(item_tree, tree_id, item); | ||||
|         item_list: Option<ast::AssocItemList>, | ||||
|     ) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId<ast::Item>, MacroCallId)>, Vec<DefDiagnostic>) | ||||
|     { | ||||
|         if let Some(item_list) = item_list { | ||||
|             for item in item_list.assoc_items() { | ||||
|                 self.collect_item(item); | ||||
|             } | ||||
|         ( | ||||
|             self.items.into_boxed_slice(), | ||||
|             if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, | ||||
|             self.diagnostics, | ||||
|         ) | ||||
|         } | ||||
|         self.macro_calls.shrink_to_fit(); | ||||
|         (self.items.into_boxed_slice(), self.macro_calls, self.diagnostics) | ||||
|     } | ||||
| 
 | ||||
|     fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) { | ||||
|         let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); | ||||
|         if !attrs.is_cfg_enabled(self.module_id.krate.cfg_options(self.db)) { | ||||
|     fn collect_item(&mut self, item: ast::AssocItem) { | ||||
|         let ast_id = self.ast_id_map.ast_id(&item); | ||||
|         let attrs = Attrs::new(self.db, &item, self.span_map.as_ref(), self.cfg_options); | ||||
|         if let Err(cfg) = attrs.is_cfg_enabled(self.cfg_options) { | ||||
|             self.diagnostics.push(DefDiagnostic::unconfigured_code( | ||||
|                 self.module_id.local_id, | ||||
|                 tree_id, | ||||
|                 ModItem::from(item).into(), | ||||
|                 attrs.cfg().unwrap(), | ||||
|                 self.module_id.krate.cfg_options(self.db).clone(), | ||||
|                 InFile::new(self.file_id, ast_id.erase()), | ||||
|                 cfg, | ||||
|                 self.cfg_options.clone(), | ||||
|             )); | ||||
|             return; | ||||
|         } | ||||
|         let ast_id = InFile::new(self.file_id, ast_id.upcast()); | ||||
| 
 | ||||
|         'attrs: for attr in &*attrs { | ||||
|             let ast_id = AstId::new(tree_id.file_id(), item.ast_id(item_tree).upcast()); | ||||
|             let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id }; | ||||
| 
 | ||||
|             match self.def_map.resolve_attr_macro( | ||||
|  | @ -223,34 +237,51 @@ impl<'a> AssocItemCollector<'a> { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         self.record_item(item_tree, tree_id, item); | ||||
|         self.record_item(item); | ||||
|     } | ||||
| 
 | ||||
|     fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) { | ||||
|     fn record_item(&mut self, item: ast::AssocItem) { | ||||
|         match item { | ||||
|             AssocItem::Function(id) => { | ||||
|                 let item = &item_tree[id]; | ||||
|             ast::AssocItem::Fn(function) => { | ||||
|                 let Some(name) = function.name() else { return }; | ||||
|                 let ast_id = self.ast_id_map.ast_id(&function); | ||||
|                 let def = FunctionLoc { | ||||
|                     container: self.container, | ||||
|                     id: InFile::new(self.file_id, ast_id), | ||||
|                 } | ||||
|                 .intern(self.db); | ||||
|                 self.items.push((name.as_name(), def.into())); | ||||
|             } | ||||
|             ast::AssocItem::TypeAlias(type_alias) => { | ||||
|                 let Some(name) = type_alias.name() else { return }; | ||||
|                 let ast_id = self.ast_id_map.ast_id(&type_alias); | ||||
|                 let def = TypeAliasLoc { | ||||
|                     container: self.container, | ||||
|                     id: InFile::new(self.file_id, ast_id), | ||||
|                 } | ||||
|                 .intern(self.db); | ||||
|                 self.items.push((name.as_name(), def.into())); | ||||
|             } | ||||
|             ast::AssocItem::Const(konst) => { | ||||
|                 let Some(name) = konst.name() else { return }; | ||||
|                 let ast_id = self.ast_id_map.ast_id(&konst); | ||||
|                 let def = | ||||
|                     FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } | ||||
|                     ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) } | ||||
|                         .intern(self.db); | ||||
|                 self.items.push((item.name.clone(), def.into())); | ||||
|                 self.items.push((name.as_name(), def.into())); | ||||
|             } | ||||
|             AssocItem::TypeAlias(id) => { | ||||
|                 let item = &item_tree[id]; | ||||
|                 let def = | ||||
|                     TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } | ||||
|                         .intern(self.db); | ||||
|                 self.items.push((item.name.clone(), def.into())); | ||||
|             } | ||||
|             AssocItem::Const(id) => { | ||||
|                 let item = &item_tree[id]; | ||||
|                 let Some(name) = item.name.clone() else { return }; | ||||
|                 let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } | ||||
|                     .intern(self.db); | ||||
|                 self.items.push((name, def.into())); | ||||
|             } | ||||
|             AssocItem::MacroCall(call) => { | ||||
|                 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; | ||||
|             ast::AssocItem::MacroCall(call) => { | ||||
|                 let ast_id = self.ast_id_map.ast_id(&call); | ||||
|                 let ast_id = InFile::new(self.file_id, ast_id); | ||||
|                 let Some(path) = call.path() else { return }; | ||||
|                 let range = path.syntax().text_range(); | ||||
|                 let Some(path) = ModPath::from_src(self.db, path, &mut |range| { | ||||
|                     self.span_map.span_for_range(range).ctx | ||||
|                 }) else { | ||||
|                     return; | ||||
|                 }; | ||||
|                 let path = Interned::new(path); | ||||
|                 let ctxt = self.span_map.span_for_range(range).ctx; | ||||
| 
 | ||||
|                 let resolver = |path: &_| { | ||||
|                     self.def_map | ||||
|  | @ -268,10 +299,10 @@ impl<'a> AssocItemCollector<'a> { | |||
|                 }; | ||||
|                 match macro_call_as_call_id( | ||||
|                     self.db, | ||||
|                     InFile::new(tree_id.file_id(), ast_id), | ||||
|                     path, | ||||
|                     ast_id, | ||||
|                     &path, | ||||
|                     ctxt, | ||||
|                     expand_to, | ||||
|                     ExpandTo::Items, | ||||
|                     self.module_id.krate(), | ||||
|                     resolver, | ||||
|                     &mut |ptr, call_id| { | ||||
|  | @ -281,8 +312,7 @@ impl<'a> AssocItemCollector<'a> { | |||
|                     // FIXME: Expansion error?
 | ||||
|                     Ok(call_id) => match call_id.value { | ||||
|                         Some(call_id) => { | ||||
|                             self.macro_calls | ||||
|                                 .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); | ||||
|                             self.macro_calls.push((ast_id.upcast(), call_id)); | ||||
|                             self.collect_macro_items(call_id); | ||||
|                         } | ||||
|                         None => (), | ||||
|  | @ -291,11 +321,11 @@ impl<'a> AssocItemCollector<'a> { | |||
|                         self.diagnostics.push(DefDiagnostic::unresolved_macro_call( | ||||
|                             self.module_id.local_id, | ||||
|                             MacroCallKind::FnLike { | ||||
|                                 ast_id: InFile::new(tree_id.file_id(), ast_id), | ||||
|                                 expand_to, | ||||
|                                 ast_id, | ||||
|                                 expand_to: ExpandTo::Items, | ||||
|                                 eager: None, | ||||
|                             }, | ||||
|                             Clone::clone(path), | ||||
|                             (*path).clone(), | ||||
|                         )); | ||||
|                     } | ||||
|                 } | ||||
|  | @ -308,13 +338,29 @@ impl<'a> AssocItemCollector<'a> { | |||
|             tracing::warn!("macro expansion is too deep"); | ||||
|             return; | ||||
|         } | ||||
|         let tree_id = TreeId::new(macro_call_id.into(), None); | ||||
|         let item_tree = self.db.file_item_tree(macro_call_id.into()); | ||||
| 
 | ||||
|         let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value; | ||||
|         let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into()); | ||||
|         let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id)); | ||||
|         let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map)); | ||||
|         self.depth += 1; | ||||
|         for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) { | ||||
|             self.collect_item(&item_tree, tree_id, item); | ||||
| 
 | ||||
|         let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`"); | ||||
|         for item in items.items() { | ||||
|             let item = match item { | ||||
|                 ast::Item::Fn(it) => ast::AssocItem::from(it), | ||||
|                 ast::Item::Const(it) => it.into(), | ||||
|                 ast::Item::TypeAlias(it) => it.into(), | ||||
|                 ast::Item::MacroCall(it) => it.into(), | ||||
|                 // FIXME: Should error on disallowed item kinds.
 | ||||
|                 _ => continue, | ||||
|             }; | ||||
|             self.collect_item(item); | ||||
|         } | ||||
| 
 | ||||
|         self.depth -= 1; | ||||
|         self.file_id = old_file_id; | ||||
|         self.ast_id_map = old_ast_id_map; | ||||
|         self.span_map = old_span_map; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; | |||
| use cfg::{CfgAtom, CfgExpr, CfgOptions}; | ||||
| use either::Either; | ||||
| use hir_expand::{ | ||||
|     EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, | ||||
|     MacroDefKind, | ||||
|     EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, | ||||
|     MacroDefId, MacroDefKind, | ||||
|     attrs::{Attr, AttrId}, | ||||
|     builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro}, | ||||
|     mod_path::{ModPath, PathKind}, | ||||
|  | @ -35,9 +35,8 @@ use crate::{ | |||
|     db::DefDatabase, | ||||
|     item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, | ||||
|     item_tree::{ | ||||
|         self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, | ||||
|         ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, | ||||
|         UseTreeKind, | ||||
|         self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall, | ||||
|         MacroRules, Mod, ModItemId, ModKind, TreeId, | ||||
|     }, | ||||
|     macro_call_as_call_id, | ||||
|     nameres::{ | ||||
|  | @ -154,14 +153,14 @@ struct Import { | |||
| impl Import { | ||||
|     fn from_use( | ||||
|         tree: &ItemTree, | ||||
|         item_tree_id: ItemTreeId<item_tree::Use>, | ||||
|         item: FileAstId<ast::Use>, | ||||
|         id: UseId, | ||||
|         is_prelude: bool, | ||||
|         mut cb: impl FnMut(Self), | ||||
|     ) { | ||||
|         let it = &tree[item_tree_id.value]; | ||||
|         let it = &tree[item]; | ||||
|         let visibility = &tree[it.visibility]; | ||||
|         it.use_tree.expand(|idx, path, kind, alias| { | ||||
|         it.expand(|idx, path, kind, alias| { | ||||
|             cb(Self { | ||||
|                 path, | ||||
|                 alias, | ||||
|  | @ -181,15 +180,15 @@ struct ImportDirective { | |||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||||
| struct MacroDirective { | ||||
| struct MacroDirective<'db> { | ||||
|     module_id: LocalModuleId, | ||||
|     depth: usize, | ||||
|     kind: MacroDirectiveKind, | ||||
|     kind: MacroDirectiveKind<'db>, | ||||
|     container: ItemContainerId, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||||
| enum MacroDirectiveKind { | ||||
| enum MacroDirectiveKind<'db> { | ||||
|     FnLike { | ||||
|         ast_id: AstIdWithPath<ast::MacroCall>, | ||||
|         expand_to: ExpandTo, | ||||
|  | @ -206,30 +205,31 @@ enum MacroDirectiveKind { | |||
|     Attr { | ||||
|         ast_id: AstIdWithPath<ast::Item>, | ||||
|         attr: Attr, | ||||
|         mod_item: ModItem, | ||||
|         mod_item: ModItemId, | ||||
|         /* is this needed? */ tree: TreeId, | ||||
|         item_tree: &'db ItemTree, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| /// Walks the tree of module recursively
 | ||||
| struct DefCollector<'a> { | ||||
|     db: &'a dyn DefDatabase, | ||||
| struct DefCollector<'db> { | ||||
|     db: &'db dyn DefDatabase, | ||||
|     def_map: DefMap, | ||||
|     local_def_map: LocalDefMap, | ||||
|     /// Set only in case of blocks.
 | ||||
|     crate_local_def_map: Option<&'a LocalDefMap>, | ||||
|     crate_local_def_map: Option<&'db LocalDefMap>, | ||||
|     // The dependencies of the current crate, including optional deps like `test`.
 | ||||
|     deps: FxHashMap<Name, BuiltDependency>, | ||||
|     glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>, | ||||
|     unresolved_imports: Vec<ImportDirective>, | ||||
|     indeterminate_imports: Vec<(ImportDirective, PerNs)>, | ||||
|     unresolved_macros: Vec<MacroDirective>, | ||||
|     unresolved_macros: Vec<MacroDirective<'db>>, | ||||
|     // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
 | ||||
|     // resolve. When we emit diagnostics for unresolved imports, we only do so if the import
 | ||||
|     // doesn't start with an unresolved crate's name.
 | ||||
|     unresolved_extern_crates: FxHashSet<Name>, | ||||
|     mod_dirs: FxHashMap<LocalModuleId, ModDir>, | ||||
|     cfg_options: &'a CfgOptions, | ||||
|     cfg_options: &'db CfgOptions, | ||||
|     /// List of procedural macros defined by this crate. This is read from the dynamic library
 | ||||
|     /// built by the build system, and is the list of proc-macros we can actually expand. It is
 | ||||
|     /// empty when proc-macro support is disabled (in which case we still do name resolution for
 | ||||
|  | @ -244,10 +244,10 @@ struct DefCollector<'a> { | |||
|     /// This also stores the attributes to skip when we resolve derive helpers and non-macro
 | ||||
|     /// non-builtin attributes in general.
 | ||||
|     // FIXME: There has to be a better way to do this
 | ||||
|     skip_attrs: FxHashMap<InFile<ModItem>, AttrId>, | ||||
|     skip_attrs: FxHashMap<InFile<FileAstId<ast::Item>>, AttrId>, | ||||
| } | ||||
| 
 | ||||
| impl DefCollector<'_> { | ||||
| impl<'db> DefCollector<'db> { | ||||
|     fn seed_with_top_level(&mut self) { | ||||
|         let _p = tracing::info_span!("seed_with_top_level").entered(); | ||||
| 
 | ||||
|  | @ -355,7 +355,7 @@ impl DefCollector<'_> { | |||
|             macro_depth: 0, | ||||
|             module_id: DefMap::ROOT, | ||||
|             tree_id: TreeId::new(file_id.into(), None), | ||||
|             item_tree: &item_tree, | ||||
|             item_tree, | ||||
|             mod_dir: ModDir::root(), | ||||
|         } | ||||
|         .collect_in_top_module(item_tree.top_level_items()); | ||||
|  | @ -376,7 +376,7 @@ impl DefCollector<'_> { | |||
|                 macro_depth: 0, | ||||
|                 module_id: DefMap::ROOT, | ||||
|                 tree_id, | ||||
|                 item_tree: &item_tree, | ||||
|                 item_tree, | ||||
|                 mod_dir: ModDir::root(), | ||||
|             } | ||||
|             .collect_in_top_module(item_tree.top_level_items()); | ||||
|  | @ -437,9 +437,8 @@ impl DefCollector<'_> { | |||
|             // Additionally, while the proc macro entry points must be `pub`, they are not publicly
 | ||||
|             // exported in type/value namespace. This function reduces the visibility of all items
 | ||||
|             // in the crate root that aren't proc macros.
 | ||||
|             let module_id = self.def_map.module_id(DefMap::ROOT); | ||||
|             let root = &mut self.def_map.modules[DefMap::ROOT]; | ||||
|             root.scope.censor_non_proc_macros(module_id); | ||||
|             root.scope.censor_non_proc_macros(self.def_map.krate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -459,7 +458,7 @@ impl DefCollector<'_> { | |||
|             self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive | ||||
|                 .kind | ||||
|             { | ||||
|                 MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => { | ||||
|                 MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree, item_tree } => { | ||||
|                     self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( | ||||
|                         directive.module_id, | ||||
|                         MacroCallKind::Attr { | ||||
|  | @ -470,16 +469,22 @@ impl DefCollector<'_> { | |||
|                         attr.path().clone(), | ||||
|                     )); | ||||
| 
 | ||||
|                     self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id); | ||||
|                     self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id); | ||||
| 
 | ||||
|                     Some((idx, directive, *mod_item, *tree)) | ||||
|                     Some((idx, directive, *mod_item, *tree, *item_tree)) | ||||
|                 } | ||||
|                 _ => None, | ||||
|             }); | ||||
| 
 | ||||
|         match unresolved_attr { | ||||
|             Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => { | ||||
|                 let item_tree = &tree_id.item_tree(self.db); | ||||
|             Some(( | ||||
|                 pos, | ||||
|                 &MacroDirective { module_id, depth, container, .. }, | ||||
|                 mod_item, | ||||
|                 tree_id, | ||||
|                 item_tree, | ||||
|             )) => { | ||||
|                 // FIXME: Remove this clone
 | ||||
|                 let mod_dir = self.mod_dirs[&module_id].clone(); | ||||
|                 ModCollector { | ||||
|                     def_collector: self, | ||||
|  | @ -576,13 +581,7 @@ impl DefCollector<'_> { | |||
|     /// use a dummy expander that always errors. This comes with the drawback of macros potentially
 | ||||
|     /// going out of sync with what the build system sees (since we resolve using VFS state, but
 | ||||
|     /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
 | ||||
|     fn export_proc_macro( | ||||
|         &mut self, | ||||
|         def: ProcMacroDef, | ||||
|         id: ItemTreeId<item_tree::Function>, | ||||
|         ast_id: AstId<ast::Fn>, | ||||
|         fn_id: FunctionId, | ||||
|     ) { | ||||
|     fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>, fn_id: FunctionId) { | ||||
|         let kind = def.kind.to_basedb_kind(); | ||||
|         let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) { | ||||
|             Some(_) | ||||
|  | @ -598,7 +597,7 @@ impl DefCollector<'_> { | |||
| 
 | ||||
|         let proc_macro_id = ProcMacroLoc { | ||||
|             container: self.def_map.crate_root(), | ||||
|             id, | ||||
|             id: ast_id, | ||||
|             expander, | ||||
|             kind, | ||||
|             edition: self.def_map.data.edition, | ||||
|  | @ -609,7 +608,7 @@ impl DefCollector<'_> { | |||
|         self.define_proc_macro(def.name.clone(), proc_macro_id); | ||||
|         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); | ||||
|         if let ProcMacroKind::Derive { helpers } = def.kind { | ||||
|             crate_data.exported_derives.insert(self.db.macro_def(proc_macro_id.into()), helpers); | ||||
|             crate_data.exported_derives.insert(proc_macro_id.into(), helpers); | ||||
|         } | ||||
|         crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id); | ||||
|     } | ||||
|  | @ -887,9 +886,31 @@ impl DefCollector<'_> { | |||
|                 let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree }); | ||||
|                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | ||||
| 
 | ||||
|                 // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
 | ||||
|                 // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
 | ||||
|                 // or `pub use ::crate_name`.
 | ||||
|                 //
 | ||||
|                 // This has been historically allowed, but may be not allowed in future
 | ||||
|                 // https://github.com/rust-lang/rust/issues/127909
 | ||||
|                 if let Some(def) = def.types.as_mut() { | ||||
|                     let is_extern_crate_reimport_without_prefix = || { | ||||
|                         let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { | ||||
|                             return false; | ||||
|                         }; | ||||
|                         if kind == ImportKind::Glob { | ||||
|                             return false; | ||||
|                         } | ||||
|                         matches!(import.path.kind, PathKind::Plain | PathKind::SELF) | ||||
|                             && import.path.segments().len() < 2 | ||||
|                     }; | ||||
|                     if is_extern_crate_reimport_without_prefix() { | ||||
|                         def.vis = vis; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 self.update(module_id, &[(name.cloned(), def)], vis, Some(imp)); | ||||
|             } | ||||
|             ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => { | ||||
|             ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => { | ||||
|                 tracing::debug!("glob import: {:?}", import); | ||||
|                 let glob = GlobId { use_: id, idx: use_tree }; | ||||
|                 match def.take_types() { | ||||
|  | @ -973,12 +994,11 @@ impl DefCollector<'_> { | |||
|                     Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | ||||
|                         cov_mark::hit!(glob_enum); | ||||
|                         // glob import from enum => just import all the variants
 | ||||
|                         let resolutions = self | ||||
|                             .db | ||||
|                             .enum_variants(e) | ||||
|                         let resolutions = e | ||||
|                             .enum_variants(self.db) | ||||
|                             .variants | ||||
|                             .iter() | ||||
|                             .map(|&(variant, ref name)| { | ||||
|                             .map(|&(variant, ref name, _)| { | ||||
|                                 let res = PerNs::both(variant.into(), variant.into(), vis, None); | ||||
|                                 (Some(name.clone()), res) | ||||
|                             }) | ||||
|  | @ -1150,34 +1170,9 @@ impl DefCollector<'_> { | |||
|         vis: Visibility, | ||||
|         def_import_type: Option<ImportOrExternCrate>, | ||||
|     ) -> bool { | ||||
|         // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
 | ||||
|         // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
 | ||||
|         // or `pub use ::crate_name`.
 | ||||
|         //
 | ||||
|         // This has been historically allowed, but may be not allowed in future
 | ||||
|         // https://github.com/rust-lang/rust/issues/127909
 | ||||
|         if let Some(def) = defs.types.as_mut() { | ||||
|             let is_extern_crate_reimport_without_prefix = || { | ||||
|                 let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { | ||||
|                     return false; | ||||
|                 }; | ||||
|                 let Some(ImportOrExternCrate::Import(id)) = def_import_type else { | ||||
|                     return false; | ||||
|                 }; | ||||
|                 let use_id = id.use_.lookup(self.db).id; | ||||
|                 let item_tree = use_id.item_tree(self.db); | ||||
|                 let use_kind = item_tree[use_id.value].use_tree.kind(); | ||||
|                 let UseTreeKind::Single { path, .. } = use_kind else { | ||||
|                     return false; | ||||
|                 }; | ||||
|                 path.segments().len() < 2 | ||||
|             }; | ||||
|             if is_extern_crate_reimport_without_prefix() { | ||||
|                 def.vis = vis; | ||||
|             } else { | ||||
|             def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); | ||||
|         } | ||||
|         } | ||||
|         if let Some(def) = defs.values.as_mut() { | ||||
|             def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); | ||||
|         } | ||||
|  | @ -1259,7 +1254,7 @@ impl DefCollector<'_> { | |||
|     fn resolve_macros(&mut self) -> ReachedFixedPoint { | ||||
|         let mut macros = mem::take(&mut self.unresolved_macros); | ||||
|         let mut resolved = Vec::new(); | ||||
|         let mut push_resolved = |directive: &MacroDirective, call_id| { | ||||
|         let mut push_resolved = |directive: &MacroDirective<'_>, call_id| { | ||||
|             resolved.push((directive.module_id, directive.depth, directive.container, call_id)); | ||||
|         }; | ||||
| 
 | ||||
|  | @ -1272,7 +1267,7 @@ impl DefCollector<'_> { | |||
|         let mut eager_callback_buffer = vec![]; | ||||
|         let mut res = ReachedFixedPoint::Yes; | ||||
|         // Retain unresolved macros after this round of resolution.
 | ||||
|         let mut retain = |directive: &MacroDirective| { | ||||
|         let mut retain = |directive: &MacroDirective<'db>| { | ||||
|             let subns = match &directive.kind { | ||||
|                 MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang, | ||||
|                 MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => { | ||||
|  | @ -1349,7 +1344,7 @@ impl DefCollector<'_> { | |||
|                         // Record its helper attributes.
 | ||||
|                         if def_id.krate != self.def_map.krate { | ||||
|                             let def_map = crate_def_map(self.db, def_id.krate); | ||||
|                             if let Some(helpers) = def_map.data.exported_derives.get(&def_id) { | ||||
|                             if let Some(helpers) = def_map.data.exported_derives.get(¯o_id) { | ||||
|                                 self.def_map | ||||
|                                     .derive_helpers_in_scope | ||||
|                                     .entry(ast_id.ast_id.map(|it| it.upcast())) | ||||
|  | @ -1367,22 +1362,29 @@ impl DefCollector<'_> { | |||
|                         return Resolved::Yes; | ||||
|                     } | ||||
|                 } | ||||
|                 MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => { | ||||
|                 MacroDirectiveKind::Attr { | ||||
|                     ast_id: file_ast_id, | ||||
|                     mod_item, | ||||
|                     attr, | ||||
|                     tree, | ||||
|                     item_tree, | ||||
|                 } => { | ||||
|                     let &AstIdWithPath { ast_id, ref path } = file_ast_id; | ||||
|                     let file_id = ast_id.file_id; | ||||
| 
 | ||||
|                     let mut recollect_without = |collector: &mut Self| { | ||||
|                         // Remove the original directive since we resolved it.
 | ||||
|                         let mod_dir = collector.mod_dirs[&directive.module_id].clone(); | ||||
|                         collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id); | ||||
|                         collector | ||||
|                             .skip_attrs | ||||
|                             .insert(InFile::new(file_id, mod_item.ast_id()), attr.id); | ||||
| 
 | ||||
|                         let item_tree = tree.item_tree(self.db); | ||||
|                         ModCollector { | ||||
|                             def_collector: collector, | ||||
|                             macro_depth: directive.depth, | ||||
|                             module_id: directive.module_id, | ||||
|                             tree_id: *tree, | ||||
|                             item_tree: &item_tree, | ||||
|                             item_tree, | ||||
|                             mod_dir, | ||||
|                         } | ||||
|                         .collect(&[*mod_item], directive.container); | ||||
|  | @ -1435,11 +1437,10 @@ impl DefCollector<'_> { | |||
|                         // normal (as that would just be an identity expansion with extra output)
 | ||||
|                         // Instead we treat derive attributes special and apply them separately.
 | ||||
| 
 | ||||
|                         let item_tree = tree.item_tree(self.db); | ||||
|                         let ast_adt_id: FileAstId<ast::Adt> = match *mod_item { | ||||
|                             ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(), | ||||
|                             ModItem::Union(union) => item_tree[union].ast_id().upcast(), | ||||
|                             ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(), | ||||
|                             ModItemId::Struct(ast_id) => ast_id.upcast(), | ||||
|                             ModItemId::Union(ast_id) => ast_id.upcast(), | ||||
|                             ModItemId::Enum(ast_id) => ast_id.upcast(), | ||||
|                             _ => { | ||||
|                                 let diag = DefDiagnostic::invalid_derive_target( | ||||
|                                     directive.module_id, | ||||
|  | @ -1571,7 +1572,7 @@ impl DefCollector<'_> { | |||
|             macro_depth: depth, | ||||
|             tree_id: TreeId::new(file_id, None), | ||||
|             module_id, | ||||
|             item_tree: &item_tree, | ||||
|             item_tree, | ||||
|             mod_dir, | ||||
|         } | ||||
|         .collect(item_tree.top_level_items(), container); | ||||
|  | @ -1672,22 +1673,22 @@ impl DefCollector<'_> { | |||
| } | ||||
| 
 | ||||
| /// Walks a single module, populating defs, imports and macros
 | ||||
| struct ModCollector<'a, 'b> { | ||||
|     def_collector: &'a mut DefCollector<'b>, | ||||
| struct ModCollector<'a, 'db> { | ||||
|     def_collector: &'a mut DefCollector<'db>, | ||||
|     macro_depth: usize, | ||||
|     module_id: LocalModuleId, | ||||
|     tree_id: TreeId, | ||||
|     item_tree: &'a ItemTree, | ||||
|     item_tree: &'db ItemTree, | ||||
|     mod_dir: ModDir, | ||||
| } | ||||
| 
 | ||||
| impl ModCollector<'_, '_> { | ||||
|     fn collect_in_top_module(&mut self, items: &[ModItem]) { | ||||
|     fn collect_in_top_module(&mut self, items: &[ModItemId]) { | ||||
|         let module = self.def_collector.def_map.module_id(self.module_id); | ||||
|         self.collect(items, module.into()) | ||||
|     } | ||||
| 
 | ||||
|     fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { | ||||
|     fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) { | ||||
|         let krate = self.def_collector.def_map.krate; | ||||
|         let is_crate_root = | ||||
|             self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none(); | ||||
|  | @ -1726,11 +1727,12 @@ impl ModCollector<'_, '_> { | |||
|                 .unwrap_or(Visibility::Public) | ||||
|         }; | ||||
| 
 | ||||
|         let mut process_mod_item = |item: ModItem| { | ||||
|             let attrs = self.item_tree.attrs(db, krate, item.into()); | ||||
|         let mut process_mod_item = |item: ModItemId| { | ||||
|             let attrs = self.item_tree.attrs(db, krate, item.ast_id()); | ||||
|             if let Some(cfg) = attrs.cfg() { | ||||
|                 if !self.is_cfg_enabled(&cfg) { | ||||
|                     self.emit_unconfigured_diagnostic(self.tree_id, item.into(), &cfg); | ||||
|                     let ast_id = item.ast_id().erase(); | ||||
|                     self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | @ -1747,39 +1749,31 @@ impl ModCollector<'_, '_> { | |||
|                 self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map); | ||||
| 
 | ||||
|             match item { | ||||
|                 ModItem::Mod(m) => self.collect_module(m, &attrs), | ||||
|                 ModItem::Use(item_tree_id) => { | ||||
|                     let id = UseLoc { | ||||
|                         container: module, | ||||
|                         id: ItemTreeId::new(self.tree_id, item_tree_id), | ||||
|                     } | ||||
|                 ModItemId::Mod(m) => self.collect_module(m, &attrs), | ||||
|                 ModItemId::Use(item_tree_id) => { | ||||
|                     let id = | ||||
|                         UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) } | ||||
|                             .intern(db); | ||||
|                     let is_prelude = attrs.by_key(sym::prelude_import).exists(); | ||||
|                     Import::from_use( | ||||
|                         self.item_tree, | ||||
|                         ItemTreeId::new(self.tree_id, item_tree_id), | ||||
|                         id, | ||||
|                         is_prelude, | ||||
|                         |import| { | ||||
|                     Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| { | ||||
|                         self.def_collector.unresolved_imports.push(ImportDirective { | ||||
|                             module_id: self.module_id, | ||||
|                             import, | ||||
|                             status: PartialResolvedImport::Unresolved, | ||||
|                         }); | ||||
|                         }, | ||||
|                     ) | ||||
|                     }) | ||||
|                 } | ||||
|                 ModItem::ExternCrate(item_tree_id) => { | ||||
|                 ModItemId::ExternCrate(item_tree_id) => { | ||||
|                     let item_tree::ExternCrate { name, visibility, alias } = | ||||
|                         &self.item_tree[item_tree_id]; | ||||
| 
 | ||||
|                     let id = ExternCrateLoc { | ||||
|                         container: module, | ||||
|                         id: ItemTreeId::new(self.tree_id, item_tree_id), | ||||
|                         id: InFile::new(self.tree_id.file_id(), item_tree_id), | ||||
|                     } | ||||
|                     .intern(db); | ||||
|                     def_map.modules[self.module_id].scope.define_extern_crate_decl(id); | ||||
| 
 | ||||
|                     let item_tree::ExternCrate { name, visibility, alias, ast_id } = | ||||
|                         &self.item_tree[item_tree_id]; | ||||
| 
 | ||||
|                     let is_self = *name == sym::self_; | ||||
|                     let resolved = if is_self { | ||||
|                         cov_mark::hit!(extern_crate_self_as); | ||||
|  | @ -1838,15 +1832,15 @@ impl ModCollector<'_, '_> { | |||
|                         self.def_collector.def_map.diagnostics.push( | ||||
|                             DefDiagnostic::unresolved_extern_crate( | ||||
|                                 module_id, | ||||
|                                 InFile::new(self.file_id(), *ast_id), | ||||
|                                 InFile::new(self.file_id(), item_tree_id), | ||||
|                             ), | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
|                 ModItem::ExternBlock(block) => { | ||||
|                 ModItemId::ExternBlock(block) => { | ||||
|                     let extern_block_id = ExternBlockLoc { | ||||
|                         container: module, | ||||
|                         id: ItemTreeId::new(self.tree_id, block), | ||||
|                         id: InFile::new(self.file_id(), block), | ||||
|                     } | ||||
|                     .intern(db); | ||||
|                     self.def_collector.def_map.modules[self.module_id] | ||||
|  | @ -1857,19 +1851,20 @@ impl ModCollector<'_, '_> { | |||
|                         ItemContainerId::ExternBlockId(extern_block_id), | ||||
|                     ) | ||||
|                 } | ||||
|                 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container), | ||||
|                 ModItem::MacroRules(id) => self.collect_macro_rules(id, module), | ||||
|                 ModItem::Macro2(id) => self.collect_macro_def(id, module), | ||||
|                 ModItem::Impl(imp) => { | ||||
|                 ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container), | ||||
|                 ModItemId::MacroRules(id) => self.collect_macro_rules(id, module), | ||||
|                 ModItemId::Macro2(id) => self.collect_macro_def(id, module), | ||||
|                 ModItemId::Impl(imp) => { | ||||
|                     let impl_id = | ||||
|                         ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) } | ||||
|                         ImplLoc { container: module, id: InFile::new(self.file_id(), imp) } | ||||
|                             .intern(db); | ||||
|                     self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) | ||||
|                 } | ||||
|                 ModItem::Function(id) => { | ||||
|                 ModItemId::Function(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
|                     let fn_id = | ||||
|                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); | ||||
|                         FunctionLoc { container, id: InFile::new(self.tree_id.file_id(), id) } | ||||
|                             .intern(db); | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
| 
 | ||||
|  | @ -1880,8 +1875,7 @@ impl ModCollector<'_, '_> { | |||
|                         if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { | ||||
|                             self.def_collector.export_proc_macro( | ||||
|                                 proc_macro, | ||||
|                                 ItemTreeId::new(self.tree_id, id), | ||||
|                                 InFile::new(self.file_id(), self.item_tree[id].ast_id()), | ||||
|                                 InFile::new(self.file_id(), id), | ||||
|                                 fn_id, | ||||
|                             ); | ||||
|                         } | ||||
|  | @ -1889,13 +1883,13 @@ impl ModCollector<'_, '_> { | |||
| 
 | ||||
|                     update_def(self.def_collector, fn_id.into(), &it.name, vis, false); | ||||
|                 } | ||||
|                 ModItem::Struct(id) => { | ||||
|                 ModItemId::Struct(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         StructLoc { container: module, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -1903,13 +1897,13 @@ impl ModCollector<'_, '_> { | |||
|                         !matches!(it.shape, FieldsShape::Record), | ||||
|                     ); | ||||
|                 } | ||||
|                 ModItem::Union(id) => { | ||||
|                 ModItemId::Union(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         UnionLoc { container: module, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -1917,19 +1911,20 @@ impl ModCollector<'_, '_> { | |||
|                         false, | ||||
|                     ); | ||||
|                 } | ||||
|                 ModItem::Enum(id) => { | ||||
|                 ModItemId::Enum(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
|                     let enum_ = | ||||
|                         EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) } | ||||
|                             .intern(db); | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def(self.def_collector, enum_.into(), &it.name, vis, false); | ||||
|                 } | ||||
|                 ModItem::Const(id) => { | ||||
|                 ModItemId::Const(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
|                     let const_id = | ||||
|                         ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); | ||||
|                         ConstLoc { container, id: InFile::new(self.tree_id.file_id(), id) } | ||||
|                             .intern(db); | ||||
| 
 | ||||
|                     match &it.name { | ||||
|                         Some(name) => { | ||||
|  | @ -1945,13 +1940,13 @@ impl ModCollector<'_, '_> { | |||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 ModItem::Static(id) => { | ||||
|                 ModItemId::Static(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         StaticLoc { container, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -1959,13 +1954,13 @@ impl ModCollector<'_, '_> { | |||
|                         false, | ||||
|                     ); | ||||
|                 } | ||||
|                 ModItem::Trait(id) => { | ||||
|                 ModItemId::Trait(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         TraitLoc { container: module, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -1973,13 +1968,13 @@ impl ModCollector<'_, '_> { | |||
|                         false, | ||||
|                     ); | ||||
|                 } | ||||
|                 ModItem::TraitAlias(id) => { | ||||
|                 ModItemId::TraitAlias(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -1987,13 +1982,13 @@ impl ModCollector<'_, '_> { | |||
|                         false, | ||||
|                     ); | ||||
|                 } | ||||
|                 ModItem::TypeAlias(id) => { | ||||
|                 ModItemId::TypeAlias(id) => { | ||||
|                     let it = &self.item_tree[id]; | ||||
| 
 | ||||
|                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); | ||||
|                     update_def( | ||||
|                         self.def_collector, | ||||
|                         TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) } | ||||
|                         TypeAliasLoc { container, id: InFile::new(self.file_id(), id) } | ||||
|                             .intern(db) | ||||
|                             .into(), | ||||
|                         &it.name, | ||||
|  | @ -2010,12 +2005,12 @@ impl ModCollector<'_, '_> { | |||
|         if is_crate_root { | ||||
|             items | ||||
|                 .iter() | ||||
|                 .filter(|it| matches!(it, ModItem::ExternCrate(..))) | ||||
|                 .filter(|it| matches!(it, ModItemId::ExternCrate(..))) | ||||
|                 .copied() | ||||
|                 .for_each(&mut process_mod_item); | ||||
|             items | ||||
|                 .iter() | ||||
|                 .filter(|it| !matches!(it, ModItem::ExternCrate(..))) | ||||
|                 .filter(|it| !matches!(it, ModItemId::ExternCrate(..))) | ||||
|                 .copied() | ||||
|                 .for_each(process_mod_item); | ||||
|         } else { | ||||
|  | @ -2056,19 +2051,18 @@ impl ModCollector<'_, '_> { | |||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) { | ||||
|     fn collect_module(&mut self, module_ast_id: ItemTreeAstId<Mod>, attrs: &Attrs) { | ||||
|         let path_attr = attrs.by_key(sym::path).string_value_unescape(); | ||||
|         let is_macro_use = attrs.by_key(sym::macro_use).exists(); | ||||
|         let module = &self.item_tree[module_id]; | ||||
|         let module = &self.item_tree[module_ast_id]; | ||||
|         match &module.kind { | ||||
|             // inline module, just recurse
 | ||||
|             ModKind::Inline { items } => { | ||||
|                 let module_id = self.push_child_module( | ||||
|                     module.name.clone(), | ||||
|                     module.ast_id, | ||||
|                     module_ast_id, | ||||
|                     None, | ||||
|                     &self.item_tree[module.visibility], | ||||
|                     module_id, | ||||
|                 ); | ||||
| 
 | ||||
|                 let Some(mod_dir) = | ||||
|  | @ -2091,7 +2085,7 @@ impl ModCollector<'_, '_> { | |||
|             } | ||||
|             // out of line module, resolve, parse and recurse
 | ||||
|             ModKind::Outline => { | ||||
|                 let ast_id = AstId::new(self.file_id(), module.ast_id); | ||||
|                 let ast_id = AstId::new(self.file_id(), module_ast_id); | ||||
|                 let db = self.def_collector.db; | ||||
|                 match self.mod_dir.resolve_declaration( | ||||
|                     db, | ||||
|  | @ -2110,8 +2104,7 @@ impl ModCollector<'_, '_> { | |||
|                         match is_enabled { | ||||
|                             Err(cfg) => { | ||||
|                                 self.emit_unconfigured_diagnostic( | ||||
|                                     self.tree_id, | ||||
|                                     AttrOwner::ModItem(module_id.into()), | ||||
|                                     InFile::new(self.file_id(), module_ast_id.erase()), | ||||
|                                     &cfg, | ||||
|                                 ); | ||||
|                             } | ||||
|  | @ -2121,14 +2114,13 @@ impl ModCollector<'_, '_> { | |||
|                                     ast_id.value, | ||||
|                                     Some((file_id, is_mod_rs)), | ||||
|                                     &self.item_tree[module.visibility], | ||||
|                                     module_id, | ||||
|                                 ); | ||||
|                                 ModCollector { | ||||
|                                     def_collector: self.def_collector, | ||||
|                                     macro_depth: self.macro_depth, | ||||
|                                     module_id, | ||||
|                                     tree_id: TreeId::new(file_id.into(), None), | ||||
|                                     item_tree: &item_tree, | ||||
|                                     item_tree, | ||||
|                                     mod_dir, | ||||
|                                 } | ||||
|                                 .collect_in_top_module(item_tree.top_level_items()); | ||||
|  | @ -2149,7 +2141,6 @@ impl ModCollector<'_, '_> { | |||
|                             ast_id.value, | ||||
|                             None, | ||||
|                             &self.item_tree[module.visibility], | ||||
|                             module_id, | ||||
|                         ); | ||||
|                         self.def_collector.def_map.diagnostics.push( | ||||
|                             DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates), | ||||
|  | @ -2166,7 +2157,6 @@ impl ModCollector<'_, '_> { | |||
|         declaration: FileAstId<ast::Module>, | ||||
|         definition: Option<(EditionedFileId, bool)>, | ||||
|         visibility: &crate::visibility::RawVisibility, | ||||
|         mod_tree_id: FileItemTreeId<Mod>, | ||||
|     ) -> LocalModuleId { | ||||
|         let def_map = &mut self.def_collector.def_map; | ||||
|         let vis = def_map | ||||
|  | @ -2179,15 +2169,14 @@ impl ModCollector<'_, '_> { | |||
|             ) | ||||
|             .unwrap_or(Visibility::Public); | ||||
|         let origin = match definition { | ||||
|             None => ModuleOrigin::Inline { | ||||
|                 definition: declaration, | ||||
|                 definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), | ||||
|             }, | ||||
|             None => { | ||||
|                 ModuleOrigin::Inline { definition: declaration, definition_tree_id: self.tree_id } | ||||
|             } | ||||
|             Some((definition, is_mod_rs)) => ModuleOrigin::File { | ||||
|                 declaration, | ||||
|                 definition, | ||||
|                 is_mod_rs, | ||||
|                 declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), | ||||
|                 declaration_tree_id: self.tree_id, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|  | @ -2228,11 +2217,14 @@ impl ModCollector<'_, '_> { | |||
|     fn resolve_attributes( | ||||
|         &mut self, | ||||
|         attrs: &Attrs, | ||||
|         mod_item: ModItem, | ||||
|         mod_item: ModItemId, | ||||
|         container: ItemContainerId, | ||||
|     ) -> Result<(), ()> { | ||||
|         let mut ignore_up_to = | ||||
|             self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied(); | ||||
|         let mut ignore_up_to = self | ||||
|             .def_collector | ||||
|             .skip_attrs | ||||
|             .get(&InFile::new(self.file_id(), mod_item.ast_id())) | ||||
|             .copied(); | ||||
|         let iter = attrs | ||||
|             .iter() | ||||
|             .dedup_by(|a, b| { | ||||
|  | @ -2262,11 +2254,7 @@ impl ModCollector<'_, '_> { | |||
|                 attr.path.display(self.def_collector.db, Edition::LATEST) | ||||
|             ); | ||||
| 
 | ||||
|             let ast_id = AstIdWithPath::new( | ||||
|                 self.file_id(), | ||||
|                 mod_item.ast_id(self.item_tree), | ||||
|                 attr.path.clone(), | ||||
|             ); | ||||
|             let ast_id = AstIdWithPath::new(self.file_id(), mod_item.ast_id(), attr.path.clone()); | ||||
|             self.def_collector.unresolved_macros.push(MacroDirective { | ||||
|                 module_id: self.module_id, | ||||
|                 depth: self.macro_depth + 1, | ||||
|  | @ -2275,6 +2263,7 @@ impl ModCollector<'_, '_> { | |||
|                     attr: attr.clone(), | ||||
|                     mod_item, | ||||
|                     tree: self.tree_id, | ||||
|                     item_tree: self.item_tree, | ||||
|                 }, | ||||
|                 container, | ||||
|             }); | ||||
|  | @ -2285,11 +2274,11 @@ impl ModCollector<'_, '_> { | |||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) { | ||||
|     fn collect_macro_rules(&mut self, ast_id: ItemTreeAstId<MacroRules>, module: ModuleId) { | ||||
|         let krate = self.def_collector.def_map.krate; | ||||
|         let mac = &self.item_tree[id]; | ||||
|         let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | ||||
|         let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); | ||||
|         let mac = &self.item_tree[ast_id]; | ||||
|         let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast()); | ||||
|         let f_ast_id = InFile::new(self.file_id(), ast_id.upcast()); | ||||
| 
 | ||||
|         let export_attr = || attrs.by_key(sym::macro_export); | ||||
| 
 | ||||
|  | @ -2336,7 +2325,7 @@ impl ModCollector<'_, '_> { | |||
|                     self.def_collector | ||||
|                         .def_map | ||||
|                         .diagnostics | ||||
|                         .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); | ||||
|                         .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id)); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | @ -2352,16 +2341,13 @@ impl ModCollector<'_, '_> { | |||
| 
 | ||||
|         let macro_id = MacroRulesLoc { | ||||
|             container: module, | ||||
|             id: ItemTreeId::new(self.tree_id, id), | ||||
|             id: InFile::new(self.file_id(), ast_id), | ||||
|             flags, | ||||
|             expander, | ||||
|             edition: self.def_collector.def_map.data.edition, | ||||
|         } | ||||
|         .intern(self.def_collector.db); | ||||
|         self.def_collector.def_map.macro_def_to_macro_id.insert( | ||||
|             InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(), | ||||
|             macro_id.into(), | ||||
|         ); | ||||
|         self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into()); | ||||
|         self.def_collector.define_macro_rules( | ||||
|             self.module_id, | ||||
|             mac.name.clone(), | ||||
|  | @ -2370,14 +2356,14 @@ impl ModCollector<'_, '_> { | |||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     fn collect_macro_def(&mut self, id: FileItemTreeId<Macro2>, module: ModuleId) { | ||||
|     fn collect_macro_def(&mut self, ast_id: ItemTreeAstId<Macro2>, module: ModuleId) { | ||||
|         let krate = self.def_collector.def_map.krate; | ||||
|         let mac = &self.item_tree[id]; | ||||
|         let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); | ||||
|         let mac = &self.item_tree[ast_id]; | ||||
|         let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast()); | ||||
|         let f_ast_id = InFile::new(self.file_id(), ast_id.upcast()); | ||||
| 
 | ||||
|         // Case 1: builtin macros
 | ||||
|         let mut helpers_opt = None; | ||||
|         let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | ||||
|         let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() { | ||||
|             if let Some(expander) = find_builtin_macro(&mac.name) { | ||||
|                 match expander { | ||||
|  | @ -2409,7 +2395,7 @@ impl ModCollector<'_, '_> { | |||
|                 self.def_collector | ||||
|                     .def_map | ||||
|                     .diagnostics | ||||
|                     .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); | ||||
|                     .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id)); | ||||
|                 return; | ||||
|             } | ||||
|         } else { | ||||
|  | @ -2420,16 +2406,13 @@ impl ModCollector<'_, '_> { | |||
| 
 | ||||
|         let macro_id = Macro2Loc { | ||||
|             container: module, | ||||
|             id: ItemTreeId::new(self.tree_id, id), | ||||
|             id: InFile::new(self.file_id(), ast_id), | ||||
|             expander, | ||||
|             allow_internal_unsafe, | ||||
|             edition: self.def_collector.def_map.data.edition, | ||||
|         } | ||||
|         .intern(self.def_collector.db); | ||||
|         self.def_collector.def_map.macro_def_to_macro_id.insert( | ||||
|             InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(), | ||||
|             macro_id.into(), | ||||
|         ); | ||||
|         self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into()); | ||||
|         self.def_collector.define_macro_def( | ||||
|             self.module_id, | ||||
|             mac.name.clone(), | ||||
|  | @ -2441,16 +2424,17 @@ impl ModCollector<'_, '_> { | |||
|                 Arc::get_mut(&mut self.def_collector.def_map.data) | ||||
|                     .unwrap() | ||||
|                     .exported_derives | ||||
|                     .insert(self.def_collector.db.macro_def(macro_id.into()), helpers); | ||||
|                     .insert(macro_id.into(), helpers); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn collect_macro_call( | ||||
|         &mut self, | ||||
|         &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall, | ||||
|         ast_id: FileAstId<ast::MacroCall>, | ||||
|         container: ItemContainerId, | ||||
|     ) { | ||||
|         let &MacroCall { ref path, expand_to, ctxt } = &self.item_tree[ast_id]; | ||||
|         let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone()); | ||||
|         let db = self.def_collector.db; | ||||
| 
 | ||||
|  | @ -2565,16 +2549,16 @@ impl ModCollector<'_, '_> { | |||
|         self.def_collector.cfg_options.check(cfg) != Some(false) | ||||
|     } | ||||
| 
 | ||||
|     fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) { | ||||
|     fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) { | ||||
|         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( | ||||
|             self.module_id, | ||||
|             tree_id, | ||||
|             item, | ||||
|             ast_id, | ||||
|             cfg.clone(), | ||||
|             self.def_collector.cfg_options.clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn file_id(&self) -> HirFileId { | ||||
|         self.tree_id.file_id() | ||||
|     } | ||||
|  |  | |||
|  | @ -3,22 +3,18 @@ | |||
| use std::ops::Not; | ||||
| 
 | ||||
| use cfg::{CfgExpr, CfgOptions}; | ||||
| use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; | ||||
| use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; | ||||
| use la_arena::Idx; | ||||
| use syntax::ast; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AstId, | ||||
|     item_tree::{self, AttrOwner, ItemTreeId, TreeId}, | ||||
|     nameres::LocalModuleId, | ||||
| }; | ||||
| use crate::{AstId, nameres::LocalModuleId}; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub enum DefDiagnosticKind { | ||||
|     UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> }, | ||||
|     UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, | ||||
|     UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> }, | ||||
|     UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions }, | ||||
|     UnresolvedImport { id: AstId<ast::Use>, index: Idx<ast::UseTree> }, | ||||
|     UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, | ||||
|     UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, | ||||
|     UnimplementedBuiltinMacro { ast: AstId<ast::Macro> }, | ||||
|     InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize }, | ||||
|  | @ -28,7 +24,7 @@ pub enum DefDiagnosticKind { | |||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||||
| pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>); | ||||
| pub struct DefDiagnostics(Option<triomphe::ThinArc<(), DefDiagnostic>>); | ||||
| 
 | ||||
| impl DefDiagnostics { | ||||
|     pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self { | ||||
|  | @ -36,12 +32,12 @@ impl DefDiagnostics { | |||
|             diagnostics | ||||
|                 .is_empty() | ||||
|                 .not() | ||||
|                 .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())), | ||||
|                 .then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> { | ||||
|         self.0.as_ref().into_iter().flat_map(|it| &***it) | ||||
|         self.0.as_ref().into_iter().flat_map(|it| &it.slice) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -75,7 +71,7 @@ impl DefDiagnostic { | |||
| 
 | ||||
|     pub(super) fn unresolved_import( | ||||
|         container: LocalModuleId, | ||||
|         id: ItemTreeId<item_tree::Use>, | ||||
|         id: AstId<ast::Use>, | ||||
|         index: Idx<ast::UseTree>, | ||||
|     ) -> Self { | ||||
|         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } | ||||
|  | @ -92,14 +88,13 @@ impl DefDiagnostic { | |||
| 
 | ||||
|     pub fn unconfigured_code( | ||||
|         container: LocalModuleId, | ||||
|         tree: TreeId, | ||||
|         item: AttrOwner, | ||||
|         ast_id: ErasedAstId, | ||||
|         cfg: CfgExpr, | ||||
|         opts: CfgOptions, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             in_module: container, | ||||
|             kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts }, | ||||
|             kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ | |||
| 
 | ||||
| use either::Either; | ||||
| use hir_expand::{ | ||||
|     Lookup, | ||||
|     mod_path::{ModPath, PathKind}, | ||||
|     name::Name, | ||||
| }; | ||||
|  | @ -107,7 +106,7 @@ impl DefMap { | |||
|         visibility: &RawVisibility, | ||||
|         within_impl: bool, | ||||
|     ) -> Option<Visibility> { | ||||
|         let mut vis = match visibility { | ||||
|         let vis = match visibility { | ||||
|             RawVisibility::Module(path, explicitness) => { | ||||
|                 let (result, remaining) = self.resolve_path( | ||||
|                     local_def_map, | ||||
|  | @ -121,15 +120,12 @@ impl DefMap { | |||
|                     return None; | ||||
|                 } | ||||
|                 let types = result.take_types()?; | ||||
|                 match types { | ||||
|                 let mut vis = match types { | ||||
|                     ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness), | ||||
|                     // error: visibility needs to refer to module
 | ||||
|                     _ => { | ||||
|                         return None; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             RawVisibility::Public => Visibility::Public, | ||||
|                 }; | ||||
| 
 | ||||
|                 // In block expressions, `self` normally refers to the containing non-block module, and
 | ||||
|  | @ -138,12 +134,22 @@ impl DefMap { | |||
|                 if let Visibility::Module(m, mv) = vis { | ||||
|                     // ...unless we're resolving visibility for an associated item in an impl.
 | ||||
|                     if self.block_id() != m.block && !within_impl { | ||||
|                 cov_mark::hit!(adjust_vis_in_block_def_map); | ||||
|                         vis = Visibility::Module(self.module_id(Self::ROOT), mv); | ||||
|                 tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); | ||||
|                         tracing::debug!( | ||||
|                             "visibility {:?} points outside DefMap, adjusting to {:?}", | ||||
|                             m, | ||||
|                             vis | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 vis | ||||
|             } | ||||
|             RawVisibility::PubSelf(explicitness) => { | ||||
|                 Visibility::Module(self.module_id(original_module), *explicitness) | ||||
|             } | ||||
|             RawVisibility::Public => Visibility::Public, | ||||
|             RawVisibility::PubCrate => Visibility::PubCrate(self.krate), | ||||
|         }; | ||||
|         Some(vis) | ||||
|     } | ||||
| 
 | ||||
|  | @ -529,11 +535,12 @@ impl DefMap { | |||
|                     // enum variant
 | ||||
|                     cov_mark::hit!(can_import_enum_variant); | ||||
| 
 | ||||
|                     let res = | ||||
|                         db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map( | ||||
|                             |&(variant, _)| { | ||||
|                                 let item_tree_id = variant.lookup(db).id; | ||||
|                                 match item_tree_id.item_tree(db)[item_tree_id.value].shape { | ||||
|                     let res = e | ||||
|                         .enum_variants(db) | ||||
|                         .variants | ||||
|                         .iter() | ||||
|                         .find(|(_, name, _)| name == segment) | ||||
|                         .map(|&(variant, _, shape)| match shape { | ||||
|                             FieldsShape::Record => { | ||||
|                                 PerNs::types(variant.into(), Visibility::Public, None) | ||||
|                             } | ||||
|  | @ -543,9 +550,7 @@ impl DefMap { | |||
|                                 Visibility::Public, | ||||
|                                 None, | ||||
|                             ), | ||||
|                                 } | ||||
|                             }, | ||||
|                         ); | ||||
|                         }); | ||||
|                     // FIXME: Need to filter visibility here and below? Not sure.
 | ||||
|                     return match res { | ||||
|                         Some(res) => { | ||||
|  |  | |||
|  | @ -2,13 +2,13 @@ use base_db::{ | |||
|     CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, | ||||
|     DependencyBuilder, Env, RootQueryDb, SourceDatabase, | ||||
| }; | ||||
| use expect_test::{Expect, expect}; | ||||
| use intern::Symbol; | ||||
| use span::Edition; | ||||
| use test_fixture::WithFixture; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, ModuleDefId, | ||||
|     db::DefDatabase, | ||||
|     nameres::{crate_def_map, tests::TestDB}, | ||||
| }; | ||||
|  | @ -16,29 +16,29 @@ use crate::{ | |||
| fn check_def_map_is_not_recomputed( | ||||
|     #[rust_analyzer::rust_fixture] ra_fixture_initial: &str, | ||||
|     #[rust_analyzer::rust_fixture] ra_fixture_change: &str, | ||||
|     expecta: Expect, | ||||
|     expectb: Expect, | ||||
| ) { | ||||
|     let (mut db, pos) = TestDB::with_position(ra_fixture_initial); | ||||
|     let krate = db.fetch_test_crate(); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             crate_def_map(&db, krate); | ||||
|         }); | ||||
|         assert!( | ||||
|             format!("{events:?}").contains("crate_local_def_map"), | ||||
|             "no crate def map computed:\n{events:#?}", | ||||
|         ) | ||||
|     } | ||||
|         }, | ||||
|         &[], | ||||
|         expecta, | ||||
|     ); | ||||
|     db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change); | ||||
| 
 | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             crate_def_map(&db, krate); | ||||
|         }); | ||||
|         assert!( | ||||
|             !format!("{events:?}").contains("crate_local_def_map"), | ||||
|             "crate def map invalidated:\n{events:#?}", | ||||
|         ) | ||||
|     } | ||||
|         }, | ||||
|         &[("crate_local_def_map", 0)], | ||||
|         expectb, | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -104,15 +104,20 @@ pub const BAZ: u32 = 0; | |||
|         Arc::ptr_eq(&all_crates_before, &all_crates_after), | ||||
|         "the all_crates list should not have been invalidated" | ||||
|     ); | ||||
| 
 | ||||
|     let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             for &krate in db.all_crates().iter() { | ||||
|                 crate_def_map(&db, krate); | ||||
|             } | ||||
|     }); | ||||
|     let invalidated_def_maps = | ||||
|         events.iter().filter(|event| event.contains("crate_local_def_map")).count(); | ||||
|     assert_eq!(invalidated_def_maps, 1, "{events:#?}") | ||||
|         }, | ||||
|         &[("crate_local_def_map", 1)], | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -152,6 +157,33 @@ fn foo() -> i32 { 92 } | |||
| #[cfg(never)] | ||||
| fn no() {} | ||||
| ",
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "of_", | ||||
|             ] | ||||
|         "#]],
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "of_", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  | @ -183,6 +215,41 @@ m!(Y); | |||
| 
 | ||||
| pub struct S {} | ||||
| ",
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "decl_macro_expander_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  | @ -206,6 +273,49 @@ fn f() {} | |||
| #[proc_macros::identity] | ||||
| fn f() { foo } | ||||
| ",
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "proc_macros_for_crate_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "expand_proc_macro_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "proc_macro_span_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "expand_proc_macro_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  | @ -287,6 +397,60 @@ m2!(X); | |||
| #[derive(proc_macros::DeriveIdentity)] | ||||
| pub struct S {} | ||||
| ",
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "decl_macro_expander_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "decl_macro_expander_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "proc_macros_for_crate_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "expand_proc_macro_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "proc_macro_span_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "decl_macro_expander_shim", | ||||
|                 "macro_arg_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
|  | @ -341,19 +505,46 @@ m!(Z); | |||
| "#,
 | ||||
|     ); | ||||
|     let krate = db.test_crate(); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let crate_def_map = crate_def_map(&db, krate); | ||||
|             let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||||
|             assert_eq!(module_data.scope.resolutions().count(), 4); | ||||
|         }); | ||||
|         let n_recalculated_item_trees = | ||||
|             events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); | ||||
|         assert_eq!(n_recalculated_item_trees, 6); | ||||
|         let n_reparsed_macros = | ||||
|             events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); | ||||
|         assert_eq!(n_reparsed_macros, 3); | ||||
|     } | ||||
|         }, | ||||
|         &[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)], | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_def_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "decl_macro_expander_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_macro_expansion_shim", | ||||
|                 "macro_arg_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = r#" | ||||
| m!(X); | ||||
|  | @ -363,28 +554,31 @@ m!(Z); | |||
| "#;
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let crate_def_map = crate_def_map(&db, krate); | ||||
|             let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||||
|             assert_eq!(module_data.scope.resolutions().count(), 4); | ||||
|         }); | ||||
|         let n_recalculated_item_trees = | ||||
|             events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); | ||||
|         assert_eq!(n_recalculated_item_trees, 1, "{events:#?}"); | ||||
|         let n_reparsed_macros = | ||||
|             events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); | ||||
|         assert_eq!(n_reparsed_macros, 0); | ||||
|     } | ||||
|         }, | ||||
|         &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)], | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "macro_arg_shim", | ||||
|                 "macro_arg_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn item_tree_prevents_reparsing() { | ||||
|     // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and
 | ||||
|     // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to
 | ||||
|     // run those other queries without triggering a reparse.
 | ||||
| 
 | ||||
|     let (db, pos) = TestDB::with_position( | ||||
|     let (mut db, pos) = TestDB::with_position( | ||||
|         r#" | ||||
| pub struct S; | ||||
| pub union U {} | ||||
|  | @ -399,53 +593,54 @@ pub static ST: u8 = 0; | |||
| pub type Ty = (); | ||||
| "#,
 | ||||
|     ); | ||||
|     let krate = db.test_crate(); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
| 
 | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             db.file_item_tree(pos.file_id.into()); | ||||
|         }); | ||||
|         let n_calculated_item_trees = | ||||
|             events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); | ||||
|         assert_eq!(n_calculated_item_trees, 1); | ||||
|         let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count(); | ||||
|         assert_eq!(n_parsed_files, 1); | ||||
|     } | ||||
| 
 | ||||
|     // FIXME(salsa-transition): bring this back
 | ||||
|     // base_db::ParseQuery.in_db(&db).purge();
 | ||||
| 
 | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|             let crate_def_map = crate_def_map(&db, krate); | ||||
|             let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||||
|             assert_eq!(module_data.scope.resolutions().count(), 8); | ||||
|             assert_eq!(module_data.scope.impls().count(), 1); | ||||
| 
 | ||||
|             for imp in module_data.scope.impls() { | ||||
|                 db.impl_signature(imp); | ||||
|             } | ||||
| 
 | ||||
|             for (_, res) in module_data.scope.resolutions() { | ||||
|                 match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() { | ||||
|                     ModuleDefId::FunctionId(f) => _ = db.function_signature(f), | ||||
|                     ModuleDefId::AdtId(adt) => match adt { | ||||
|                         AdtId::StructId(it) => _ = db.struct_signature(it), | ||||
|                         AdtId::UnionId(it) => _ = db.union_signature(it), | ||||
|                         AdtId::EnumId(it) => _ = db.enum_signature(it), | ||||
|         }, | ||||
|                     ModuleDefId::ConstId(it) => _ = db.const_signature(it), | ||||
|                     ModuleDefId::StaticId(it) => _ = db.static_signature(it), | ||||
|                     ModuleDefId::TraitId(it) => _ = db.trait_signature(it), | ||||
|                     ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_signature(it), | ||||
|                     ModuleDefId::TypeAliasId(it) => _ = db.type_alias_signature(it), | ||||
|                     ModuleDefId::EnumVariantId(_) | ||||
|                     | ModuleDefId::ModuleId(_) | ||||
|                     | ModuleDefId::MacroId(_) | ||||
|                     | ModuleDefId::BuiltinType(_) => unreachable!(), | ||||
|         &[("file_item_tree_query", 1), ("parse", 1)], | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let file_id = pos.file_id.file_id(&db); | ||||
|     let file_text = db.file_text(file_id).text(&db); | ||||
|     db.set_file_text(file_id, &format!("{file_text}\n")); | ||||
| 
 | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             db.file_item_tree(pos.file_id.into()); | ||||
|         }, | ||||
|         &[("file_item_tree_query", 1), ("parse", 1)], | ||||
|         expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| fn execute_assert_events( | ||||
|     db: &TestDB, | ||||
|     f: impl FnOnce(), | ||||
|     required: &[(&str, usize)], | ||||
|     expect: Expect, | ||||
| ) { | ||||
|     let events = db.log_executed(f); | ||||
|     for (event, count) in required { | ||||
|         let n = events.iter().filter(|it| it.contains(event)).count(); | ||||
|         assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}"); | ||||
|     } | ||||
|         }); | ||||
|         let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); | ||||
|         assert_eq!(n_reparsed_files, 0); | ||||
|     } | ||||
|     expect.assert_debug_eq(&events); | ||||
| } | ||||
|  |  | |||
|  | @ -5,21 +5,22 @@ use base_db::Crate; | |||
| use hir_expand::{ | ||||
|     MacroDefId, | ||||
|     mod_path::{ModPath, PathKind}, | ||||
|     name::Name, | ||||
|     name::{AsName, Name}, | ||||
| }; | ||||
| use intern::{Symbol, sym}; | ||||
| use itertools::Itertools as _; | ||||
| use rustc_hash::FxHashSet; | ||||
| use smallvec::{SmallVec, smallvec}; | ||||
| use span::SyntaxContext; | ||||
| use syntax::ast::HasName; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, | ||||
|     ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, | ||||
|     ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, | ||||
|     MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, | ||||
|     TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, | ||||
|     AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, | ||||
|     EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, | ||||
|     GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, | ||||
|     Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, | ||||
|     TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, | ||||
|     builtin_type::BuiltinType, | ||||
|     db::DefDatabase, | ||||
|     expr_store::{ | ||||
|  | @ -32,10 +33,10 @@ use crate::{ | |||
|         generics::{GenericParams, TypeOrConstParamData}, | ||||
|     }, | ||||
|     item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope}, | ||||
|     item_tree::ImportAlias, | ||||
|     lang_item::LangItemTarget, | ||||
|     nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, | ||||
|     per_ns::PerNs, | ||||
|     src::HasSource, | ||||
|     type_ref::LifetimeRef, | ||||
|     visibility::{RawVisibility, Visibility}, | ||||
| }; | ||||
|  | @ -304,6 +305,10 @@ impl<'db> Resolver<'db> { | |||
|                     }), | ||||
|                 ) | ||||
|             } | ||||
|             RawVisibility::PubSelf(explicitness) => { | ||||
|                 Some(Visibility::Module(self.module(), *explicitness)) | ||||
|             } | ||||
|             RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())), | ||||
|             RawVisibility::Public => Some(Visibility::Public), | ||||
|         } | ||||
|     } | ||||
|  | @ -627,14 +632,14 @@ impl<'db> Resolver<'db> { | |||
|             .extern_crate_decls() | ||||
|             .filter_map(|id| { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let tree = loc.item_tree_id().item_tree(db); | ||||
|                 match &tree[loc.id.value].alias { | ||||
|                     Some(alias) => match alias { | ||||
|                         ImportAlias::Underscore => None, | ||||
|                         ImportAlias::Alias(name) => Some(name.clone()), | ||||
|                     }, | ||||
|                     None => Some(tree[loc.id.value].name.clone()), | ||||
|                 } | ||||
|                 let extern_crate = loc.source(db); | ||||
|                 // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate`
 | ||||
|                 // if it is an underscore.
 | ||||
|                 extern_crate | ||||
|                     .value | ||||
|                     .rename() | ||||
|                     .map(|a| a.name().map(|it| it.as_name())) | ||||
|                     .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name())) | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|  | @ -1471,10 +1476,7 @@ impl HasResolver for MacroRulesId { | |||
| 
 | ||||
| fn lookup_resolver( | ||||
|     db: &dyn DefDatabase, | ||||
|     lookup: impl Lookup< | ||||
|         Database = dyn DefDatabase, | ||||
|         Data = impl ItemTreeLoc<Container = impl HasResolver>, | ||||
|     >, | ||||
|     lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Container = impl HasResolver>>, | ||||
| ) -> Resolver<'_> { | ||||
|     lookup.lookup(db).container().resolver(db) | ||||
| } | ||||
|  |  | |||
|  | @ -4,21 +4,25 @@ use std::ops::Not as _; | |||
| 
 | ||||
| use bitflags::bitflags; | ||||
| use cfg::{CfgExpr, CfgOptions}; | ||||
| use either::Either; | ||||
| use hir_expand::{InFile, Intern, Lookup, name::Name}; | ||||
| use hir_expand::{ | ||||
|     InFile, Intern, Lookup, | ||||
|     name::{AsName, Name}, | ||||
| }; | ||||
| use intern::{Symbol, sym}; | ||||
| use la_arena::{Arena, Idx}; | ||||
| use rustc_abi::{IntegerType, ReprOptions}; | ||||
| use syntax::{ | ||||
|     AstNode, SyntaxNodePtr, | ||||
|     ast::{self, HasGenericParams, IsString}, | ||||
|     NodeOrToken, SyntaxNodePtr, T, | ||||
|     ast::{self, HasGenericParams, HasName, HasVisibility, IsString}, | ||||
| }; | ||||
| use thin_vec::ThinVec; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId, | ||||
|     ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId, | ||||
|     ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId, | ||||
|     ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, | ||||
|     VariantId, | ||||
|     attr::Attrs, | ||||
|     db::DefDatabase, | ||||
|     expr_store::{ | ||||
|         ExpressionStore, ExpressionStoreSourceMap, | ||||
|  | @ -28,15 +32,17 @@ use crate::{ | |||
|         }, | ||||
|     }, | ||||
|     hir::{ExprId, PatId, generics::GenericParams}, | ||||
|     item_tree::{ | ||||
|         AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem, | ||||
|         RawVisibility, RawVisibilityId, | ||||
|     }, | ||||
|     item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, | ||||
|     lang_item::LangItem, | ||||
|     src::HasSource, | ||||
|     type_ref::{TraitRef, TypeBound, TypeRefId}, | ||||
| }; | ||||
| 
 | ||||
| #[inline] | ||||
| fn as_name_opt(name: Option<ast::Name>) -> Name { | ||||
|     name.map_or_else(Name::missing, |it| it.as_name()) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub struct StructSignature { | ||||
|     pub name: Name, | ||||
|  | @ -70,8 +76,8 @@ bitflags! { | |||
| impl StructSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); | ||||
|         let InFile { file_id, value: source } = loc.source(db); | ||||
|         let attrs = db.attrs(id.into()); | ||||
| 
 | ||||
|         let mut flags = StructFlags::empty(); | ||||
|         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { | ||||
|  | @ -91,23 +97,23 @@ impl StructSignature { | |||
|             } | ||||
|         } | ||||
|         let repr = attrs.repr(); | ||||
|         let shape = adt_shape(source.kind()); | ||||
| 
 | ||||
|         let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); | ||||
|         let (store, generic_params, source_map) = lower_generic_params( | ||||
|             db, | ||||
|             loc.container, | ||||
|             id.into(), | ||||
|             file_id, | ||||
|             value.generic_param_list(), | ||||
|             value.where_clause(), | ||||
|             source.generic_param_list(), | ||||
|             source.where_clause(), | ||||
|         ); | ||||
|         ( | ||||
|             Arc::new(StructSignature { | ||||
|                 generic_params, | ||||
|                 store, | ||||
|                 flags, | ||||
|                 shape: item_tree[loc.id.value].shape, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 shape, | ||||
|                 name: as_name_opt(source.name()), | ||||
|                 repr, | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|  | @ -115,6 +121,15 @@ impl StructSignature { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[inline] | ||||
| fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { | ||||
|     match adt_kind { | ||||
|         ast::StructKind::Record(_) => FieldsShape::Record, | ||||
|         ast::StructKind::Tuple(_) => FieldsShape::Tuple, | ||||
|         ast::StructKind::Unit => FieldsShape::Unit, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub struct UnionSignature { | ||||
|     pub name: Name, | ||||
|  | @ -127,9 +142,7 @@ pub struct UnionSignature { | |||
| impl UnionSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let krate = loc.container.krate; | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         let mut flags = StructFlags::empty(); | ||||
|         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { | ||||
|             flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; | ||||
|  | @ -140,14 +153,14 @@ impl UnionSignature { | |||
| 
 | ||||
|         let repr = attrs.repr(); | ||||
| 
 | ||||
|         let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); | ||||
|         let InFile { file_id, value: source } = loc.source(db); | ||||
|         let (store, generic_params, source_map) = lower_generic_params( | ||||
|             db, | ||||
|             loc.container, | ||||
|             id.into(), | ||||
|             file_id, | ||||
|             value.generic_param_list(), | ||||
|             value.where_clause(), | ||||
|             source.generic_param_list(), | ||||
|             source.where_clause(), | ||||
|         ); | ||||
|         ( | ||||
|             Arc::new(UnionSignature { | ||||
|  | @ -155,7 +168,7 @@ impl UnionSignature { | |||
|                 store, | ||||
|                 flags, | ||||
|                 repr, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name: as_name_opt(source.name()), | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|  | @ -181,8 +194,7 @@ pub struct EnumSignature { | |||
| impl EnumSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         let mut flags = EnumFlags::empty(); | ||||
|         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { | ||||
|             flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; | ||||
|  | @ -190,14 +202,14 @@ impl EnumSignature { | |||
| 
 | ||||
|         let repr = attrs.repr(); | ||||
| 
 | ||||
|         let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); | ||||
|         let InFile { file_id, value: source } = loc.source(db); | ||||
|         let (store, generic_params, source_map) = lower_generic_params( | ||||
|             db, | ||||
|             loc.container, | ||||
|             id.into(), | ||||
|             file_id, | ||||
|             value.generic_param_list(), | ||||
|             value.where_clause(), | ||||
|             source.generic_param_list(), | ||||
|             source.where_clause(), | ||||
|         ); | ||||
| 
 | ||||
|         ( | ||||
|  | @ -206,7 +218,7 @@ impl EnumSignature { | |||
|                 store, | ||||
|                 flags, | ||||
|                 repr, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name: as_name_opt(source.name()), | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|  | @ -239,10 +251,9 @@ pub struct ConstSignature { | |||
| impl ConstSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let module = loc.container.module(db); | ||||
|         let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         let mut flags = ConstFlags::empty(); | ||||
|         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { | ||||
|             flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL; | ||||
|  | @ -253,14 +264,14 @@ impl ConstSignature { | |||
|         } | ||||
| 
 | ||||
|         let (store, source_map, type_ref) = | ||||
|             crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); | ||||
|             crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); | ||||
| 
 | ||||
|         ( | ||||
|             Arc::new(ConstSignature { | ||||
|                 store: Arc::new(store), | ||||
|                 type_ref, | ||||
|                 flags, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name: source.value.name().map(|it| it.as_name()), | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|  | @ -295,10 +306,9 @@ pub struct StaticSignature { | |||
| impl StaticSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let module = loc.container.module(db); | ||||
|         let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         let mut flags = StaticFlags::empty(); | ||||
|         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { | ||||
|             flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL; | ||||
|  | @ -323,14 +333,14 @@ impl StaticSignature { | |||
|         } | ||||
| 
 | ||||
|         let (store, source_map, type_ref) = | ||||
|             crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); | ||||
|             crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); | ||||
| 
 | ||||
|         ( | ||||
|             Arc::new(StaticSignature { | ||||
|                 store: Arc::new(store), | ||||
|                 type_ref, | ||||
|                 flags, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name: as_name_opt(source.value.name()), | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|  | @ -407,10 +417,9 @@ pub struct TraitSignature { | |||
| impl TraitSignature { | ||||
|     pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let mut flags = TraitFlags::empty(); | ||||
|         let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         let source = loc.source(db); | ||||
|         if source.value.auto_token().is_some() { | ||||
|             flags.insert(TraitFlags::AUTO); | ||||
|  | @ -446,15 +455,11 @@ impl TraitSignature { | |||
|             flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH; | ||||
|         } | ||||
| 
 | ||||
|         let name = as_name_opt(source.value.name()); | ||||
|         let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id); | ||||
| 
 | ||||
|         ( | ||||
|             Arc::new(TraitSignature { | ||||
|                 store: Arc::new(store), | ||||
|                 generic_params, | ||||
|                 flags, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|             }), | ||||
|             Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|     } | ||||
|  | @ -473,17 +478,13 @@ impl TraitAliasSignature { | |||
|         id: TraitAliasId, | ||||
|     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let source = loc.source(db); | ||||
|         let name = as_name_opt(source.value.name()); | ||||
|         let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id); | ||||
| 
 | ||||
|         ( | ||||
|             Arc::new(TraitAliasSignature { | ||||
|                 generic_params, | ||||
|                 store: Arc::new(store), | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|             }), | ||||
|             Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|     } | ||||
|  | @ -530,10 +531,9 @@ impl FunctionSignature { | |||
|     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let module = loc.container.module(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let mut flags = FnFlags::empty(); | ||||
|         let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { | ||||
|             flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL); | ||||
|         } | ||||
|  | @ -568,6 +568,7 @@ impl FunctionSignature { | |||
|             flags.insert(FnFlags::HAS_BODY); | ||||
|         } | ||||
| 
 | ||||
|         let name = as_name_opt(source.value.name()); | ||||
|         let abi = source.value.abi().map(|abi| { | ||||
|             abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes())) | ||||
|         }); | ||||
|  | @ -588,7 +589,7 @@ impl FunctionSignature { | |||
|                 abi, | ||||
|                 flags, | ||||
|                 legacy_const_generics_indices, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name, | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|         ) | ||||
|  | @ -662,14 +663,9 @@ impl TypeAliasSignature { | |||
|         id: TypeAliasId, | ||||
|     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { | ||||
|         let loc = id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         let mut flags = TypeAliasFlags::empty(); | ||||
|         let attrs = item_tree.attrs( | ||||
|             db, | ||||
|             loc.container.module(db).krate(), | ||||
|             ModItem::from(loc.id.value).into(), | ||||
|         ); | ||||
|         let attrs = db.attrs(id.into()); | ||||
|         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { | ||||
|             flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL); | ||||
|         } | ||||
|  | @ -680,6 +676,7 @@ impl TypeAliasSignature { | |||
|             flags.insert(TypeAliasFlags::IS_EXTERN); | ||||
|         } | ||||
|         let source = loc.source(db); | ||||
|         let name = as_name_opt(source.value.name()); | ||||
|         let (store, source_map, generic_params, bounds, ty) = | ||||
|             lower_type_alias(db, loc.container.module(db), source, id); | ||||
| 
 | ||||
|  | @ -689,7 +686,7 @@ impl TypeAliasSignature { | |||
|                 generic_params, | ||||
|                 flags, | ||||
|                 bounds, | ||||
|                 name: item_tree[loc.id.value].name.clone(), | ||||
|                 name, | ||||
|                 ty, | ||||
|             }), | ||||
|             Arc::new(source_map), | ||||
|  | @ -743,104 +740,41 @@ impl VariantFields { | |||
|         let (shape, (fields, store, source_map)) = match id { | ||||
|             VariantId::EnumVariantId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 let parent = loc.parent.lookup(db); | ||||
|                 let variant = &item_tree[loc.id.value]; | ||||
|                 ( | ||||
|                     variant.shape, | ||||
|                     lower_fields( | ||||
|                 let source = loc.source(db); | ||||
|                 let shape = adt_shape(source.value.kind()); | ||||
|                 let span_map = db.span_map(source.file_id); | ||||
|                 let override_visibility = visibility_from_ast( | ||||
|                     db, | ||||
|                     source.value.parent_enum().visibility(), | ||||
|                     &mut |range| span_map.span_for_range(range).ctx, | ||||
|                 ); | ||||
|                 let fields = lower_field_list( | ||||
|                     db, | ||||
|                     parent.container, | ||||
|                         &item_tree, | ||||
|                         FieldParent::EnumVariant(loc.id.value), | ||||
|                         loc.source(db).map(|src| { | ||||
|                             variant.fields.iter().zip( | ||||
|                                 src.field_list() | ||||
|                                     .map(|it| { | ||||
|                                         match it { | ||||
|                                             ast::FieldList::RecordFieldList(record_field_list) => { | ||||
|                                                 Either::Left(record_field_list.fields().map(|it| { | ||||
|                                                     (SyntaxNodePtr::new(it.syntax()), it.ty()) | ||||
|                                                 })) | ||||
|                                             } | ||||
|                                             ast::FieldList::TupleFieldList(field_list) => { | ||||
|                                                 Either::Right(field_list.fields().map(|it| { | ||||
|                                                     (SyntaxNodePtr::new(it.syntax()), it.ty()) | ||||
|                                                 })) | ||||
|                                             } | ||||
|                                         } | ||||
|                                         .into_iter() | ||||
|                                     }) | ||||
|                                     .into_iter() | ||||
|                                     .flatten(), | ||||
|                             ) | ||||
|                         }), | ||||
|                         Some(item_tree[parent.id.value].visibility), | ||||
|                     ), | ||||
|                 ) | ||||
|                     source.map(|src| src.field_list()), | ||||
|                     Some(override_visibility), | ||||
|                 ); | ||||
|                 (shape, fields) | ||||
|             } | ||||
|             VariantId::StructId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 let strukt = &item_tree[loc.id.value]; | ||||
|                 ( | ||||
|                     strukt.shape, | ||||
|                     lower_fields( | ||||
|                         db, | ||||
|                         loc.container, | ||||
|                         &item_tree, | ||||
|                         FieldParent::Struct(loc.id.value), | ||||
|                         loc.source(db).map(|src| { | ||||
|                             strukt.fields.iter().zip( | ||||
|                                 src.field_list() | ||||
|                                     .map(|it| { | ||||
|                                         match it { | ||||
|                                             ast::FieldList::RecordFieldList(record_field_list) => { | ||||
|                                                 Either::Left(record_field_list.fields().map(|it| { | ||||
|                                                     (SyntaxNodePtr::new(it.syntax()), it.ty()) | ||||
|                                                 })) | ||||
|                                             } | ||||
|                                             ast::FieldList::TupleFieldList(field_list) => { | ||||
|                                                 Either::Right(field_list.fields().map(|it| { | ||||
|                                                     (SyntaxNodePtr::new(it.syntax()), it.ty()) | ||||
|                                                 })) | ||||
|                                             } | ||||
|                                         } | ||||
|                                         .into_iter() | ||||
|                                     }) | ||||
|                                     .into_iter() | ||||
|                                     .flatten(), | ||||
|                             ) | ||||
|                         }), | ||||
|                         None, | ||||
|                     ), | ||||
|                 ) | ||||
|                 let source = loc.source(db); | ||||
|                 let shape = adt_shape(source.value.kind()); | ||||
|                 let fields = | ||||
|                     lower_field_list(db, loc.container, source.map(|src| src.field_list()), None); | ||||
|                 (shape, fields) | ||||
|             } | ||||
|             VariantId::UnionId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 let union = &item_tree[loc.id.value]; | ||||
|                 ( | ||||
|                     FieldsShape::Record, | ||||
|                     lower_fields( | ||||
|                 let source = loc.source(db); | ||||
|                 let fields = lower_field_list( | ||||
|                     db, | ||||
|                     loc.container, | ||||
|                         &item_tree, | ||||
|                         FieldParent::Union(loc.id.value), | ||||
|                         loc.source(db).map(|src| { | ||||
|                             union.fields.iter().zip( | ||||
|                                 src.record_field_list() | ||||
|                                     .map(|it| { | ||||
|                                         it.fields() | ||||
|                                             .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty())) | ||||
|                                     }) | ||||
|                                     .into_iter() | ||||
|                                     .flatten(), | ||||
|                             ) | ||||
|                         }), | ||||
|                     source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)), | ||||
|                     None, | ||||
|                     ), | ||||
|                 ) | ||||
|                 ); | ||||
|                 (FieldsShape::Record, fields) | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|  | @ -860,39 +794,81 @@ impl VariantFields { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fn lower_fields<'a>( | ||||
| fn lower_field_list( | ||||
|     db: &dyn DefDatabase, | ||||
|     module: ModuleId, | ||||
|     item_tree: &ItemTree, | ||||
|     parent: FieldParent, | ||||
|     fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>, | ||||
|     override_visibility: Option<RawVisibilityId>, | ||||
|     fields: InFile<Option<ast::FieldList>>, | ||||
|     override_visibility: Option<RawVisibility>, | ||||
| ) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { | ||||
|     let file_id = fields.file_id; | ||||
|     match fields.value { | ||||
|         Some(ast::FieldList::RecordFieldList(fields)) => lower_fields( | ||||
|             db, | ||||
|             module, | ||||
|             InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), | ||||
|             |_, field| as_name_opt(field.name()), | ||||
|             override_visibility, | ||||
|         ), | ||||
|         Some(ast::FieldList::TupleFieldList(fields)) => lower_fields( | ||||
|             db, | ||||
|             module, | ||||
|             InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), | ||||
|             |idx, _| Name::new_tuple_field(idx), | ||||
|             override_visibility, | ||||
|         ), | ||||
|         None => lower_fields( | ||||
|             db, | ||||
|             module, | ||||
|             InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()), | ||||
|             |_, _| Name::missing(), | ||||
|             None, | ||||
|         ), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>( | ||||
|     db: &dyn DefDatabase, | ||||
|     module: ModuleId, | ||||
|     fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>, | ||||
|     mut field_name: impl FnMut(usize, &Field) -> Name, | ||||
|     override_visibility: Option<RawVisibility>, | ||||
| ) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { | ||||
|     let mut arena = Arena::new(); | ||||
|     let cfg_options = module.krate.cfg_options(db); | ||||
|     let mut col = ExprCollector::new(db, module, fields.file_id); | ||||
|     for (idx, (field, (ptr, ty))) in fields.value.enumerate() { | ||||
|         let attr_owner = AttrOwner::make_field_indexed(parent, idx); | ||||
|         let attrs = item_tree.attrs(db, module.krate, attr_owner); | ||||
|         if attrs.is_cfg_enabled(cfg_options) { | ||||
|             arena.alloc(FieldData { | ||||
|                 name: field.name.clone(), | ||||
|                 type_ref: col | ||||
|                     .lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator), | ||||
|                 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), | ||||
|                 is_unsafe: field.is_unsafe, | ||||
|     let mut idx = 0; | ||||
|     for (ty, field) in fields.value { | ||||
|         match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) { | ||||
|             Ok(()) => { | ||||
|                 let type_ref = | ||||
|                     col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator); | ||||
|                 let visibility = override_visibility.clone().unwrap_or_else(|| { | ||||
|                     visibility_from_ast(db, field.visibility(), &mut |range| { | ||||
|                         col.span_map().span_for_range(range).ctx | ||||
|                     }) | ||||
|                 }); | ||||
|         } else { | ||||
|                 let is_unsafe = field | ||||
|                     .syntax() | ||||
|                     .children_with_tokens() | ||||
|                     .filter_map(NodeOrToken::into_token) | ||||
|                     .any(|token| token.kind() == T![unsafe]); | ||||
|                 let name = field_name(idx, &field); | ||||
|                 arena.alloc(FieldData { name, type_ref, visibility, is_unsafe }); | ||||
|                 idx += 1; | ||||
|             } | ||||
|             Err(cfg) => { | ||||
|                 col.source_map.diagnostics.push( | ||||
|                     crate::expr_store::ExpressionStoreDiagnostics::InactiveCode { | ||||
|                     node: InFile::new(fields.file_id, ptr), | ||||
|                     cfg: attrs.cfg().unwrap(), | ||||
|                         node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())), | ||||
|                         cfg, | ||||
|                         opts: cfg_options.clone(), | ||||
|                     }, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     let store = col.store.finish(); | ||||
|     arena.shrink_to_fit(); | ||||
|     (arena, store, col.source_map) | ||||
| } | ||||
| 
 | ||||
|  | @ -905,56 +881,71 @@ pub struct InactiveEnumVariantCode { | |||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct EnumVariants { | ||||
|     pub variants: Box<[(EnumVariantId, Name)]>, | ||||
|     pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>, | ||||
| } | ||||
| 
 | ||||
| #[salsa::tracked] | ||||
| impl EnumVariants { | ||||
|     pub(crate) fn enum_variants_query( | ||||
|     #[salsa::tracked(returns(ref))] | ||||
|     pub(crate) fn of( | ||||
|         db: &dyn DefDatabase, | ||||
|         e: EnumId, | ||||
|     ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) { | ||||
|     ) -> (EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) { | ||||
|         let loc = e.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         let source = loc.source(db); | ||||
|         let ast_id_map = db.ast_id_map(source.file_id); | ||||
|         let span_map = db.span_map(source.file_id); | ||||
| 
 | ||||
|         let mut diagnostics = ThinVec::new(); | ||||
|         let cfg_options = loc.container.krate.cfg_options(db); | ||||
|         let mut index = 0; | ||||
|         let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone()) | ||||
|         let Some(variants) = source.value.variant_list() else { | ||||
|             return (EnumVariants { variants: Box::default() }, None); | ||||
|         }; | ||||
|         let variants = variants | ||||
|             .variants() | ||||
|             .filter_map(|variant| { | ||||
|                 let attrs = item_tree.attrs(db, loc.container.krate, variant.into()); | ||||
|                 if attrs.is_cfg_enabled(cfg_options) { | ||||
|                     let enum_variant = EnumVariantLoc { | ||||
|                         id: ItemTreeId::new(loc.id.tree_id(), variant), | ||||
|                         parent: e, | ||||
|                         index, | ||||
|                     } | ||||
|                 let ast_id = ast_id_map.ast_id(&variant); | ||||
|                 match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) { | ||||
|                     Ok(()) => { | ||||
|                         let enum_variant = | ||||
|                             EnumVariantLoc { id: source.with_value(ast_id), parent: e, index } | ||||
|                                 .intern(db); | ||||
|                         index += 1; | ||||
|                     Some((enum_variant, item_tree[variant].name.clone())) | ||||
|                 } else { | ||||
|                         let name = as_name_opt(variant.name()); | ||||
|                         let shape = adt_shape(variant.kind()); | ||||
|                         Some((enum_variant, name, shape)) | ||||
|                     } | ||||
|                     Err(cfg) => { | ||||
|                         diagnostics.push(InactiveEnumVariantCode { | ||||
|                         ast_id: item_tree[variant].ast_id, | ||||
|                         cfg: attrs.cfg().unwrap(), | ||||
|                             ast_id, | ||||
|                             cfg, | ||||
|                             opts: cfg_options.clone(), | ||||
|                         }); | ||||
|                         None | ||||
|                     } | ||||
|                 } | ||||
|             }) | ||||
|             .collect(); | ||||
| 
 | ||||
|         ( | ||||
|             Arc::new(EnumVariants { variants }), | ||||
|             diagnostics.is_empty().not().then(|| Arc::new(diagnostics)), | ||||
|         ) | ||||
|         (EnumVariants { variants }, diagnostics.is_empty().not().then_some(diagnostics)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl EnumVariants { | ||||
|     pub fn variant(&self, name: &Name) -> Option<EnumVariantId> { | ||||
|         self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None }) | ||||
|         self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option<Name> { | ||||
|         self.variants | ||||
|             .iter() | ||||
|             .find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None }) | ||||
|     } | ||||
| 
 | ||||
|     // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
 | ||||
|     pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { | ||||
|         self.variants.iter().all(|&(v, _)| { | ||||
|         self.variants.iter().all(|&(v, _, _)| { | ||||
|             // The condition check order is slightly modified from rustc
 | ||||
|             // to improve performance by early returning with relatively fast checks
 | ||||
|             let variant = &db.variant_fields(v.into()); | ||||
|  | @ -973,3 +964,17 @@ impl EnumVariants { | |||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn extern_block_abi( | ||||
|     db: &dyn DefDatabase, | ||||
|     extern_block: ExternBlockId, | ||||
| ) -> Option<Symbol> { | ||||
|     let source = extern_block.lookup(db).source(db); | ||||
|     source.value.abi().map(|abi| { | ||||
|         match abi.abi_string() { | ||||
|             Some(tok) => Symbol::intern(tok.text_without_quotes()), | ||||
|             // `extern` default to be `extern "C"`.
 | ||||
|             _ => sym::C, | ||||
|         } | ||||
|     }) | ||||
| } | ||||
|  |  | |||
|  | @ -1,15 +1,13 @@ | |||
| //! Utilities for mapping between hir IDs and the surface syntax.
 | ||||
| 
 | ||||
| use either::Either; | ||||
| use hir_expand::InFile; | ||||
| use la_arena::ArenaMap; | ||||
| use hir_expand::{AstId, InFile}; | ||||
| use la_arena::{Arena, ArenaMap, Idx}; | ||||
| use syntax::{AstNode, AstPtr, ast}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, | ||||
|     UseId, VariantId, | ||||
|     db::DefDatabase, | ||||
|     item_tree::{AttrOwner, FieldParent, ItemTreeNode}, | ||||
|     AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, | ||||
|     UseId, VariantId, attr::Attrs, db::DefDatabase, | ||||
| }; | ||||
| 
 | ||||
| pub trait HasSource { | ||||
|  | @ -23,18 +21,13 @@ pub trait HasSource { | |||
| 
 | ||||
| impl<T> HasSource for T | ||||
| where | ||||
|     T: ItemTreeLoc, | ||||
|     T::Id: ItemTreeNode, | ||||
|     T: AstIdLoc, | ||||
| { | ||||
|     type Value = <T::Id as ItemTreeNode>::Source; | ||||
|     type Value = T::Ast; | ||||
|     fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile<AstPtr<Self::Value>> { | ||||
|         let id = self.item_tree_id(); | ||||
|         let file_id = id.file_id(); | ||||
|         let tree = id.item_tree(db); | ||||
|         let ast_id_map = db.ast_id_map(file_id); | ||||
|         let node = &tree[id.value]; | ||||
| 
 | ||||
|         InFile::new(file_id, ast_id_map.get(node.ast_id())) | ||||
|         let id = self.ast_id(); | ||||
|         let ast_id_map = db.ast_id_map(id.file_id); | ||||
|         InFile::new(id.file_id, ast_id_map.get(id.value)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -43,18 +36,37 @@ pub trait HasChildSource<ChildId> { | |||
|     fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>; | ||||
| } | ||||
| 
 | ||||
| /// Maps a `UseTree` contained in this import back to its AST node.
 | ||||
| pub fn use_tree_to_ast( | ||||
|     db: &dyn DefDatabase, | ||||
|     use_ast_id: AstId<ast::Use>, | ||||
|     index: Idx<ast::UseTree>, | ||||
| ) -> ast::UseTree { | ||||
|     use_tree_source_map(db, use_ast_id)[index].clone() | ||||
| } | ||||
| 
 | ||||
| /// Maps a `UseTree` contained in this import back to its AST node.
 | ||||
| fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId<ast::Use>) -> Arena<ast::UseTree> { | ||||
|     // Re-lower the AST item and get the source map.
 | ||||
|     // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
 | ||||
|     let ast = use_ast_id.to_node(db); | ||||
|     let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); | ||||
|     let mut span_map = None; | ||||
|     crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| { | ||||
|         span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx | ||||
|     }) | ||||
|     .expect("failed to lower use tree") | ||||
|     .1 | ||||
| } | ||||
| 
 | ||||
| impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId { | ||||
|     type Value = ast::UseTree; | ||||
|     fn child_source( | ||||
|         &self, | ||||
|         db: &dyn DefDatabase, | ||||
|     ) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> { | ||||
|         let loc = &self.lookup(db); | ||||
|         let use_ = &loc.id.item_tree(db)[loc.id.value]; | ||||
|         InFile::new( | ||||
|             loc.id.file_id(), | ||||
|             use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(), | ||||
|         ) | ||||
|         let loc = self.lookup(db); | ||||
|         InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -124,49 +136,30 @@ impl HasChildSource<LocalFieldId> for VariantId { | |||
|     type Value = Either<ast::TupleField, ast::RecordField>; | ||||
| 
 | ||||
|     fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> { | ||||
|         let item_tree; | ||||
|         let (src, parent, container) = match *self { | ||||
|         let (src, container) = match *self { | ||||
|             VariantId::EnumVariantId(it) => { | ||||
|                 let lookup = it.lookup(db); | ||||
|                 item_tree = lookup.id.item_tree(db); | ||||
|                 ( | ||||
|                     lookup.source(db).map(|it| it.kind()), | ||||
|                     FieldParent::EnumVariant(lookup.id.value), | ||||
|                     lookup.parent.lookup(db).container, | ||||
|                 ) | ||||
|                 (lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container) | ||||
|             } | ||||
|             VariantId::StructId(it) => { | ||||
|                 let lookup = it.lookup(db); | ||||
|                 item_tree = lookup.id.item_tree(db); | ||||
|                 ( | ||||
|                     lookup.source(db).map(|it| it.kind()), | ||||
|                     FieldParent::Struct(lookup.id.value), | ||||
|                     lookup.container, | ||||
|                 ) | ||||
|                 (lookup.source(db).map(|it| it.kind()), lookup.container) | ||||
|             } | ||||
|             VariantId::UnionId(it) => { | ||||
|                 let lookup = it.lookup(db); | ||||
|                 item_tree = lookup.id.item_tree(db); | ||||
|                 ( | ||||
|                     lookup.source(db).map(|it| it.kind()), | ||||
|                     FieldParent::Union(lookup.id.value), | ||||
|                     lookup.container, | ||||
|                 ) | ||||
|                 (lookup.source(db).map(|it| it.kind()), lookup.container) | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         let span_map = db.span_map(src.file_id); | ||||
|         let mut map = ArenaMap::new(); | ||||
|         match &src.value { | ||||
|             ast::StructKind::Tuple(fl) => { | ||||
|                 let cfg_options = container.krate.cfg_options(db); | ||||
|                 let mut idx = 0; | ||||
|                 for (i, fd) in fl.fields().enumerate() { | ||||
|                     let attrs = item_tree.attrs( | ||||
|                         db, | ||||
|                         container.krate, | ||||
|                         AttrOwner::make_field_indexed(parent, i), | ||||
|                     ); | ||||
|                     if !attrs.is_cfg_enabled(cfg_options) { | ||||
|                 for fd in fl.fields() { | ||||
|                     let enabled = | ||||
|                         Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); | ||||
|                     if !enabled { | ||||
|                         continue; | ||||
|                     } | ||||
|                     map.insert( | ||||
|  | @ -179,13 +172,10 @@ impl HasChildSource<LocalFieldId> for VariantId { | |||
|             ast::StructKind::Record(fl) => { | ||||
|                 let cfg_options = container.krate.cfg_options(db); | ||||
|                 let mut idx = 0; | ||||
|                 for (i, fd) in fl.fields().enumerate() { | ||||
|                     let attrs = item_tree.attrs( | ||||
|                         db, | ||||
|                         container.krate, | ||||
|                         AttrOwner::make_field_indexed(parent, i), | ||||
|                     ); | ||||
|                     if !attrs.is_cfg_enabled(cfg_options) { | ||||
|                 for fd in fl.fields() { | ||||
|                     let enabled = | ||||
|                         Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); | ||||
|                     if !enabled { | ||||
|                         continue; | ||||
|                     } | ||||
|                     map.insert( | ||||
|  | @ -195,7 +185,7 @@ impl HasChildSource<LocalFieldId> for VariantId { | |||
|                     idx += 1; | ||||
|                 } | ||||
|             } | ||||
|             _ => (), | ||||
|             ast::StructKind::Unit => (), | ||||
|         } | ||||
|         InFile::new(src.file_id, map) | ||||
|     } | ||||
|  |  | |||
|  | @ -2,16 +2,15 @@ | |||
| 
 | ||||
| use std::iter; | ||||
| 
 | ||||
| use hir_expand::Lookup; | ||||
| use base_db::Crate; | ||||
| use hir_expand::{InFile, Lookup}; | ||||
| use la_arena::ArenaMap; | ||||
| use syntax::ast::{self, HasVisibility}; | ||||
| use triomphe::Arc; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId, | ||||
|     LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId, | ||||
|     db::DefDatabase, | ||||
|     nameres::DefMap, | ||||
|     resolver::{HasResolver, Resolver}, | ||||
|     AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId, | ||||
|     VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, | ||||
| }; | ||||
| 
 | ||||
| pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; | ||||
|  | @ -21,6 +20,8 @@ pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; | |||
| pub enum Visibility { | ||||
|     /// Visibility is restricted to a certain module.
 | ||||
|     Module(ModuleId, VisibilityExplicitness), | ||||
|     /// Visibility is restricted to the crate.
 | ||||
|     PubCrate(Crate), | ||||
|     /// Visibility is unrestricted.
 | ||||
|     Public, | ||||
| } | ||||
|  | @ -43,8 +44,13 @@ impl Visibility { | |||
|     pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { | ||||
|         let to_module = match self { | ||||
|             Visibility::Module(m, _) => m, | ||||
|             Visibility::PubCrate(krate) => return from_module.krate == krate, | ||||
|             Visibility::Public => return true, | ||||
|         }; | ||||
|         if from_module == to_module { | ||||
|             // if the modules are the same, visibility is trivially satisfied
 | ||||
|             return true; | ||||
|         } | ||||
|         // if they're not in the same crate, it can't be visible
 | ||||
|         if from_module.krate != to_module.krate { | ||||
|             return false; | ||||
|  | @ -61,12 +67,18 @@ impl Visibility { | |||
|     ) -> bool { | ||||
|         let to_module = match self { | ||||
|             Visibility::Module(m, _) => m, | ||||
|             Visibility::PubCrate(krate) => return def_map.krate() == krate, | ||||
|             Visibility::Public => return true, | ||||
|         }; | ||||
|         // if they're not in the same crate, it can't be visible
 | ||||
|         if def_map.krate() != to_module.krate { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if from_module == to_module.local_id && def_map.block_id() == to_module.block { | ||||
|             // if the modules are the same, visibility is trivially satisfied
 | ||||
|             return true; | ||||
|         } | ||||
|         Self::is_visible_from_def_map_(db, def_map, to_module, from_module) | ||||
|     } | ||||
| 
 | ||||
|  | @ -90,9 +102,7 @@ impl Visibility { | |||
|                 // `to_module` is not a block, so there is no parent def map to use.
 | ||||
|                 (None, _) => (), | ||||
|                 // `to_module` is at `def_map`'s block, no need to move further.
 | ||||
|                 (Some(a), Some(b)) if a == b => { | ||||
|                     cov_mark::hit!(is_visible_from_same_block_def_map); | ||||
|                 } | ||||
|                 (Some(a), Some(b)) if a == b => {} | ||||
|                 _ => { | ||||
|                     if let Some(parent) = to_module.def_map(db).parent() { | ||||
|                         to_module = parent; | ||||
|  | @ -134,26 +144,56 @@ impl Visibility { | |||
|     pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { | ||||
|         match (self, other) { | ||||
|             (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public), | ||||
|             (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { | ||||
|                 if krate == krateb { | ||||
|                     Some(Visibility::PubCrate(krate)) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             (Visibility::Module(mod_, _), Visibility::PubCrate(krate)) | ||||
|             | (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => { | ||||
|                 if mod_.krate == krate { | ||||
|                     Some(Visibility::PubCrate(krate)) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { | ||||
|                 if mod_a.krate != mod_b.krate { | ||||
|                 if mod_a == mod_b { | ||||
|                     // Most module visibilities are `pub(self)`, and assuming no errors
 | ||||
|                     // this will be the common and thus fast path.
 | ||||
|                     return Some(Visibility::Module( | ||||
|                         mod_a, | ||||
|                         match (expl_a, expl_b) { | ||||
|                             (VisibilityExplicitness::Explicit, _) | ||||
|                             | (_, VisibilityExplicitness::Explicit) => { | ||||
|                                 VisibilityExplicitness::Explicit | ||||
|                             } | ||||
|                             _ => VisibilityExplicitness::Implicit, | ||||
|                         }, | ||||
|                     )); | ||||
|                 } | ||||
| 
 | ||||
|                 if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { | ||||
|                     return None; | ||||
|                 } | ||||
| 
 | ||||
|                 let def_block = def_map.block_id(); | ||||
|                 if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { | ||||
|                 if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { | ||||
|                     return None; | ||||
|                 } | ||||
| 
 | ||||
|                 let mut a_ancestors = | ||||
|                     iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); | ||||
|                 let mut b_ancestors = | ||||
|                     iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); | ||||
| 
 | ||||
|                 if a_ancestors.any(|m| m == mod_b.local_id) { | ||||
|                     // B is above A
 | ||||
|                     return Some(Visibility::Module(mod_b, expl_b)); | ||||
|                 } | ||||
| 
 | ||||
|                 let mut b_ancestors = | ||||
|                     iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); | ||||
|                 if b_ancestors.any(|m| m == mod_a.local_id) { | ||||
|                     // A is above B
 | ||||
|                     return Some(Visibility::Module(mod_a, expl_a)); | ||||
|  | @ -171,26 +211,52 @@ impl Visibility { | |||
|     pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { | ||||
|         match (self, other) { | ||||
|             (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis), | ||||
|             (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { | ||||
|                 if krate == krateb { | ||||
|                     Some(Visibility::PubCrate(krate)) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             (Visibility::Module(mod_, exp), Visibility::PubCrate(krate)) | ||||
|             | (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => { | ||||
|                 if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None } | ||||
|             } | ||||
|             (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { | ||||
|                 if mod_a.krate != mod_b.krate { | ||||
|                 if mod_a == mod_b { | ||||
|                     // Most module visibilities are `pub(self)`, and assuming no errors
 | ||||
|                     // this will be the common and thus fast path.
 | ||||
|                     return Some(Visibility::Module( | ||||
|                         mod_a, | ||||
|                         match (expl_a, expl_b) { | ||||
|                             (VisibilityExplicitness::Explicit, _) | ||||
|                             | (_, VisibilityExplicitness::Explicit) => { | ||||
|                                 VisibilityExplicitness::Explicit | ||||
|                             } | ||||
|                             _ => VisibilityExplicitness::Implicit, | ||||
|                         }, | ||||
|                     )); | ||||
|                 } | ||||
| 
 | ||||
|                 if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { | ||||
|                     return None; | ||||
|                 } | ||||
| 
 | ||||
|                 let def_block = def_map.block_id(); | ||||
|                 if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { | ||||
|                 if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { | ||||
|                     return None; | ||||
|                 } | ||||
| 
 | ||||
|                 let mut a_ancestors = | ||||
|                     iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); | ||||
|                 let mut b_ancestors = | ||||
|                     iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); | ||||
| 
 | ||||
|                 if a_ancestors.any(|m| m == mod_b.local_id) { | ||||
|                     // B is above A
 | ||||
|                     return Some(Visibility::Module(mod_a, expl_a)); | ||||
|                 } | ||||
| 
 | ||||
|                 let mut b_ancestors = | ||||
|                     iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); | ||||
|                 if b_ancestors.any(|m| m == mod_a.local_id) { | ||||
|                     // A is above B
 | ||||
|                     return Some(Visibility::Module(mod_b, expl_b)); | ||||
|  | @ -217,49 +283,62 @@ pub(crate) fn field_visibilities_query( | |||
|     for (field_id, field_data) in fields.iter() { | ||||
|         res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); | ||||
|     } | ||||
|     res.shrink_to_fit(); | ||||
|     Arc::new(res) | ||||
| } | ||||
| 
 | ||||
| /// Resolve visibility of a function.
 | ||||
| pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { | ||||
|     let resolver = def.resolver(db); | ||||
|     let loc = def.lookup(db); | ||||
|     let tree = loc.item_tree_id().item_tree(db); | ||||
|     if let ItemContainerId::TraitId(trait_id) = loc.container { | ||||
|         trait_vis(db, &resolver, trait_id) | ||||
|     } else { | ||||
|         Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) | ||||
|     } | ||||
| pub fn visibility_from_ast( | ||||
|     db: &dyn DefDatabase, | ||||
|     has_resolver: impl HasResolver, | ||||
|     ast_vis: InFile<Option<ast::Visibility>>, | ||||
| ) -> Visibility { | ||||
|     let mut span_map = None; | ||||
|     let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| { | ||||
|         span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx | ||||
|     }); | ||||
|     if raw_vis == RawVisibility::Public { | ||||
|         return Visibility::Public; | ||||
|     } | ||||
| 
 | ||||
| /// Resolve visibility of a const.
 | ||||
| pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility { | ||||
|     let resolver = def.resolver(db); | ||||
|     let loc = def.lookup(db); | ||||
|     let tree = loc.item_tree_id().item_tree(db); | ||||
|     if let ItemContainerId::TraitId(trait_id) = loc.container { | ||||
|         trait_vis(db, &resolver, trait_id) | ||||
|     } else { | ||||
|         Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) | ||||
|     } | ||||
|     Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis) | ||||
| } | ||||
| 
 | ||||
| /// Resolve visibility of a type alias.
 | ||||
| pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility { | ||||
|     let resolver = def.resolver(db); | ||||
|     let loc = def.lookup(db); | ||||
|     let tree = loc.item_tree_id().item_tree(db); | ||||
|     if let ItemContainerId::TraitId(trait_id) = loc.container { | ||||
|         trait_vis(db, &resolver, trait_id) | ||||
|     } else { | ||||
|         Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) | ||||
| pub(crate) fn assoc_visibility_query(db: &dyn DefDatabase, def: AssocItemId) -> Visibility { | ||||
|     match def { | ||||
|         AssocItemId::FunctionId(function_id) => { | ||||
|             let loc = function_id.lookup(db); | ||||
|             trait_item_visibility(db, loc.container).unwrap_or_else(|| { | ||||
|                 let source = loc.source(db); | ||||
|                 visibility_from_ast(db, function_id, source.map(|src| src.visibility())) | ||||
|             }) | ||||
|         } | ||||
|         AssocItemId::ConstId(const_id) => { | ||||
|             let loc = const_id.lookup(db); | ||||
|             trait_item_visibility(db, loc.container).unwrap_or_else(|| { | ||||
|                 let source = loc.source(db); | ||||
|                 visibility_from_ast(db, const_id, source.map(|src| src.visibility())) | ||||
|             }) | ||||
|         } | ||||
|         AssocItemId::TypeAliasId(type_alias_id) => { | ||||
|             let loc = type_alias_id.lookup(db); | ||||
|             trait_item_visibility(db, loc.container).unwrap_or_else(|| { | ||||
|                 let source = loc.source(db); | ||||
|                 visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility())) | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[inline] | ||||
| fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility { | ||||
|     let ItemLoc { id: tree_id, .. } = trait_id.lookup(db); | ||||
|     let item_tree = tree_id.item_tree(db); | ||||
|     let tr_def = &item_tree[tree_id.value]; | ||||
|     Visibility::resolve(db, resolver, &item_tree[tr_def.visibility]) | ||||
| fn trait_item_visibility(db: &dyn DefDatabase, container: ItemContainerId) -> Option<Visibility> { | ||||
|     match container { | ||||
|         ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, trait_)), | ||||
|         _ => None, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn trait_visibility(db: &dyn DefDatabase, def: TraitId) -> Visibility { | ||||
|     let loc = def.lookup(db); | ||||
|     let source = loc.source(db); | ||||
|     visibility_from_ast(db, def, source.map(|src| src.visibility())) | ||||
| } | ||||
|  |  | |||
|  | @ -277,8 +277,8 @@ mod tests { | |||
|         assert_eq!(quoted.to_string(), "hello"); | ||||
|         let t = format!("{quoted:#?}"); | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 937550:0@0..0#ROOT2024 937550:0@0..0#ROOT2024 | ||||
|               IDENT   hello 937550:0@0..0#ROOT2024"#]]
 | ||||
|             SUBTREE $$ 937550:Root[0000, 0]@0..0#ROOT2024 937550:Root[0000, 0]@0..0#ROOT2024 | ||||
|               IDENT   hello 937550:Root[0000, 0]@0..0#ROOT2024"#]]
 | ||||
|         .assert_eq(&t); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ use crate::{ | |||
|     AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, | ||||
|     EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId, | ||||
|     MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, | ||||
|     attrs::{AttrId, collect_attrs}, | ||||
|     attrs::{AttrId, AttrInput, RawAttrs, collect_attrs}, | ||||
|     builtin::pseudo_derive_attr_expansion, | ||||
|     cfg_process, | ||||
|     declarative::DeclarativeMacroExpander, | ||||
|  | @ -60,6 +60,7 @@ pub trait ExpandDatabase: RootQueryDb { | |||
|     fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>; | ||||
| 
 | ||||
|     #[salsa::invoke(ast_id_map)] | ||||
|     #[salsa::lru(1024)] | ||||
|     fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; | ||||
| 
 | ||||
|     #[salsa::transparent] | ||||
|  | @ -241,19 +242,10 @@ pub fn expand_speculative( | |||
| 
 | ||||
|     let attr_arg = match loc.kind { | ||||
|         MacroCallKind::Attr { invoc_attr_index, .. } => { | ||||
|             let attr = if loc.def.is_attribute_derive() { | ||||
|             if loc.def.is_attribute_derive() { | ||||
|                 // for pseudo-derive expansion we actually pass the attribute itself only
 | ||||
|                 ast::Attr::cast(speculative_args.clone()) | ||||
|             } else { | ||||
|                 // Attributes may have an input token tree, build the subtree and map for this as well
 | ||||
|                 // then try finding a token id for our token if it is inside this input subtree.
 | ||||
|                 let item = ast::Item::cast(speculative_args.clone())?; | ||||
|                 collect_attrs(&item) | ||||
|                     .nth(invoc_attr_index.ast_index()) | ||||
|                     .and_then(|x| Either::left(x.1)) | ||||
|             }?; | ||||
|             match attr.token_tree() { | ||||
|                 Some(token_tree) => { | ||||
|                 ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map( | ||||
|                     |token_tree| { | ||||
|                         let mut tree = syntax_node_to_token_tree( | ||||
|                             token_tree.syntax(), | ||||
|                             span_map, | ||||
|  | @ -261,10 +253,25 @@ pub fn expand_speculative( | |||
|                             DocCommentDesugarMode::ProcMacro, | ||||
|                         ); | ||||
|                         *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span); | ||||
| 
 | ||||
|                     Some(tree) | ||||
|                         tree | ||||
|                     }, | ||||
|                 ) | ||||
|             } else { | ||||
|                 // Attributes may have an input token tree, build the subtree and map for this as well
 | ||||
|                 // then try finding a token id for our token if it is inside this input subtree.
 | ||||
|                 let item = ast::Item::cast(speculative_args.clone())?; | ||||
|                 let attrs = RawAttrs::new_expanded(db, &item, span_map, loc.krate.cfg_options(db)); | ||||
|                 attrs.iter().find(|attr| attr.id == invoc_attr_index).and_then(|attr| { | ||||
|                     match attr.input.as_deref()? { | ||||
|                         AttrInput::TokenTree(tt) => { | ||||
|                             let mut attr_arg = tt.clone(); | ||||
|                             attr_arg.top_subtree_delimiter_mut().kind = | ||||
|                                 tt::DelimiterKind::Invisible; | ||||
|                             Some(attr_arg) | ||||
|                         } | ||||
|                 _ => None, | ||||
|                         AttrInput::Literal(_) => None, | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
|         _ => None, | ||||
|  |  | |||
|  | @ -106,7 +106,7 @@ impl FileRange { | |||
| /// It is stable across reparses, and can be used as salsa key/value.
 | ||||
| pub type AstId<N> = crate::InFile<FileAstId<N>>; | ||||
| 
 | ||||
| impl<N: AstIdNode> AstId<N> { | ||||
| impl<N: AstNode> AstId<N> { | ||||
|     pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { | ||||
|         self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)) | ||||
|     } | ||||
|  | @ -122,6 +122,13 @@ impl<N: AstIdNode> AstId<N> { | |||
|     pub fn erase(&self) -> ErasedAstId { | ||||
|         crate::InFile::new(self.file_id, self.value.erase()) | ||||
|     } | ||||
|     #[inline] | ||||
|     pub fn upcast<M: AstIdNode>(self) -> AstId<M> | ||||
|     where | ||||
|         N: Into<M>, | ||||
|     { | ||||
|         self.map(|it| it.upcast()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub type ErasedAstId = crate::InFile<ErasedFileAstId>; | ||||
|  |  | |||
|  | @ -34,9 +34,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { | |||
|         current_dir: String, | ||||
|     ) -> Result<tt::TopSubtree, ProcMacroExpansionError>; | ||||
| 
 | ||||
|     fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { | ||||
|         other.type_id() == self.type_id() | ||||
|     } | ||||
|     fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool; | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for dyn ProcMacroExpander { | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ la-arena.workspace = true | |||
| triomphe.workspace = true | ||||
| typed-arena = "2.0.2" | ||||
| indexmap.workspace = true | ||||
| rustc_apfloat = "0.2.2" | ||||
| rustc_apfloat = "0.2.3" | ||||
| query-group.workspace = true | ||||
| salsa.workspace = true | ||||
| salsa-macros.workspace = true | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { | |||
|     ) -> Option<rust_ir::AssociatedTyValueId<Interner>> { | ||||
|         let alias_id = from_assoc_type_id(assoc_type_id); | ||||
|         let trait_sig = self.db.type_alias_signature(alias_id); | ||||
|         self.db.impl_items(hir_def::ImplId::from_chalk(self.db, impl_id)).items.iter().find_map( | ||||
|         hir_def::ImplId::from_chalk(self.db, impl_id).impl_items(self.db).items.iter().find_map( | ||||
|             |(name, item)| match item { | ||||
|                 AssocItemId::TypeAliasId(alias) if &trait_sig.name == name => { | ||||
|                     Some(TypeAliasAsValue(*alias).to_chalk(self.db)) | ||||
|  | @ -261,10 +261,20 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { | |||
|         &self, | ||||
|         well_known_trait: WellKnownTrait, | ||||
|     ) -> Option<chalk_ir::TraitId<Interner>> { | ||||
|         let lang_attr = lang_item_from_well_known_trait(well_known_trait); | ||||
|         let trait_ = lang_attr.resolve_trait(self.db, self.krate)?; | ||||
|         let lang_item = lang_item_from_well_known_trait(well_known_trait); | ||||
|         let trait_ = lang_item.resolve_trait(self.db, self.krate)?; | ||||
|         Some(to_chalk_trait_id(trait_)) | ||||
|     } | ||||
|     fn well_known_assoc_type_id( | ||||
|         &self, | ||||
|         assoc_type: rust_ir::WellKnownAssocType, | ||||
|     ) -> Option<chalk_ir::AssocTypeId<Interner>> { | ||||
|         let lang_item = match assoc_type { | ||||
|             rust_ir::WellKnownAssocType::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, | ||||
|         }; | ||||
|         let alias = lang_item.resolve_type_alias(self.db, self.krate)?; | ||||
|         Some(to_assoc_type_id(alias)) | ||||
|     } | ||||
| 
 | ||||
|     fn program_clauses_for_env( | ||||
|         &self, | ||||
|  | @ -813,11 +823,11 @@ pub(crate) fn adt_datum_query( | |||
|             (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())]) | ||||
|         } | ||||
|         hir_def::AdtId::EnumId(id) => { | ||||
|             let variants = db | ||||
|                 .enum_variants(id) | ||||
|             let variants = id | ||||
|                 .enum_variants(db) | ||||
|                 .variants | ||||
|                 .iter() | ||||
|                 .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into())) | ||||
|                 .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) | ||||
|                 .collect(); | ||||
|             (rust_ir::AdtKind::Enum, variants) | ||||
|         } | ||||
|  | @ -870,8 +880,8 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) | |||
| 
 | ||||
|     let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; | ||||
|     let trait_data = db.trait_items(trait_); | ||||
|     let associated_ty_value_ids = db | ||||
|         .impl_items(impl_id) | ||||
|     let associated_ty_value_ids = impl_id | ||||
|         .impl_items(db) | ||||
|         .items | ||||
|         .iter() | ||||
|         .filter_map(|(_, item)| match item { | ||||
|  |  | |||
|  | @ -16,7 +16,8 @@ use crate::{ | |||
|     ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, | ||||
|     QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, | ||||
|     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, | ||||
|     from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, | ||||
|     from_placeholder_idx, generics::generics, mapping::ToChalk, to_chalk_trait_id, | ||||
|     utils::ClosureSubst, | ||||
| }; | ||||
| 
 | ||||
| pub trait TyExt { | ||||
|  | @ -190,10 +191,9 @@ impl TyExt for Ty { | |||
|     fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { | ||||
|         match *self.kind(Interner) { | ||||
|             TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), | ||||
|             TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable( | ||||
|                 db, | ||||
|                 db.lookup_intern_callable_def(callable.into()), | ||||
|             )), | ||||
|             TyKind::FnDef(callable, ..) => { | ||||
|                 Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable))) | ||||
|             } | ||||
|             TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), | ||||
|             TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), | ||||
|             _ => None, | ||||
|  | @ -202,7 +202,7 @@ impl TyExt for Ty { | |||
| 
 | ||||
|     fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> { | ||||
|         match self.kind(Interner) { | ||||
|             &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())), | ||||
|             &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -286,7 +286,7 @@ pub(crate) fn const_eval_discriminant_variant( | |||
|         let value = match prev_idx { | ||||
|             Some(prev_idx) => { | ||||
|                 1 + db.const_eval_discriminant( | ||||
|                     db.enum_variants(loc.parent).variants[prev_idx as usize].0, | ||||
|                     loc.parent.enum_variants(db).variants[prev_idx as usize].0, | ||||
|                 )? | ||||
|             } | ||||
|             _ => 0, | ||||
|  |  | |||
|  | @ -112,16 +112,16 @@ fn size_of_val() { | |||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn min_align_of_val() { | ||||
| fn align_of_val() { | ||||
|     check_number( | ||||
|         r#" | ||||
|         //- minicore: coerce_unsized
 | ||||
|         #[rustc_intrinsic] | ||||
|         pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; | ||||
|         pub fn align_of_val<T: ?Sized>(_: *const T) -> usize; | ||||
| 
 | ||||
|         struct X(i32, u8); | ||||
| 
 | ||||
|         const GOAL: usize = min_align_of_val(&X(1, 2)); | ||||
|         const GOAL: usize = align_of_val(&X(1, 2)); | ||||
|         "#,
 | ||||
|         4, | ||||
|     ); | ||||
|  | @ -129,11 +129,11 @@ fn min_align_of_val() { | |||
|         r#" | ||||
|         //- minicore: coerce_unsized
 | ||||
|         #[rustc_intrinsic] | ||||
|         pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; | ||||
|         pub fn align_of_val<T: ?Sized>(_: *const T) -> usize; | ||||
| 
 | ||||
|         const GOAL: usize = { | ||||
|             let x: &[i32] = &[1, 2, 3]; | ||||
|             min_align_of_val(x) | ||||
|             align_of_val(x) | ||||
|         }; | ||||
|         "#,
 | ||||
|         4, | ||||
|  |  | |||
|  | @ -236,9 +236,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { | |||
|     fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc<TraitImpls>]>; | ||||
| 
 | ||||
|     // Interned IDs for Chalk integration
 | ||||
|     #[salsa::interned] | ||||
|     fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId; | ||||
| 
 | ||||
|     #[salsa::interned] | ||||
|     fn intern_type_or_const_param_id( | ||||
|         &self, | ||||
|  | @ -347,7 +344,3 @@ impl_intern_key!(InternedClosureId, InternedClosure); | |||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||||
| pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); | ||||
| impl_intern_key!(InternedCoroutineId, InternedCoroutine); | ||||
| 
 | ||||
| // This exists just for Chalk, because Chalk just has a single `FnDefId` where
 | ||||
| // we have different IDs for struct and enum variant constructors.
 | ||||
| impl_intern_key!(InternedCallableDefId, CallableDefId); | ||||
|  |  | |||
|  | @ -395,9 +395,9 @@ impl<'a> DeclValidator<'a> { | |||
| 
 | ||||
|     /// Check incorrect names for enum variants.
 | ||||
|     fn validate_enum_variants(&mut self, enum_id: EnumId) { | ||||
|         let data = self.db.enum_variants(enum_id); | ||||
|         let data = enum_id.enum_variants(self.db); | ||||
| 
 | ||||
|         for (variant_id, _) in data.variants.iter() { | ||||
|         for (variant_id, _, _) in data.variants.iter() { | ||||
|             self.validate_enum_variant_fields(*variant_id); | ||||
|         } | ||||
| 
 | ||||
|  | @ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> { | |||
|         let mut enum_variants_replacements = data | ||||
|             .variants | ||||
|             .iter() | ||||
|             .filter_map(|(_, name)| { | ||||
|             .filter_map(|(_, name, _)| { | ||||
|                 to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { | ||||
|                     Replacement { | ||||
|                         current_name: name.clone(), | ||||
|  |  | |||
|  | @ -642,7 +642,7 @@ fn missing_match_arms<'p>( | |||
|     } | ||||
| 
 | ||||
|     let non_empty_enum = match scrut_ty.as_adt() { | ||||
|         Some((AdtId::EnumId(e), _)) => !cx.db.enum_variants(e).variants.is_empty(), | ||||
|         Some((AdtId::EnumId(e), _)) => !e.enum_variants(cx.db).variants.is_empty(), | ||||
|         _ => false, | ||||
|     }; | ||||
|     let display_target = DisplayTarget::from_crate(cx.db, krate); | ||||
|  |  | |||
|  | @ -328,7 +328,7 @@ impl HirDisplay for Pat { | |||
|                             write!( | ||||
|                                 f, | ||||
|                                 "{}", | ||||
|                                 f.db.enum_variants(loc.parent).variants[loc.index as usize] | ||||
|                                 loc.parent.enum_variants(f.db).variants[loc.index as usize] | ||||
|                                     .1 | ||||
|                                     .display(f.db, f.edition()) | ||||
|                             )?; | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ impl EnumVariantContiguousIndex { | |||
|     } | ||||
| 
 | ||||
|     fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId { | ||||
|         db.enum_variants(eid).variants[self.0].0 | ||||
|         eid.enum_variants(db).variants[self.0].0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -458,14 +458,14 @@ impl PatCx for MatchCheckCtx<'_> { | |||
|             TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), | ||||
|             TyKind::Array(..) | TyKind::Slice(..) => unhandled(), | ||||
|             &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => { | ||||
|                 let enum_data = cx.db.enum_variants(enum_id); | ||||
|                 let enum_data = enum_id.enum_variants(cx.db); | ||||
|                 let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt); | ||||
| 
 | ||||
|                 if enum_data.variants.is_empty() && !is_declared_nonexhaustive { | ||||
|                     ConstructorSet::NoConstructors | ||||
|                 } else { | ||||
|                     let mut variants = IndexVec::with_capacity(enum_data.variants.len()); | ||||
|                     for &(variant, _) in enum_data.variants.iter() { | ||||
|                     for &(variant, _, _) in enum_data.variants.iter() { | ||||
|                         let is_uninhabited = is_enum_variant_uninhabited_from( | ||||
|                             cx.db, | ||||
|                             variant, | ||||
|  |  | |||
|  | @ -914,7 +914,7 @@ fn render_const_scalar( | |||
|                     write!( | ||||
|                         f, | ||||
|                         "{}", | ||||
|                         f.db.enum_variants(loc.parent).variants[loc.index as usize] | ||||
|                         loc.parent.enum_variants(f.db).variants[loc.index as usize] | ||||
|                             .1 | ||||
|                             .display(f.db, f.edition()) | ||||
|                     )?; | ||||
|  | @ -1208,7 +1208,7 @@ impl HirDisplay for Ty { | |||
|                         write!( | ||||
|                             f, | ||||
|                             "{}", | ||||
|                             db.enum_variants(loc.parent).variants[loc.index as usize] | ||||
|                             loc.parent.enum_variants(db).variants[loc.index as usize] | ||||
|                                 .1 | ||||
|                                 .display(db, f.edition()) | ||||
|                         )? | ||||
|  | @ -2082,6 +2082,7 @@ pub fn write_visibility( | |||
| ) -> Result<(), HirDisplayError> { | ||||
|     match vis { | ||||
|         Visibility::Public => write!(f, "pub "), | ||||
|         Visibility::PubCrate(_) => write!(f, "pub(crate) "), | ||||
|         Visibility::Module(vis_id, _) => { | ||||
|             let def_map = module_id.def_map(f.db); | ||||
|             let root_module_id = def_map.module_id(DefMap::ROOT); | ||||
|  |  | |||
|  | @ -67,11 +67,11 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm | |||
|                 } | ||||
|                 // Unions cannot have fields with destructors.
 | ||||
|                 AdtId::UnionId(_) => DropGlue::None, | ||||
|                 AdtId::EnumId(id) => db | ||||
|                     .enum_variants(id) | ||||
|                 AdtId::EnumId(id) => id | ||||
|                     .enum_variants(db) | ||||
|                     .variants | ||||
|                     .iter() | ||||
|                     .map(|&(variant, _)| { | ||||
|                     .map(|&(variant, _, _)| { | ||||
|                         db.field_types(variant.into()) | ||||
|                             .iter() | ||||
|                             .map(|(_, field_ty)| { | ||||
|  |  | |||
|  | @ -122,7 +122,7 @@ pub fn dyn_compatibility_of_trait_query( | |||
|     res | ||||
| } | ||||
| 
 | ||||
| fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { | ||||
| pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { | ||||
|     let krate = def.module(db).krate(); | ||||
|     let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else { | ||||
|         return false; | ||||
|  |  | |||
|  | @ -229,7 +229,7 @@ impl Generics { | |||
|     } | ||||
| 
 | ||||
|     /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
 | ||||
|     pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { | ||||
|     pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { | ||||
|         Substitution::from_iter( | ||||
|             Interner, | ||||
|             self.iter_id().map(|id| match id { | ||||
|  |  | |||
|  | @ -1673,7 +1673,7 @@ impl<'db> InferenceContext<'db> { | |||
|                     // If we can resolve to an enum variant, it takes priority over associated type
 | ||||
|                     // of the same name.
 | ||||
|                     if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { | ||||
|                         let enum_data = self.db.enum_variants(id); | ||||
|                         let enum_data = id.enum_variants(self.db); | ||||
|                         if let Some(variant) = enum_data.variant(current_segment.name) { | ||||
|                             return if remaining_segments.len() == 1 { | ||||
|                                 (ty, Some(variant.into())) | ||||
|  | @ -1792,7 +1792,7 @@ impl<'db> InferenceContext<'db> { | |||
|                 let segment = path.segments().last().unwrap(); | ||||
|                 // this could be an enum variant or associated type
 | ||||
|                 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||||
|                     let enum_data = self.db.enum_variants(enum_id); | ||||
|                     let enum_data = enum_id.enum_variants(self.db); | ||||
|                     if let Some(variant) = enum_data.variant(segment) { | ||||
|                         return (ty, Some(variant.into())); | ||||
|                     } | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ impl CastTy { | |||
|                 let (AdtId::EnumId(id), _) = t.as_adt()? else { | ||||
|                     return None; | ||||
|                 }; | ||||
|                 let enum_data = table.db.enum_variants(id); | ||||
|                 let enum_data = id.enum_variants(table.db); | ||||
|                 if enum_data.is_payload_free(table.db) { Some(Self::Int(Int::CEnum)) } else { None } | ||||
|             } | ||||
|             TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)), | ||||
|  |  | |||
|  | @ -1360,7 +1360,7 @@ impl InferenceContext<'_> { | |||
|                 if let Some(variant) = self.result.variant_resolution_for_pat(p) { | ||||
|                     let adt = variant.adt_id(self.db); | ||||
|                     let is_multivariant = match adt { | ||||
|                         hir_def::AdtId::EnumId(e) => self.db.enum_variants(e).variants.len() != 1, | ||||
|                         hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1, | ||||
|                         _ => false, | ||||
|                     }; | ||||
|                     if is_multivariant { | ||||
|  |  | |||
|  | @ -397,7 +397,7 @@ impl InferenceContext<'_> { | |||
|             Some((AdtId::EnumId(e), subst)) => (e, subst), | ||||
|             _ => return None, | ||||
|         }; | ||||
|         let enum_data = self.db.enum_variants(enum_id); | ||||
|         let enum_data = enum_id.enum_variants(self.db); | ||||
|         let variant = enum_data.variant(name)?; | ||||
|         self.write_variant_resolution(id, variant.into()); | ||||
|         Some((ValueNs::EnumVariantId(variant), subst.clone())) | ||||
|  |  | |||
|  | @ -113,9 +113,9 @@ impl UninhabitedFrom<'_> { | |||
|             AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED, | ||||
|             AdtId::StructId(s) => self.visit_variant(s.into(), subst), | ||||
|             AdtId::EnumId(e) => { | ||||
|                 let enum_data = self.db.enum_variants(e); | ||||
|                 let enum_data = e.enum_variants(self.db); | ||||
| 
 | ||||
|                 for &(variant, _) in enum_data.variants.iter() { | ||||
|                 for &(variant, _, _) in enum_data.variants.iter() { | ||||
|                     let variant_inhabitedness = self.visit_variant(variant.into(), subst); | ||||
|                     match variant_inhabitedness { | ||||
|                         Break(VisiblyUninhabited) => (), | ||||
|  |  | |||
|  | @ -56,11 +56,11 @@ pub fn layout_of_adt_query( | |||
|             (r, data.repr.unwrap_or_default(), false) | ||||
|         } | ||||
|         AdtId::EnumId(e) => { | ||||
|             let variants = db.enum_variants(e); | ||||
|             let variants = e.enum_variants(db); | ||||
|             let r = variants | ||||
|                 .variants | ||||
|                 .iter() | ||||
|                 .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) | ||||
|                 .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) | ||||
|                 .collect::<Result<SmallVec<_>, _>>()?; | ||||
|             (r, db.enum_signature(e).repr.unwrap_or_default(), false) | ||||
|         } | ||||
|  | @ -82,7 +82,7 @@ pub fn layout_of_adt_query( | |||
|             |min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)), | ||||
|             variants.iter_enumerated().filter_map(|(id, _)| { | ||||
|                 let AdtId::EnumId(e) = def else { return None }; | ||||
|                 let d = db.const_eval_discriminant(db.enum_variants(e).variants[id.0].0).ok()?; | ||||
|                 let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?; | ||||
|                 Some((id, d)) | ||||
|             }), | ||||
|             // FIXME: The current code for niche-filling relies on variant indices
 | ||||
|  |  | |||
|  | @ -98,7 +98,7 @@ pub use lower::{ | |||
|     ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*, | ||||
| }; | ||||
| pub use mapping::{ | ||||
|     from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, | ||||
|     ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, | ||||
|     lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, | ||||
|     to_foreign_def_id, to_placeholder_idx, | ||||
| }; | ||||
|  | @ -542,7 +542,7 @@ impl CallableSig { | |||
|     } | ||||
| 
 | ||||
|     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { | ||||
|         let callable_def = db.lookup_intern_callable_def(def.into()); | ||||
|         let callable_def = ToChalk::from_chalk(db, def); | ||||
|         let sig = db.callable_item_signature(callable_def); | ||||
|         sig.substitute(Interner, substs) | ||||
|     } | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ use crate::{ | |||
|     PlaceholderIndex, chalk_db, db::HirDatabase, | ||||
| }; | ||||
| 
 | ||||
| pub(crate) trait ToChalk { | ||||
| pub trait ToChalk { | ||||
|     type Chalk; | ||||
|     fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; | ||||
|     fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; | ||||
|  | @ -44,12 +44,12 @@ impl ToChalk for hir_def::ImplId { | |||
| impl ToChalk for CallableDefId { | ||||
|     type Chalk = FnDefId; | ||||
| 
 | ||||
|     fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||||
|         db.intern_callable_def(self).into() | ||||
|     fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId { | ||||
|         chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self)) | ||||
|     } | ||||
| 
 | ||||
|     fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { | ||||
|         db.lookup_intern_callable_def(fn_def_id.into()) | ||||
|         salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -70,18 +70,6 @@ impl ToChalk for TypeAliasAsValue { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<FnDefId> for crate::db::InternedCallableDefId { | ||||
|     fn from(fn_def_id: FnDefId) -> Self { | ||||
|         Self::from_id(fn_def_id.0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<crate::db::InternedCallableDefId> for FnDefId { | ||||
|     fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { | ||||
|         chalk_ir::FnDefId(callable_def_id.as_id()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId { | ||||
|     fn from(id: OpaqueTyId) -> Self { | ||||
|         FromId::from_id(id.0) | ||||
|  |  | |||
|  | @ -790,7 +790,7 @@ fn find_matching_impl( | |||
|     mut impls: impl Iterator<Item = ImplId>, | ||||
|     mut table: InferenceTable<'_>, | ||||
|     actual_trait_ref: TraitRef, | ||||
| ) -> Option<(Arc<ImplItems>, Substitution)> { | ||||
| ) -> Option<(&ImplItems, Substitution)> { | ||||
|     let db = table.db; | ||||
|     impls.find_map(|impl_| { | ||||
|         table.run_in_snapshot(|table| { | ||||
|  | @ -811,7 +811,7 @@ fn find_matching_impl( | |||
|             let goal = crate::Goal::all(Interner, wcs); | ||||
|             table.try_obligation(goal.clone())?; | ||||
|             table.register_obligation(goal); | ||||
|             Some((db.impl_items(impl_), table.resolve_completely(impl_substs))) | ||||
|             Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) | ||||
|         }) | ||||
|     }) | ||||
| } | ||||
|  | @ -875,7 +875,7 @@ fn is_inherent_impl_coherent( | |||
| 
 | ||||
|             _ => false, | ||||
|         }; | ||||
|         let items = db.impl_items(impl_id); | ||||
|         let items = impl_id.impl_items(db); | ||||
|         rustc_has_incoherent_inherent_impls | ||||
|             && !items.items.is_empty() | ||||
|             && items.items.iter().all(|&(_, assoc)| match assoc { | ||||
|  | @ -1462,7 +1462,7 @@ fn iterate_inherent_methods( | |||
|         callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, | ||||
|     ) -> ControlFlow<()> { | ||||
|         for &impl_id in impls.for_self_ty(self_ty) { | ||||
|             for &(ref item_name, item) in table.db.impl_items(impl_id).items.iter() { | ||||
|             for &(ref item_name, item) in impl_id.impl_items(table.db).items.iter() { | ||||
|                 let visible = match is_valid_impl_method_candidate( | ||||
|                     table, | ||||
|                     self_ty, | ||||
|  | @ -1550,7 +1550,7 @@ fn is_valid_impl_method_candidate( | |||
|             check_that!(name.is_none_or(|n| n == item_name)); | ||||
| 
 | ||||
|             if let Some(from_module) = visible_from_module { | ||||
|                 if !db.const_visibility(c).is_visible_from(db, from_module) { | ||||
|                 if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) { | ||||
|                     cov_mark::hit!(const_candidate_not_visible); | ||||
|                     return IsValidCandidate::NotVisible; | ||||
|                 } | ||||
|  | @ -1639,7 +1639,7 @@ fn is_valid_impl_fn_candidate( | |||
|     let data = db.function_signature(fn_id); | ||||
| 
 | ||||
|     if let Some(from_module) = visible_from_module { | ||||
|         if !db.function_visibility(fn_id).is_visible_from(db, from_module) { | ||||
|         if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) { | ||||
|             cov_mark::hit!(autoderef_candidate_not_visible); | ||||
|             return IsValidCandidate::NotVisible; | ||||
|         } | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ use triomphe::Arc; | |||
| 
 | ||||
| use crate::{ | ||||
|     CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner, | ||||
|     MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, | ||||
|     MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, | ||||
|     consteval::{ConstEvalError, intern_const_scalar, try_const_usize}, | ||||
|     db::{HirDatabase, InternedClosure}, | ||||
|     display::{ClosureStyle, DisplayTarget, HirDisplay}, | ||||
|  | @ -1631,7 +1631,7 @@ impl Evaluator<'_> { | |||
|             Variants::Empty => unreachable!(), | ||||
|             Variants::Single { index } => { | ||||
|                 let r = | ||||
|                     self.const_eval_discriminant(self.db.enum_variants(e).variants[index.0].0)?; | ||||
|                     self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?; | ||||
|                 Ok(r) | ||||
|             } | ||||
|             Variants::Multiple { tag, tag_encoding, variants, .. } => { | ||||
|  | @ -1656,7 +1656,7 @@ impl Evaluator<'_> { | |||
|                             .unwrap_or(*untagged_variant) | ||||
|                             .0; | ||||
|                         let result = | ||||
|                             self.const_eval_discriminant(self.db.enum_variants(e).variants[idx].0)?; | ||||
|                             self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?; | ||||
|                         Ok(result) | ||||
|                     } | ||||
|                 } | ||||
|  | @ -2771,12 +2771,15 @@ impl Evaluator<'_> { | |||
|             Err(e) => { | ||||
|                 let db = self.db; | ||||
|                 let loc = variant.lookup(db); | ||||
|                 let enum_loc = loc.parent.lookup(db); | ||||
|                 let edition = self.crate_id.data(self.db).edition; | ||||
|                 let name = format!( | ||||
|                     "{}::{}", | ||||
|                     enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), | ||||
|                     loc.id.item_tree(db)[loc.id.value].name.display(db, edition), | ||||
|                     self.db.enum_signature(loc.parent).name.display(db, edition), | ||||
|                     loc.parent | ||||
|                         .enum_variants(self.db) | ||||
|                         .variant_name_by_id(variant) | ||||
|                         .unwrap() | ||||
|                         .display(db, edition), | ||||
|                 ); | ||||
|                 Err(MirEvalError::ConstEvalError(name, Box::new(e))) | ||||
|             } | ||||
|  | @ -2927,7 +2930,7 @@ pub fn render_const_using_debug_impl( | |||
|     let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?; | ||||
|     evaluator.write_memory(a2, &data.addr.to_bytes())?; | ||||
|     let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef( | ||||
|         db.intern_callable_def(debug_fmt_fn.into()).into(), | ||||
|         CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db), | ||||
|         Substitution::from1(Interner, c.data(Interner).ty.clone()), | ||||
|     ) | ||||
|     .intern(Interner)); | ||||
|  |  | |||
|  | @ -65,9 +65,7 @@ impl Evaluator<'_> { | |||
|                 Some(abi) => *abi == sym::rust_dash_intrinsic, | ||||
|                 None => match def.lookup(self.db).container { | ||||
|                     hir_def::ItemContainerId::ExternBlockId(block) => { | ||||
|                         let id = block.lookup(self.db).id; | ||||
|                         id.item_tree(self.db)[id.value].abi.as_ref() | ||||
|                             == Some(&sym::rust_dash_intrinsic) | ||||
|                         block.abi(self.db) == Some(sym::rust_dash_intrinsic) | ||||
|                     } | ||||
|                     _ => false, | ||||
|                 }, | ||||
|  | @ -86,10 +84,7 @@ impl Evaluator<'_> { | |||
|             ); | ||||
|         } | ||||
|         let is_extern_c = match def.lookup(self.db).container { | ||||
|             hir_def::ItemContainerId::ExternBlockId(block) => { | ||||
|                 let id = block.lookup(self.db).id; | ||||
|                 id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C) | ||||
|             } | ||||
|             hir_def::ItemContainerId::ExternBlockId(block) => block.abi(self.db) == Some(sym::C), | ||||
|             _ => false, | ||||
|         }; | ||||
|         if is_extern_c { | ||||
|  | @ -764,7 +759,9 @@ impl Evaluator<'_> { | |||
|                 let size = self.size_of_sized(ty, locals, "size_of arg")?; | ||||
|                 destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) | ||||
|             } | ||||
|             "min_align_of" | "pref_align_of" => { | ||||
|             // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89
 | ||||
|             // (https://github.com/rust-lang/rust/pull/142410)
 | ||||
|             "min_align_of" | "align_of" => { | ||||
|                 let Some(ty) = | ||||
|                     generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) | ||||
|                 else { | ||||
|  | @ -796,17 +793,19 @@ impl Evaluator<'_> { | |||
|                     destination.write_from_bytes(self, &size.to_le_bytes()) | ||||
|                 } | ||||
|             } | ||||
|             "min_align_of_val" => { | ||||
|             // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89
 | ||||
|             // (https://github.com/rust-lang/rust/pull/142410)
 | ||||
|             "min_align_of_val" | "align_of_val" => { | ||||
|                 let Some(ty) = | ||||
|                     generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) | ||||
|                 else { | ||||
|                     return Err(MirEvalError::InternalError( | ||||
|                         "min_align_of_val generic arg is not provided".into(), | ||||
|                         "align_of_val generic arg is not provided".into(), | ||||
|                     )); | ||||
|                 }; | ||||
|                 let [arg] = args else { | ||||
|                     return Err(MirEvalError::InternalError( | ||||
|                         "min_align_of_val args are not provided".into(), | ||||
|                         "align_of_val args are not provided".into(), | ||||
|                     )); | ||||
|                 }; | ||||
|                 if let Some((_, align)) = self.size_align_of(ty, locals)? { | ||||
|  |  | |||
|  | @ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> { | |||
|                 let edition = self.edition(); | ||||
|                 let db = self.db; | ||||
|                 let loc = variant.lookup(db); | ||||
|                 let enum_loc = loc.parent.lookup(db); | ||||
|                 let name = format!( | ||||
|                     "{}::{}", | ||||
|                     enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), | ||||
|                     loc.id.item_tree(db)[loc.id.value].name.display(db, edition), | ||||
|                     self.db.enum_signature(loc.parent).name.display(db, edition), | ||||
|                     loc.parent | ||||
|                         .enum_variants(self.db) | ||||
|                         .variant_name_by_id(variant) | ||||
|                         .unwrap() | ||||
|                         .display(db, edition), | ||||
|                 ); | ||||
|                 Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) | ||||
|             } | ||||
|  | @ -2152,7 +2155,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi | |||
|             .to_string(), | ||||
|         DefWithBodyId::VariantId(it) => { | ||||
|             let loc = it.lookup(db); | ||||
|             db.enum_variants(loc.parent).variants[loc.index as usize] | ||||
|             loc.parent.enum_variants(db).variants[loc.index as usize] | ||||
|                 .1 | ||||
|                 .display(db, edition) | ||||
|                 .to_string() | ||||
|  |  | |||
|  | @ -297,10 +297,7 @@ impl MirLowerCtx<'_> { | |||
|         let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner); | ||||
|         let mut result: Place = self.temp(result_ref, current, span)?.into(); | ||||
|         let index_fn_op = Operand::const_zst( | ||||
|             TyKind::FnDef( | ||||
|                 self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(), | ||||
|                 index_fn.1, | ||||
|             ) | ||||
|             TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1) | ||||
|                 .intern(Interner), | ||||
|         ); | ||||
|         let Some(current) = self.lower_call( | ||||
|  | @ -357,7 +354,7 @@ impl MirLowerCtx<'_> { | |||
|             .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?; | ||||
|         let deref_fn_op = Operand::const_zst( | ||||
|             TyKind::FnDef( | ||||
|                 self.db.intern_callable_def(CallableDefId::FunctionId(deref_fn)).into(), | ||||
|                 CallableDefId::FunctionId(deref_fn).to_chalk(self.db), | ||||
|                 Substitution::from1(Interner, source_ty), | ||||
|             ) | ||||
|             .intern(Interner), | ||||
|  |  | |||
|  | @ -63,16 +63,16 @@ impl MirBody { | |||
|             } | ||||
|             hir_def::DefWithBodyId::VariantId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let enum_loc = loc.parent.lookup(db); | ||||
|                 let edition = this.display_target.edition; | ||||
|                 w!( | ||||
|                     this, | ||||
|                     "enum {}::{} = ", | ||||
|                     enum_loc.id.item_tree(db)[enum_loc.id.value] | ||||
|                         .name | ||||
|                         .display(db, this.display_target.edition), | ||||
|                     loc.id.item_tree(db)[loc.id.value] | ||||
|                         .name | ||||
|                         .display(db, this.display_target.edition), | ||||
|                     db.enum_signature(loc.parent).name.display(db, edition), | ||||
|                     loc.parent | ||||
|                         .enum_variants(db) | ||||
|                         .variant_name_by_id(id) | ||||
|                         .unwrap() | ||||
|                         .display(db, edition), | ||||
|                 ) | ||||
|             } | ||||
|         }); | ||||
|  | @ -336,7 +336,7 @@ impl<'a> MirPrettyCtx<'a> { | |||
|                             w!( | ||||
|                                 this, | ||||
|                                 " as {}).{}", | ||||
|                                 this.db.enum_variants(loc.parent).variants[loc.index as usize] | ||||
|                                 loc.parent.enum_variants(this.db).variants[loc.index as usize] | ||||
|                                     .1 | ||||
|                                     .display(this.db, this.display_target.edition), | ||||
|                                 name.display(this.db, this.display_target.edition) | ||||
|  |  | |||
|  | @ -437,7 +437,7 @@ pub(crate) fn visit_module( | |||
| ) { | ||||
|     visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); | ||||
|     for impl_id in crate_def_map[module_id].scope.impls() { | ||||
|         let impl_data = db.impl_items(impl_id); | ||||
|         let impl_data = impl_id.impl_items(db); | ||||
|         for &(_, item) in impl_data.items.iter() { | ||||
|             match item { | ||||
|                 AssocItemId::FunctionId(it) => { | ||||
|  | @ -479,7 +479,7 @@ pub(crate) fn visit_module( | |||
|                     visit_body(db, &body, cb); | ||||
|                 } | ||||
|                 ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { | ||||
|                     db.enum_variants(it).variants.iter().for_each(|&(it, _)| { | ||||
|                     it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| { | ||||
|                         let body = db.body(it.into()); | ||||
|                         cb(it.into()); | ||||
|                         visit_body(db, &body, cb); | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| use base_db::SourceDatabase; | ||||
| use hir_def::ModuleDefId; | ||||
| use expect_test::Expect; | ||||
| use hir_def::{DefWithBodyId, ModuleDefId}; | ||||
| use test_fixture::WithFixture; | ||||
| 
 | ||||
| use crate::{db::HirDatabase, test_db::TestDB}; | ||||
|  | @ -15,8 +16,9 @@ fn foo() -> i32 { | |||
|     $01 + 1 | ||||
| }",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |def| { | ||||
|  | @ -24,9 +26,31 @@ fn foo() -> i32 { | |||
|                     db.infer(it.into()); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("infer_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("infer_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "lang_item", | ||||
|                 "crate_lang_items", | ||||
|                 "lang_item", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| fn foo() -> i32 { | ||||
|  | @ -37,8 +61,9 @@ fn foo() -> i32 { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |def| { | ||||
|  | @ -46,9 +71,22 @@ fn foo() -> i32 { | |||
|                     db.infer(it.into()); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|         assert!(!format!("{events:?}").contains("infer_shim"), "{events:#?}") | ||||
|     } | ||||
|         }, | ||||
|         &[("infer_shim", 0)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -66,8 +104,9 @@ fn baz() -> i32 { | |||
|     1 + 1 | ||||
| }",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |def| { | ||||
|  | @ -75,9 +114,49 @@ fn baz() -> i32 { | |||
|                     db.infer(it.into()); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("infer_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("infer_shim", 3)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "lang_item", | ||||
|                 "crate_lang_items", | ||||
|                 "attrs_shim", | ||||
|                 "attrs_shim", | ||||
|                 "lang_item", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "expr_scopes_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| fn foo() -> f32 { | ||||
|  | @ -93,8 +172,9 @@ fn baz() -> i32 { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |def| { | ||||
|  | @ -102,9 +182,34 @@ fn baz() -> i32 { | |||
|                     db.infer(it.into()); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|         assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}") | ||||
|     } | ||||
|         }, | ||||
|         &[("infer_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|                 "attrs_shim", | ||||
|                 "attrs_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|                 "infer_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -121,14 +226,26 @@ fn bar() -> f32 { | |||
| } | ||||
| $0",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| fn foo() -> i32 { | ||||
|  | @ -146,24 +263,25 @@ pub struct NewStruct { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let actual = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
| 
 | ||||
|         let expected = vec![ | ||||
|             "parse_shim".to_owned(), | ||||
|             "ast_id_map_shim".to_owned(), | ||||
|             "file_item_tree_shim".to_owned(), | ||||
|             "real_span_map_shim".to_owned(), | ||||
|             "crate_local_def_map".to_owned(), | ||||
|             "trait_impls_in_crate_shim".to_owned(), | ||||
|         ]; | ||||
| 
 | ||||
|         assert_eq!(expected, actual); | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -180,14 +298,26 @@ fn bar() -> f32 { | |||
| } | ||||
| $0",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| fn foo() -> i32 { | ||||
|  | @ -206,24 +336,25 @@ pub enum SomeEnum { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let actual = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
| 
 | ||||
|         let expected = vec![ | ||||
|             "parse_shim".to_owned(), | ||||
|             "ast_id_map_shim".to_owned(), | ||||
|             "file_item_tree_shim".to_owned(), | ||||
|             "real_span_map_shim".to_owned(), | ||||
|             "crate_local_def_map".to_owned(), | ||||
|             "trait_impls_in_crate_shim".to_owned(), | ||||
|         ]; | ||||
| 
 | ||||
|         assert_eq!(expected, actual); | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -240,14 +371,26 @@ fn bar() -> f32 { | |||
| } | ||||
| $0",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| use std::collections::HashMap; | ||||
|  | @ -263,24 +406,25 @@ fn bar() -> f32 { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let actual = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
| 
 | ||||
|         let expected = vec![ | ||||
|             "parse_shim".to_owned(), | ||||
|             "ast_id_map_shim".to_owned(), | ||||
|             "file_item_tree_shim".to_owned(), | ||||
|             "real_span_map_shim".to_owned(), | ||||
|             "crate_local_def_map".to_owned(), | ||||
|             "trait_impls_in_crate_shim".to_owned(), | ||||
|         ]; | ||||
| 
 | ||||
|         assert_eq!(expected, actual); | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
|  | @ -301,14 +445,26 @@ pub struct SomeStruct { | |||
| } | ||||
| $0",
 | ||||
|     ); | ||||
|     { | ||||
|         let events = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }); | ||||
|         assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) | ||||
|     } | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|     let new_text = " | ||||
| fn foo() -> i32 { | ||||
|  | @ -332,30 +488,243 @@ impl SomeStruct { | |||
| 
 | ||||
|     db.set_file_text(pos.file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     { | ||||
|         let actual = db.log_executed(|| { | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(pos.file_id.file_id(&db)); | ||||
|             let _crate_def_map = module.def_map(&db); | ||||
|             db.trait_impls_in_crate(module.krate()); | ||||
|         }, | ||||
|         &[("trait_impls_in_crate_shim", 1)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|                 "attrs_shim", | ||||
|                 "impl_trait_with_diagnostics_shim", | ||||
|                 "impl_signature_shim", | ||||
|                 "impl_signature_with_source_map_shim", | ||||
|                 "impl_self_ty_with_diagnostics_shim", | ||||
|                 "struct_signature_shim", | ||||
|                 "struct_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "type_for_adt_tracked", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn add_struct_invalidates_trait_solve() { | ||||
|     let (mut db, file_id) = TestDB::with_single_file( | ||||
|         " | ||||
| //- /main.rs crate:main
 | ||||
| struct SomeStruct; | ||||
| 
 | ||||
| trait Trait<T> { | ||||
|     fn method(&self) -> T; | ||||
| } | ||||
| impl Trait<u32> for SomeStruct {} | ||||
| 
 | ||||
| fn main() { | ||||
|     let s = SomeStruct; | ||||
|     s.method(); | ||||
|     s.$0 | ||||
| }",
 | ||||
|     ); | ||||
| 
 | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             let mut defs: Vec<DefWithBodyId> = vec![]; | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |it| { | ||||
|                 let def = match it { | ||||
|                     ModuleDefId::FunctionId(it) => it.into(), | ||||
|                     ModuleDefId::EnumVariantId(it) => it.into(), | ||||
|                     ModuleDefId::ConstId(it) => it.into(), | ||||
|                     ModuleDefId::StaticId(it) => it.into(), | ||||
|                     _ => return, | ||||
|                 }; | ||||
|                 defs.push(def); | ||||
|             }); | ||||
| 
 | ||||
|         let expected = vec![ | ||||
|             "parse_shim".to_owned(), | ||||
|             "ast_id_map_shim".to_owned(), | ||||
|             "file_item_tree_shim".to_owned(), | ||||
|             "real_span_map_shim".to_owned(), | ||||
|             "crate_local_def_map".to_owned(), | ||||
|             "trait_impls_in_crate_shim".to_owned(), | ||||
|             "attrs_shim".to_owned(), | ||||
|             "impl_trait_with_diagnostics_shim".to_owned(), | ||||
|             "impl_signature_shim".to_owned(), | ||||
|             "impl_signature_with_source_map_shim".to_owned(), | ||||
|             "impl_self_ty_with_diagnostics_shim".to_owned(), | ||||
|             "struct_signature_shim".to_owned(), | ||||
|             "struct_signature_with_source_map_shim".to_owned(), | ||||
|             "type_for_adt_tracked".to_owned(), | ||||
|         ]; | ||||
|             for def in defs { | ||||
|                 let _inference_result = db.infer(def); | ||||
|             } | ||||
|         }, | ||||
|         &[("trait_solve_shim", 2)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "source_root_crates_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "file_item_tree_query", | ||||
|                 "ast_id_map_shim", | ||||
|                 "parse_shim", | ||||
|                 "real_span_map_shim", | ||||
|                 "trait_items_with_diagnostics_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "of_", | ||||
|                 "infer_shim", | ||||
|                 "trait_signature_shim", | ||||
|                 "trait_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "body_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "lang_item", | ||||
|                 "crate_lang_items", | ||||
|                 "attrs_shim", | ||||
|                 "attrs_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "struct_signature_shim", | ||||
|                 "struct_signature_with_source_map_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "value_ty_shim", | ||||
|                 "variant_fields_shim", | ||||
|                 "variant_fields_with_source_map_shim", | ||||
|                 "lang_item", | ||||
|                 "inherent_impls_in_crate_shim", | ||||
|                 "impl_signature_shim", | ||||
|                 "impl_signature_with_source_map_shim", | ||||
|                 "callable_item_signature_shim", | ||||
|                 "adt_variance_shim", | ||||
|                 "variances_of_shim", | ||||
|                 "trait_solve_shim", | ||||
|                 "trait_datum_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "adt_datum_shim", | ||||
|                 "trait_impls_in_deps_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|                 "impl_trait_with_diagnostics_shim", | ||||
|                 "impl_self_ty_with_diagnostics_shim", | ||||
|                 "type_for_adt_tracked", | ||||
|                 "impl_datum_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "program_clauses_for_chalk_env_shim", | ||||
|                 "value_ty_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "trait_solve_shim", | ||||
|                 "lang_item", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| 
 | ||||
|         assert_eq!(expected, actual); | ||||
|     let new_text = " | ||||
| //- /main.rs crate:main
 | ||||
| struct AnotherStruct; | ||||
| 
 | ||||
| struct SomeStruct; | ||||
| 
 | ||||
| trait Trait<T> { | ||||
|     fn method(&self) -> T; | ||||
| } | ||||
| impl Trait<u32> for SomeStruct {} | ||||
| 
 | ||||
| fn main() { | ||||
|     let s = SomeStruct; | ||||
|     s.method(); | ||||
|     s.$0 | ||||
| }";
 | ||||
| 
 | ||||
|     db.set_file_text(file_id.file_id(&db), new_text); | ||||
| 
 | ||||
|     execute_assert_events( | ||||
|         &db, | ||||
|         || { | ||||
|             let module = db.module_for_file(file_id.file_id(&db)); | ||||
|             let crate_def_map = module.def_map(&db); | ||||
|             let mut defs: Vec<DefWithBodyId> = vec![]; | ||||
| 
 | ||||
|             visit_module(&db, crate_def_map, module.local_id, &mut |it| { | ||||
|                 let def = match it { | ||||
|                     ModuleDefId::FunctionId(it) => it.into(), | ||||
|                     ModuleDefId::EnumVariantId(it) => it.into(), | ||||
|                     ModuleDefId::ConstId(it) => it.into(), | ||||
|                     ModuleDefId::StaticId(it) => it.into(), | ||||
|                     _ => return, | ||||
|                 }; | ||||
|                 defs.push(def); | ||||
|             }); | ||||
| 
 | ||||
|             for def in defs { | ||||
|                 let _inference_result = db.infer(def); | ||||
|             } | ||||
|         }, | ||||
|         &[("trait_solve_shim", 0)], | ||||
|         expect_test::expect![[r#" | ||||
|             [ | ||||
|                 "parse_shim", | ||||
|                 "ast_id_map_shim", | ||||
|                 "file_item_tree_query", | ||||
|                 "real_span_map_shim", | ||||
|                 "crate_local_def_map", | ||||
|                 "trait_items_with_diagnostics_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "body_shim", | ||||
|                 "of_", | ||||
|                 "infer_shim", | ||||
|                 "attrs_shim", | ||||
|                 "trait_signature_with_source_map_shim", | ||||
|                 "attrs_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "function_signature_shim", | ||||
|                 "body_with_source_map_shim", | ||||
|                 "body_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "crate_lang_items", | ||||
|                 "attrs_shim", | ||||
|                 "attrs_shim", | ||||
|                 "attrs_shim", | ||||
|                 "return_type_impl_traits_shim", | ||||
|                 "infer_shim", | ||||
|                 "function_signature_with_source_map_shim", | ||||
|                 "trait_environment_shim", | ||||
|                 "expr_scopes_shim", | ||||
|                 "struct_signature_with_source_map_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "variant_fields_with_source_map_shim", | ||||
|                 "inherent_impls_in_crate_shim", | ||||
|                 "impl_signature_with_source_map_shim", | ||||
|                 "impl_signature_shim", | ||||
|                 "callable_item_signature_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "trait_impls_in_crate_shim", | ||||
|                 "impl_trait_with_diagnostics_shim", | ||||
|                 "impl_self_ty_with_diagnostics_shim", | ||||
|                 "generic_predicates_shim", | ||||
|                 "generic_predicates_shim", | ||||
|             ] | ||||
|         "#]],
 | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| fn execute_assert_events( | ||||
|     db: &TestDB, | ||||
|     f: impl FnOnce(), | ||||
|     required: &[(&str, usize)], | ||||
|     expect: Expect, | ||||
| ) { | ||||
|     let events = db.log_executed(f); | ||||
|     for (event, count) in required { | ||||
|         let n = events.iter().filter(|it| it.contains(event)).count(); | ||||
|         assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}"); | ||||
|     } | ||||
|     expect.assert_debug_eq(&events); | ||||
| } | ||||
|  |  | |||
|  | @ -109,7 +109,7 @@ impl DebugContext<'_> { | |||
|             CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(), | ||||
|             CallableDefId::EnumVariantId(e) => { | ||||
|                 let loc = e.lookup(self.0); | ||||
|                 self.0.enum_variants(loc.parent).variants[loc.index as usize].1.clone() | ||||
|                 loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone() | ||||
|             } | ||||
|         }; | ||||
|         match def { | ||||
|  |  | |||
|  | @ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call( | |||
|     let loc = func.lookup(db); | ||||
|     match loc.container { | ||||
|         hir_def::ItemContainerId::ExternBlockId(block) => { | ||||
|             let id = block.lookup(db).id; | ||||
|             let is_intrinsic_block = | ||||
|                 id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); | ||||
|             let is_intrinsic_block = block.abi(db) == Some(sym::rust_dash_intrinsic); | ||||
|             if is_intrinsic_block { | ||||
|                 // legacy intrinsics
 | ||||
|                 // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
 | ||||
|  | @ -357,7 +355,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( | |||
|     let (var_id, var_layout) = match &layout.variants { | ||||
|         hir_def::layout::Variants::Empty => unreachable!(), | ||||
|         hir_def::layout::Variants::Single { index } => { | ||||
|             (db.enum_variants(e).variants[index.0].0, layout) | ||||
|             (e.enum_variants(db).variants[index.0].0, layout) | ||||
|         } | ||||
|         hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { | ||||
|             let size = tag.size(target_data_layout).bytes_usize(); | ||||
|  | @ -367,7 +365,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( | |||
|                 TagEncoding::Direct => { | ||||
|                     let (var_idx, layout) = | ||||
|                         variants.iter_enumerated().find_map(|(var_idx, v)| { | ||||
|                             let def = db.enum_variants(e).variants[var_idx.0].0; | ||||
|                             let def = e.enum_variants(db).variants[var_idx.0].0; | ||||
|                             (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v)) | ||||
|                         })?; | ||||
|                     (var_idx, layout) | ||||
|  | @ -380,7 +378,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( | |||
|                         .filter(|x| x != untagged_variant) | ||||
|                         .nth(candidate_tag) | ||||
|                         .unwrap_or(*untagged_variant); | ||||
|                     (db.enum_variants(e).variants[variant.0].0, &variants[variant]) | ||||
|                     (e.enum_variants(db).variants[variant.0].0, &variants[variant]) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -213,7 +213,7 @@ impl Context<'_> { | |||
|                     AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)), | ||||
|                     AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)), | ||||
|                     AdtId::EnumId(e) => { | ||||
|                         db.enum_variants(e).variants.iter().for_each(|&(variant, _)| { | ||||
|                         e.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| { | ||||
|                             add_constraints_from_variant(VariantId::EnumVariantId(variant)) | ||||
|                         }); | ||||
|                     } | ||||
|  |  | |||
|  | @ -52,12 +52,14 @@ use hir_def::{ | |||
|         BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, | ||||
|         generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, | ||||
|     }, | ||||
|     item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, | ||||
|     item_tree::ImportAlias, | ||||
|     layout::{self, ReprOptions, TargetDataLayout}, | ||||
|     nameres::{self, diagnostics::DefDiagnostic}, | ||||
|     per_ns::PerNs, | ||||
|     resolver::{HasResolver, Resolver}, | ||||
|     signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, | ||||
|     src::HasSource as _, | ||||
|     visibility::visibility_from_ast, | ||||
| }; | ||||
| use hir_expand::{ | ||||
|     AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, | ||||
|  | @ -81,11 +83,11 @@ use itertools::Itertools; | |||
| use nameres::diagnostics::DefDiagnosticKind; | ||||
| use rustc_hash::FxHashSet; | ||||
| use smallvec::SmallVec; | ||||
| use span::{Edition, FileId}; | ||||
| use span::{AstIdNode, Edition, FileId}; | ||||
| use stdx::{format_to, impl_from, never}; | ||||
| use syntax::{ | ||||
|     AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, | ||||
|     ast::{self, HasAttrs as _, HasName}, | ||||
|     ast::{self, HasAttrs as _, HasName, HasVisibility as _}, | ||||
|     format_smolstr, | ||||
| }; | ||||
| use triomphe::{Arc, ThinArc}; | ||||
|  | @ -686,8 +688,8 @@ impl Module { | |||
|                         Adt::Enum(e) => { | ||||
|                             let source_map = db.enum_signature_with_source_map(e.id).1; | ||||
|                             expr_store_diagnostics(db, acc, &source_map); | ||||
|                             let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id); | ||||
|                             let file = e.id.lookup(db).id.file_id(); | ||||
|                             let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db); | ||||
|                             let file = e.id.lookup(db).id.file_id; | ||||
|                             let ast_id_map = db.ast_id_map(file); | ||||
|                             if let Some(diagnostics) = &diagnostics { | ||||
|                                 for diag in diagnostics.iter() { | ||||
|  | @ -704,7 +706,7 @@ impl Module { | |||
|                                     ); | ||||
|                                 } | ||||
|                             } | ||||
|                             for &(v, _) in &variants.variants { | ||||
|                             for &(v, _, _) in &variants.variants { | ||||
|                                 let source_map = db.variant_fields_with_source_map(v.into()).1; | ||||
|                                 push_ty_diagnostics( | ||||
|                                     db, | ||||
|  | @ -742,12 +744,10 @@ impl Module { | |||
|             GenericDef::Impl(impl_def).diagnostics(db, acc); | ||||
| 
 | ||||
|             let loc = impl_def.id.lookup(db); | ||||
|             let tree = loc.id.item_tree(db); | ||||
|             let source_map = db.impl_signature_with_source_map(impl_def.id).1; | ||||
|             expr_store_diagnostics(db, acc, &source_map); | ||||
| 
 | ||||
|             let node = &tree[loc.id.value]; | ||||
|             let file_id = loc.id.file_id(); | ||||
|             let file_id = loc.id.file_id; | ||||
|             if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { | ||||
|                 // these expansion come from us, diagnosing them is a waste of resources
 | ||||
|                 // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
 | ||||
|  | @ -760,16 +760,16 @@ impl Module { | |||
| 
 | ||||
|             let ast_id_map = db.ast_id_map(file_id); | ||||
| 
 | ||||
|             for diag in db.impl_items_with_diagnostics(impl_def.id).1.iter() { | ||||
|             for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { | ||||
|                 emit_def_diagnostic(db, acc, diag, edition); | ||||
|             } | ||||
| 
 | ||||
|             if inherent_impls.invalid_impls().contains(&impl_def.id) { | ||||
|                 acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) | ||||
|                 acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) | ||||
|             } | ||||
| 
 | ||||
|             if !impl_def.check_orphan_rules(db) { | ||||
|                 acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) | ||||
|                 acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) | ||||
|             } | ||||
| 
 | ||||
|             let trait_ = impl_def.trait_(db); | ||||
|  | @ -808,11 +808,11 @@ impl Module { | |||
|                 // unsafe negative impl
 | ||||
|                 (true, _, true, _) | | ||||
|                 // unsafe impl for safe trait
 | ||||
|                 (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()), | ||||
|                 (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()), | ||||
|                 // safe impl for unsafe trait
 | ||||
|                 (false, true, false, _) | | ||||
|                 // safe impl of dangling drop
 | ||||
|                 (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()), | ||||
|                 (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()), | ||||
|                 _ => (), | ||||
|             }; | ||||
| 
 | ||||
|  | @ -824,7 +824,7 @@ impl Module { | |||
|                     AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), | ||||
|                     AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), | ||||
|                 }); | ||||
|                 impl_assoc_items_scratch.extend(db.impl_items(impl_def.id).items.iter().cloned()); | ||||
|                 impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned()); | ||||
| 
 | ||||
|                 let redundant = impl_assoc_items_scratch | ||||
|                     .iter() | ||||
|  | @ -839,14 +839,14 @@ impl Module { | |||
|                         TraitImplRedundantAssocItems { | ||||
|                             trait_, | ||||
|                             file_id, | ||||
|                             impl_: ast_id_map.get(node.ast_id()), | ||||
|                             impl_: ast_id_map.get(loc.id.value), | ||||
|                             assoc_item: (name, assoc_item), | ||||
|                         } | ||||
|                         .into(), | ||||
|                     ) | ||||
|                 } | ||||
| 
 | ||||
|                 let missing: Vec<_> = required_items | ||||
|                 let mut missing: Vec<_> = required_items | ||||
|                     .filter(|(name, id)| { | ||||
|                         !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| { | ||||
|                             discriminant(impl_item) == discriminant(id) && impl_name == name | ||||
|  | @ -854,10 +854,42 @@ impl Module { | |||
|                     }) | ||||
|                     .map(|(name, item)| (name.clone(), AssocItem::from(*item))) | ||||
|                     .collect(); | ||||
| 
 | ||||
|                 if !missing.is_empty() { | ||||
|                     let self_ty = db.impl_self_ty(impl_def.id).substitute( | ||||
|                         Interner, | ||||
|                         &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db), | ||||
|                     ); | ||||
|                     let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) = | ||||
|                         self_ty.kind(Interner) | ||||
|                     { | ||||
|                         db.normalize_projection( | ||||
|                             projection.clone(), | ||||
|                             db.trait_environment(impl_def.id.into()), | ||||
|                         ) | ||||
|                     } else { | ||||
|                         self_ty | ||||
|                     }; | ||||
|                     let self_ty_is_guaranteed_unsized = matches!( | ||||
|                         self_ty.kind(Interner), | ||||
|                         TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str | ||||
|                     ); | ||||
|                     if self_ty_is_guaranteed_unsized { | ||||
|                         missing.retain(|(_, assoc_item)| { | ||||
|                             let assoc_item = match *assoc_item { | ||||
|                                 AssocItem::Function(it) => it.id.into(), | ||||
|                                 AssocItem::Const(it) => it.id.into(), | ||||
|                                 AssocItem::TypeAlias(it) => it.id.into(), | ||||
|                             }; | ||||
|                             !hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item) | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if !missing.is_empty() { | ||||
|                     acc.push( | ||||
|                         TraitImplMissingAssocItems { | ||||
|                             impl_: ast_id_map.get(node.ast_id()), | ||||
|                             impl_: ast_id_map.get(loc.id.value), | ||||
|                             file_id, | ||||
|                             missing, | ||||
|                         } | ||||
|  | @ -880,7 +912,7 @@ impl Module { | |||
|                 &source_map, | ||||
|             ); | ||||
| 
 | ||||
|             for &(_, item) in db.impl_items(impl_def.id).items.iter() { | ||||
|             for &(_, item) in impl_def.id.impl_items(db).items.iter() { | ||||
|                 AssocItem::from(item).diagnostics(db, acc, style_lints); | ||||
|             } | ||||
|         } | ||||
|  | @ -1044,73 +1076,25 @@ fn emit_def_diagnostic_( | |||
|             ) | ||||
|         } | ||||
|         DefDiagnosticKind::UnresolvedImport { id, index } => { | ||||
|             let file_id = id.file_id(); | ||||
|             let item_tree = id.item_tree(db); | ||||
|             let import = &item_tree[id.value]; | ||||
|             let file_id = id.file_id; | ||||
| 
 | ||||
|             let use_tree = import.use_tree_to_ast(db, file_id, *index); | ||||
|             let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index); | ||||
|             acc.push( | ||||
|                 UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(), | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => { | ||||
|             let item_tree = tree.item_tree(db); | ||||
|             let ast_id_map = db.ast_id_map(tree.file_id()); | ||||
|             // FIXME: This parses... We could probably store relative ranges for the children things
 | ||||
|             // here in the item tree?
 | ||||
|             (|| { | ||||
|                 let process_field_list = | ||||
|                     |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? { | ||||
|                         ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new( | ||||
|                             it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), | ||||
|                         )), | ||||
|                         ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new( | ||||
|                             it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), | ||||
|                         )), | ||||
|                     }; | ||||
|                 let ptr = match *item { | ||||
|                     AttrOwner::ModItem(it) => { | ||||
|                         ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr() | ||||
|                     } | ||||
|                     AttrOwner::TopLevel => ast_id_map.root(), | ||||
|                     AttrOwner::Variant(it) => { | ||||
|                         ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr() | ||||
|                     } | ||||
|                     AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list( | ||||
|                         ast_id_map | ||||
|                             .get(item_tree[parent].ast_id) | ||||
|                             .to_node(&db.parse_or_expand(tree.file_id())) | ||||
|                             .field_list(), | ||||
|                         idx, | ||||
|                     )?, | ||||
|                     AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list( | ||||
|                         ast_id_map | ||||
|                             .get(item_tree[parent.index()].ast_id) | ||||
|                             .to_node(&db.parse_or_expand(tree.file_id())) | ||||
|                             .field_list(), | ||||
|                         idx, | ||||
|                     )?, | ||||
|                     AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new( | ||||
|                         ast_id_map | ||||
|                             .get(item_tree[parent.index()].ast_id) | ||||
|                             .to_node(&db.parse_or_expand(tree.file_id())) | ||||
|                             .record_field_list()? | ||||
|                             .fields() | ||||
|                             .nth(idx.into_raw().into_u32() as usize)? | ||||
|                             .syntax(), | ||||
|                     ), | ||||
|                 }; | ||||
|         DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => { | ||||
|             let ast_id_map = db.ast_id_map(ast_id.file_id); | ||||
|             let ptr = ast_id_map.get_erased(ast_id.value); | ||||
|             acc.push( | ||||
|                 InactiveCode { | ||||
|                         node: InFile::new(tree.file_id(), ptr), | ||||
|                     node: InFile::new(ast_id.file_id, ptr), | ||||
|                     cfg: cfg.clone(), | ||||
|                     opts: opts.clone(), | ||||
|                 } | ||||
|                 .into(), | ||||
|             ); | ||||
|                 Some(()) | ||||
|             })(); | ||||
|         } | ||||
|         DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { | ||||
|             let (node, precise_location) = precise_macro_call_location(ast, db); | ||||
|  | @ -1446,12 +1430,8 @@ impl Struct { | |||
| impl HasVisibility for Struct { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1504,12 +1484,8 @@ impl Union { | |||
| impl HasVisibility for Union { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1528,11 +1504,11 @@ impl Enum { | |||
|     } | ||||
| 
 | ||||
|     pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> { | ||||
|         db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() | ||||
|         self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn num_variants(self, db: &dyn HirDatabase) -> usize { | ||||
|         db.enum_variants(self.id).variants.len() | ||||
|         self.id.enum_variants(db).variants.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { | ||||
|  | @ -1597,12 +1573,8 @@ impl Enum { | |||
| impl HasVisibility for Enum { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1634,7 +1606,7 @@ impl Variant { | |||
|     pub fn name(self, db: &dyn HirDatabase) -> Name { | ||||
|         let lookup = self.id.lookup(db); | ||||
|         let enum_ = lookup.parent; | ||||
|         db.enum_variants(enum_).variants[lookup.index as usize].1.clone() | ||||
|         enum_.enum_variants(db).variants[lookup.index as usize].1.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||||
|  | @ -2660,7 +2632,7 @@ impl SelfParam { | |||
| 
 | ||||
| impl HasVisibility for Function { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         db.function_visibility(self.id) | ||||
|         db.assoc_visibility(self.id.into()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -2676,10 +2648,9 @@ impl ExternCrateDecl { | |||
| 
 | ||||
|     pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         let krate = loc.container.krate(); | ||||
|         let name = &item_tree[loc.id.value].name; | ||||
|         if *name == sym::self_ { | ||||
|         let name = self.name(db); | ||||
|         if name == sym::self_ { | ||||
|             Some(krate.into()) | ||||
|         } else { | ||||
|             krate.data(db).dependencies.iter().find_map(|dep| { | ||||
|  | @ -2690,25 +2661,29 @@ impl ExternCrateDecl { | |||
| 
 | ||||
|     pub fn name(self, db: &dyn HirDatabase) -> Name { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         item_tree[loc.id.value].name.clone() | ||||
|         let source = loc.source(db); | ||||
|         as_name_opt(source.value.name_ref()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         item_tree[loc.id.value].alias.clone() | ||||
|         let source = loc.source(db); | ||||
|         let rename = source.value.rename()?; | ||||
|         if let Some(name) = rename.name() { | ||||
|             Some(ImportAlias::Alias(name.as_name())) | ||||
|         } else if rename.underscore_token().is_some() { | ||||
|             Some(ImportAlias::Underscore) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the name under which this crate is made accessible, taking `_` into account.
 | ||||
|     pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
| 
 | ||||
|         match &item_tree[loc.id.value].alias { | ||||
|         match self.alias(db) { | ||||
|             Some(ImportAlias::Underscore) => None, | ||||
|             Some(ImportAlias::Alias(alias)) => Some(alias.clone()), | ||||
|             None => Some(item_tree[loc.id.value].name.clone()), | ||||
|             Some(ImportAlias::Alias(alias)) => Some(alias), | ||||
|             None => Some(self.name(db)), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -2716,12 +2691,8 @@ impl ExternCrateDecl { | |||
| impl HasVisibility for ExternCrateDecl { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -2756,7 +2727,7 @@ impl Const { | |||
| 
 | ||||
| impl HasVisibility for Const { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         db.const_visibility(self.id) | ||||
|         db.assoc_visibility(self.id.into()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -2841,12 +2812,8 @@ impl Static { | |||
| impl HasVisibility for Static { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -2935,11 +2902,7 @@ impl Trait { | |||
|     } | ||||
| 
 | ||||
|     fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { | ||||
|         db.trait_items(self.id) | ||||
|             .macro_calls | ||||
|             .as_ref() | ||||
|             .map(|it| it.as_ref().clone().into_boxed_slice()) | ||||
|             .unwrap_or_default() | ||||
|         db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice() | ||||
|     } | ||||
| 
 | ||||
|     /// `#[rust_analyzer::completions(...)]` mode.
 | ||||
|  | @ -2951,12 +2914,8 @@ impl Trait { | |||
| impl HasVisibility for Trait { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -2978,12 +2937,8 @@ impl TraitAlias { | |||
| impl HasVisibility for TraitAlias { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         let loc = self.id.lookup(db); | ||||
|         let item_tree = loc.id.item_tree(db); | ||||
|         Visibility::resolve( | ||||
|             db, | ||||
|             &self.id.resolver(db), | ||||
|             &item_tree[item_tree[loc.id.value].visibility], | ||||
|         ) | ||||
|         let source = loc.source(db); | ||||
|         visibility_from_ast(db, self.id, source.map(|src| src.visibility())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -3021,7 +2976,7 @@ impl TypeAlias { | |||
| 
 | ||||
| impl HasVisibility for TypeAlias { | ||||
|     fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||||
|         db.type_alias_visibility(self.id) | ||||
|         db.assoc_visibility(self.id.into()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -3131,25 +3086,23 @@ impl Macro { | |||
|         match self.id { | ||||
|             MacroId::Macro2Id(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 item_tree[loc.id.value].name.clone() | ||||
|                 let source = loc.source(db); | ||||
|                 as_name_opt(source.value.name()) | ||||
|             } | ||||
|             MacroId::MacroRulesId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 item_tree[loc.id.value].name.clone() | ||||
|                 let source = loc.source(db); | ||||
|                 as_name_opt(source.value.name()) | ||||
|             } | ||||
|             MacroId::ProcMacroId(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 let source = loc.source(db); | ||||
|                 match loc.kind { | ||||
|                     ProcMacroKind::CustomDerive => db | ||||
|                         .attrs(id.into()) | ||||
|                         .parse_proc_macro_derive() | ||||
|                         .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it), | ||||
|                     ProcMacroKind::Bang | ProcMacroKind::Attr => { | ||||
|                         item_tree[loc.id.value].name.clone() | ||||
|                     } | ||||
|                         .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), | ||||
|                     ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -3246,12 +3199,8 @@ impl HasVisibility for Macro { | |||
|         match self.id { | ||||
|             MacroId::Macro2Id(id) => { | ||||
|                 let loc = id.lookup(db); | ||||
|                 let item_tree = loc.id.item_tree(db); | ||||
|                 Visibility::resolve( | ||||
|                     db, | ||||
|                     &id.resolver(db), | ||||
|                     &item_tree[item_tree[loc.id.value].visibility], | ||||
|                 ) | ||||
|                 let source = loc.source(db); | ||||
|                 visibility_from_ast(db, id, source.map(|src| src.visibility())) | ||||
|             } | ||||
|             MacroId::MacroRulesId(_) => Visibility::Public, | ||||
|             MacroId::ProcMacroId(_) => Visibility::Public, | ||||
|  | @ -3405,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( | |||
| where | ||||
|     ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>, | ||||
|     DEF: From<ID>, | ||||
|     LOC: ItemTreeNode, | ||||
|     LOC: AstIdNode, | ||||
| { | ||||
|     match id.lookup(db).container { | ||||
|         ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | ||||
|  | @ -3421,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( | |||
| where | ||||
|     ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>, | ||||
|     DEF: From<ID>, | ||||
|     LOC: ItemTreeNode, | ||||
|     LOC: AstIdNode, | ||||
| { | ||||
|     match id.lookup(db).container { | ||||
|         ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), | ||||
|  | @ -4464,7 +4413,7 @@ impl Impl { | |||
|     } | ||||
| 
 | ||||
|     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||||
|         db.impl_items(self.id).items.iter().map(|&(_, it)| it.into()).collect() | ||||
|         self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_negative(self, db: &dyn HirDatabase) -> bool { | ||||
|  | @ -4513,11 +4462,7 @@ impl Impl { | |||
|     } | ||||
| 
 | ||||
|     fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { | ||||
|         db.impl_items(self.id) | ||||
|             .macro_calls | ||||
|             .as_ref() | ||||
|             .map(|it| it.as_ref().clone().into_boxed_slice()) | ||||
|             .unwrap_or_default() | ||||
|         self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -5326,7 +5271,7 @@ impl Type { | |||
|             let impls = db.inherent_impls_in_crate(krate); | ||||
| 
 | ||||
|             for impl_def in impls.for_self_ty(&self.ty) { | ||||
|                 for &(_, item) in db.impl_items(*impl_def).items.iter() { | ||||
|                 for &(_, item) in impl_def.impl_items(db).items.iter() { | ||||
|                     if callback(item) { | ||||
|                         return; | ||||
|                     } | ||||
|  | @ -6478,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( | |||
|         }) | ||||
|         .flatten() | ||||
| } | ||||
| 
 | ||||
| fn as_name_opt(name: Option<impl AsName>) -> Name { | ||||
|     name.map_or_else(Name::missing, |name| name.as_name()) | ||||
| } | ||||
|  |  | |||
|  | @ -25,7 +25,6 @@ use hir_expand::{ | |||
|     builtin::{BuiltinFnLikeExpander, EagerExpander}, | ||||
|     db::ExpandDatabase, | ||||
|     files::{FileRangeWrapper, HirFileRange, InRealFile}, | ||||
|     inert_attr_macro::find_builtin_attr_idx, | ||||
|     mod_path::{ModPath, PathKind}, | ||||
|     name::AsName, | ||||
| }; | ||||
|  | @ -159,13 +158,13 @@ pub struct SemanticsImpl<'db> { | |||
|     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>, | ||||
| } | ||||
| 
 | ||||
| impl<DB> fmt::Debug for Semantics<'_, DB> { | ||||
| impl<DB: ?Sized> 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> { | ||||
| impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> { | ||||
|     type Target = SemanticsImpl<'db>; | ||||
| 
 | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|  | @ -173,12 +172,28 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| // Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
 | ||||
| // find actual use within the rust-analyzer project itself, it exists to enable the use
 | ||||
| // within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
 | ||||
| impl Semantics<'_, dyn HirDatabase> { | ||||
|     /// Creates an instance that's weakly coupled to its underlying database type.
 | ||||
|     pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> { | ||||
|         let impl_ = SemanticsImpl::new(db); | ||||
|         Semantics { db, imp: impl_ } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<DB: HirDatabase> Semantics<'_, DB> { | ||||
|     /// Creates an instance that's strongly coupled to its underlying database type.
 | ||||
|     pub fn new(db: &DB) -> Semantics<'_, DB> { | ||||
|         let impl_ = SemanticsImpl::new(db); | ||||
|         Semantics { db, imp: impl_ } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Note: We take `DB` as `?Sized` here in order to support type-erased
 | ||||
| // use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
 | ||||
| impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> { | ||||
|     pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId { | ||||
|         self.imp.find_file(syntax_node).file_id | ||||
|     } | ||||
|  | @ -229,7 +244,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> { | |||
|         offset: TextSize, | ||||
|     ) -> impl Iterator<Item = ast::NameLike> + 'slf { | ||||
|         node.token_at_offset(offset) | ||||
|             .map(move |token| self.descend_into_macros_no_opaque(token)) | ||||
|             .map(move |token| self.descend_into_macros_no_opaque(token, true)) | ||||
|             .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent())) | ||||
|             // 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
 | ||||
|  | @ -953,13 +968,6 @@ impl<'db> SemanticsImpl<'db> { | |||
|             let Some(item) = ast::Item::cast(ancestor) else { | ||||
|                 return false; | ||||
|             }; | ||||
|             // Optimization to skip the semantic check.
 | ||||
|             if item.attrs().all(|attr| { | ||||
|                 attr.simple_name() | ||||
|                     .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some()) | ||||
|             }) { | ||||
|                 return false; | ||||
|             } | ||||
|             self.with_ctx(|ctx| { | ||||
|                 if ctx.item_to_macro_call(token.with_value(&item)).is_some() { | ||||
|                     return true; | ||||
|  | @ -1001,10 +1009,11 @@ impl<'db> SemanticsImpl<'db> { | |||
|     pub fn descend_into_macros_no_opaque( | ||||
|         &self, | ||||
|         token: SyntaxToken, | ||||
|         always_descend_into_derives: bool, | ||||
|     ) -> SmallVec<[InFile<SyntaxToken>; 1]> { | ||||
|         let mut res = smallvec![]; | ||||
|         let token = self.wrap_token_infile(token); | ||||
|         self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| { | ||||
|         self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| { | ||||
|             if !ctx.is_opaque(self.db) { | ||||
|                 // Don't descend into opaque contexts
 | ||||
|                 res.push(t); | ||||
|  |  | |||
|  | @ -6,10 +6,11 @@ | |||
| 
 | ||||
| use either::Either; | ||||
| use hir_expand::{HirFileId, attrs::collect_attrs}; | ||||
| use span::AstIdNode; | ||||
| use syntax::{AstPtr, ast}; | ||||
| 
 | ||||
| use hir_def::{ | ||||
|     AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc, | ||||
|     AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, | ||||
|     LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId, | ||||
|     VariantId, | ||||
|     db::DefDatabase, | ||||
|  | @ -19,7 +20,6 @@ use hir_def::{ | |||
|     }, | ||||
|     hir::generics::GenericParams, | ||||
|     item_scope::ItemScope, | ||||
|     item_tree::ItemTreeNode, | ||||
|     nameres::DefMap, | ||||
|     src::{HasChildSource, HasSource}, | ||||
| }; | ||||
|  | @ -61,7 +61,7 @@ impl ChildBySource for TraitId { | |||
| 
 | ||||
| impl ChildBySource for ImplId { | ||||
|     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { | ||||
|         let data = db.impl_items(*self); | ||||
|         let data = self.impl_items(db); | ||||
|         data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( | ||||
|             |(ast_id, call_id)| { | ||||
|                 let ptr = ast_id.to_ptr(db); | ||||
|  | @ -113,7 +113,7 @@ impl ChildBySource for ItemScope { | |||
|             ids.iter().for_each(|&id| { | ||||
|                 if let MacroId::MacroRulesId(id) = id { | ||||
|                     let loc = id.lookup(db); | ||||
|                     if loc.id.file_id() == file_id { | ||||
|                     if loc.id.file_id == file_id { | ||||
|                         res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id); | ||||
|                     } | ||||
|                 } | ||||
|  | @ -199,16 +199,14 @@ impl ChildBySource for VariantId { | |||
| impl ChildBySource for EnumId { | ||||
|     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { | ||||
|         let loc = &self.lookup(db); | ||||
|         if file_id != loc.id.file_id() { | ||||
|         if file_id != loc.id.file_id { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let tree = loc.id.item_tree(db); | ||||
|         let ast_id_map = db.ast_id_map(loc.id.file_id()); | ||||
|         let ast_id_map = db.ast_id_map(loc.id.file_id); | ||||
| 
 | ||||
|         db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| { | ||||
|             res[keys::ENUM_VARIANT] | ||||
|                 .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); | ||||
|         self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| { | ||||
|             res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); | ||||
|         }); | ||||
|         let (_, source_map) = db.enum_signature_with_source_map(*self); | ||||
|         source_map | ||||
|  | @ -287,15 +285,14 @@ fn insert_item_loc<ID, N, Data>( | |||
|     res: &mut DynMap, | ||||
|     file_id: HirFileId, | ||||
|     id: ID, | ||||
|     key: Key<N::Source, ID>, | ||||
|     key: Key<N, ID>, | ||||
| ) where | ||||
|     ID: Lookup<Database = dyn DefDatabase, Data = Data> + 'static, | ||||
|     Data: ItemTreeLoc<Id = N>, | ||||
|     N: ItemTreeNode, | ||||
|     N::Source: 'static, | ||||
|     Data: AstIdLoc<Ast = N>, | ||||
|     N: AstIdNode + 'static, | ||||
| { | ||||
|     let loc = id.lookup(db); | ||||
|     if loc.item_tree_id().file_id() == file_id { | ||||
|     if loc.ast_id().file_id == file_id { | ||||
|         res[key].insert(loc.ast_ptr(db).value, id) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ use hir_expand::{ | |||
| }; | ||||
| use hir_ty::{ | ||||
|     Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy, | ||||
|     Substitution, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext, | ||||
|     Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext, | ||||
|     diagnostics::{ | ||||
|         InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, | ||||
|         unsafe_operations, | ||||
|  | @ -829,7 +829,7 @@ impl<'db> SourceAnalyzer<'db> { | |||
|                                 handle_variants(id.into(), subst, &mut container)? | ||||
|                             } | ||||
|                             AdtId::EnumId(id) => { | ||||
|                                 let variants = db.enum_variants(id); | ||||
|                                 let variants = id.enum_variants(db); | ||||
|                                 let variant = variants.variant(&field_name.as_name())?; | ||||
|                                 container = Either::Left((variant, subst.clone())); | ||||
|                                 (Either::Left(Variant { id: variant }), id.into(), subst.clone()) | ||||
|  | @ -1169,8 +1169,7 @@ impl<'db> SourceAnalyzer<'db> { | |||
|                         ) | ||||
|                     } | ||||
|                     TyKind::FnDef(fn_id, subst) => { | ||||
|                         let fn_id = hir_ty::db::InternedCallableDefId::from(*fn_id); | ||||
|                         let fn_id = db.lookup_intern_callable_def(fn_id); | ||||
|                         let fn_id = ToChalk::from_chalk(db, *fn_id); | ||||
|                         let generic_def_id = match fn_id { | ||||
|                             CallableDefId::StructId(id) => id.into(), | ||||
|                             CallableDefId::FunctionId(id) => id.into(), | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| //! File symbol extraction.
 | ||||
| 
 | ||||
| use base_db::FxIndexSet; | ||||
| use either::Either; | ||||
| use hir_def::{ | ||||
|     AdtId, AssocItemId, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, | ||||
|  | @ -21,8 +22,6 @@ use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast | |||
| 
 | ||||
| use crate::{HasCrate, Module, ModuleDef, Semantics}; | ||||
| 
 | ||||
| pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; | ||||
| 
 | ||||
| /// The actual data that is stored in the index. It should be as compact as
 | ||||
| /// possible.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
|  | @ -34,6 +33,7 @@ pub struct FileSymbol { | |||
|     /// Whether this symbol is a doc alias for the original symbol.
 | ||||
|     pub is_alias: bool, | ||||
|     pub is_assoc: bool, | ||||
|     pub is_import: bool, | ||||
|     pub do_not_complete: Complete, | ||||
| } | ||||
| 
 | ||||
|  | @ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> { | |||
| 
 | ||||
|         let is_explicit_import = |vis| match vis { | ||||
|             Visibility::Public => true, | ||||
|             Visibility::PubCrate(_) => true, | ||||
|             Visibility::Module(_, VisibilityExplicitness::Explicit) => true, | ||||
|             Visibility::Module(_, VisibilityExplicitness::Implicit) => false, | ||||
|         }; | ||||
|  | @ -197,6 +198,7 @@ impl<'a> SymbolCollector<'a> { | |||
|                 loc: dec_loc, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Complete::Yes, | ||||
|             }); | ||||
|         }; | ||||
|  | @ -227,6 +229,7 @@ impl<'a> SymbolCollector<'a> { | |||
|                     loc: dec_loc, | ||||
|                     is_alias: false, | ||||
|                     is_assoc: false, | ||||
|                     is_import: false, | ||||
|                     do_not_complete: Complete::Yes, | ||||
|                 }); | ||||
|             }; | ||||
|  | @ -322,7 +325,7 @@ impl<'a> SymbolCollector<'a> { | |||
|                 .to_smolstr(), | ||||
|         ); | ||||
|         self.with_container_name(impl_name, |s| { | ||||
|             for &(ref name, assoc_item_id) in &self.db.impl_items(impl_id).items { | ||||
|             for &(ref name, assoc_item_id) in &impl_id.impl_items(self.db).items { | ||||
|                 s.push_assoc_item(assoc_item_id, name, None) | ||||
|             } | ||||
|         }) | ||||
|  | @ -398,6 +401,7 @@ impl<'a> SymbolCollector<'a> { | |||
|                     container_name: self.current_container_name.clone(), | ||||
|                     is_alias: true, | ||||
|                     is_assoc, | ||||
|                     is_import: false, | ||||
|                     do_not_complete, | ||||
|                 }); | ||||
|             } | ||||
|  | @ -410,6 +414,7 @@ impl<'a> SymbolCollector<'a> { | |||
|             loc: dec_loc, | ||||
|             is_alias: false, | ||||
|             is_assoc, | ||||
|             is_import: false, | ||||
|             do_not_complete, | ||||
|         }); | ||||
| 
 | ||||
|  | @ -442,6 +447,7 @@ impl<'a> SymbolCollector<'a> { | |||
|                     container_name: self.current_container_name.clone(), | ||||
|                     is_alias: true, | ||||
|                     is_assoc: false, | ||||
|                     is_import: false, | ||||
|                     do_not_complete, | ||||
|                 }); | ||||
|             } | ||||
|  | @ -454,6 +460,7 @@ impl<'a> SymbolCollector<'a> { | |||
|             loc: dec_loc, | ||||
|             is_alias: false, | ||||
|             is_assoc: false, | ||||
|             is_import: false, | ||||
|             do_not_complete, | ||||
|         }); | ||||
|     } | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ either.workspace = true | |||
| itertools.workspace = true | ||||
| arrayvec.workspace = true | ||||
| indexmap.workspace = true | ||||
| memchr = "2.7.4" | ||||
| memchr = "2.7.5" | ||||
| salsa.workspace = true | ||||
| salsa-macros.workspace = true | ||||
| query-group.workspace = true | ||||
|  |  | |||
|  | @ -50,6 +50,7 @@ pub struct Query { | |||
|     case_sensitive: bool, | ||||
|     only_types: bool, | ||||
|     libs: bool, | ||||
|     exclude_imports: bool, | ||||
| } | ||||
| 
 | ||||
| impl Query { | ||||
|  | @ -63,6 +64,7 @@ impl Query { | |||
|             mode: SearchMode::Fuzzy, | ||||
|             assoc_mode: AssocSearchMode::Include, | ||||
|             case_sensitive: false, | ||||
|             exclude_imports: false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -94,6 +96,10 @@ impl Query { | |||
|     pub fn case_sensitive(&mut self) { | ||||
|         self.case_sensitive = true; | ||||
|     } | ||||
| 
 | ||||
|     pub fn exclude_imports(&mut self) { | ||||
|         self.exclude_imports = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[query_group::query_group] | ||||
|  | @ -362,6 +368,9 @@ impl Query { | |||
|                     if ignore_underscore_prefixed && symbol_name.starts_with("__") { | ||||
|                         continue; | ||||
|                     } | ||||
|                     if self.exclude_imports && symbol.is_import { | ||||
|                         continue; | ||||
|                     } | ||||
|                     if self.mode.check(&self.query, self.case_sensitive, symbol_name) { | ||||
|                         if let Some(b) = cb(symbol).break_value() { | ||||
|                             return Some(b); | ||||
|  | @ -385,7 +394,8 @@ impl Query { | |||
| mod tests { | ||||
| 
 | ||||
|     use expect_test::expect_file; | ||||
|     use test_fixture::WithFixture; | ||||
|     use salsa::Durability; | ||||
|     use test_fixture::{WORKSPACE, WithFixture}; | ||||
| 
 | ||||
|     use super::*; | ||||
| 
 | ||||
|  | @ -506,4 +516,31 @@ struct Duplicate; | |||
| 
 | ||||
|         expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_exclude_imports() { | ||||
|         let (mut db, _) = RootDatabase::with_many_files( | ||||
|             r#" | ||||
| //- /lib.rs
 | ||||
| mod foo; | ||||
| pub use foo::Foo; | ||||
| 
 | ||||
| //- /foo.rs
 | ||||
| pub struct Foo; | ||||
| "#,
 | ||||
|         ); | ||||
| 
 | ||||
|         let mut local_roots = FxHashSet::default(); | ||||
|         local_roots.insert(WORKSPACE); | ||||
|         db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); | ||||
| 
 | ||||
|         let mut query = Query::new("Foo".to_owned()); | ||||
|         let mut symbols = world_symbols(&db, query.clone()); | ||||
|         symbols.sort_by_key(|x| x.is_import); | ||||
|         expect_file!["./test_data/test_symbols_with_imports.txt"].assert_debug_eq(&symbols); | ||||
| 
 | ||||
|         query.exclude_imports(); | ||||
|         let symbols = world_symbols(&db, query); | ||||
|         expect_file!["./test_data/test_symbols_exclude_imports.txt"].assert_debug_eq(&symbols); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -74,6 +75,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -107,6 +109,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: true, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -140,6 +143,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: true, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -173,6 +177,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: true, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -206,6 +211,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: true, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -239,6 +245,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: true, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|         ], | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -70,6 +71,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -101,6 +103,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -134,6 +137,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -167,6 +171,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -200,6 +205,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -231,6 +237,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -264,6 +271,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -297,6 +305,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -332,6 +341,7 @@ | |||
|                 ), | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -367,6 +377,7 @@ | |||
|                 ), | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -400,6 +411,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -433,6 +445,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -464,6 +477,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -497,6 +511,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -530,6 +545,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -565,6 +581,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -600,6 +617,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -633,6 +651,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -666,6 +685,7 @@ | |||
|                 ), | ||||
|                 is_alias: false, | ||||
|                 is_assoc: true, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -699,6 +719,7 @@ | |||
|                 ), | ||||
|                 is_alias: false, | ||||
|                 is_assoc: true, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -732,6 +753,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -763,6 +785,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -796,6 +819,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -829,6 +853,7 @@ | |||
|                 ), | ||||
|                 is_alias: false, | ||||
|                 is_assoc: true, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|         ], | ||||
|  | @ -875,6 +900,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|         ], | ||||
|  | @ -919,6 +945,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -952,6 +979,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -985,6 +1013,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: false, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -1018,6 +1047,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|             FileSymbol { | ||||
|  | @ -1051,6 +1081,7 @@ | |||
|                 container_name: None, | ||||
|                 is_alias: false, | ||||
|                 is_assoc: false, | ||||
|                 is_import: true, | ||||
|                 do_not_complete: Yes, | ||||
|             }, | ||||
|         ], | ||||
|  |  | |||
							
								
								
									
										36
									
								
								crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| [ | ||||
|     FileSymbol { | ||||
|         name: "Foo", | ||||
|         def: Adt( | ||||
|             Struct( | ||||
|                 Struct { | ||||
|                     id: StructId( | ||||
|                         3800, | ||||
|                     ), | ||||
|                 }, | ||||
|             ), | ||||
|         ), | ||||
|         loc: DeclarationLocation { | ||||
|             hir_file_id: FileId( | ||||
|                 EditionedFileId( | ||||
|                     Id(2001), | ||||
|                 ), | ||||
|             ), | ||||
|             ptr: SyntaxNodePtr { | ||||
|                 kind: STRUCT, | ||||
|                 range: 0..15, | ||||
|             }, | ||||
|             name_ptr: AstPtr( | ||||
|                 SyntaxNodePtr { | ||||
|                     kind: NAME, | ||||
|                     range: 11..14, | ||||
|                 }, | ||||
|             ), | ||||
|         }, | ||||
|         container_name: None, | ||||
|         is_alias: false, | ||||
|         is_assoc: false, | ||||
|         is_import: false, | ||||
|         do_not_complete: Yes, | ||||
|     }, | ||||
| ] | ||||
							
								
								
									
										70
									
								
								crates/ide-db/src/test_data/test_symbols_with_imports.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								crates/ide-db/src/test_data/test_symbols_with_imports.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| [ | ||||
|     FileSymbol { | ||||
|         name: "Foo", | ||||
|         def: Adt( | ||||
|             Struct( | ||||
|                 Struct { | ||||
|                     id: StructId( | ||||
|                         3800, | ||||
|                     ), | ||||
|                 }, | ||||
|             ), | ||||
|         ), | ||||
|         loc: DeclarationLocation { | ||||
|             hir_file_id: FileId( | ||||
|                 EditionedFileId( | ||||
|                     Id(2001), | ||||
|                 ), | ||||
|             ), | ||||
|             ptr: SyntaxNodePtr { | ||||
|                 kind: STRUCT, | ||||
|                 range: 0..15, | ||||
|             }, | ||||
|             name_ptr: AstPtr( | ||||
|                 SyntaxNodePtr { | ||||
|                     kind: NAME, | ||||
|                     range: 11..14, | ||||
|                 }, | ||||
|             ), | ||||
|         }, | ||||
|         container_name: None, | ||||
|         is_alias: false, | ||||
|         is_assoc: false, | ||||
|         is_import: false, | ||||
|         do_not_complete: Yes, | ||||
|     }, | ||||
|     FileSymbol { | ||||
|         name: "Foo", | ||||
|         def: Adt( | ||||
|             Struct( | ||||
|                 Struct { | ||||
|                     id: StructId( | ||||
|                         3800, | ||||
|                     ), | ||||
|                 }, | ||||
|             ), | ||||
|         ), | ||||
|         loc: DeclarationLocation { | ||||
|             hir_file_id: FileId( | ||||
|                 EditionedFileId( | ||||
|                     Id(2000), | ||||
|                 ), | ||||
|             ), | ||||
|             ptr: SyntaxNodePtr { | ||||
|                 kind: USE_TREE, | ||||
|                 range: 17..25, | ||||
|             }, | ||||
|             name_ptr: AstPtr( | ||||
|                 SyntaxNodePtr { | ||||
|                     kind: NAME_REF, | ||||
|                     range: 22..25, | ||||
|                 }, | ||||
|             ), | ||||
|         }, | ||||
|         container_name: None, | ||||
|         is_alias: false, | ||||
|         is_assoc: false, | ||||
|         is_import: true, | ||||
|         do_not_complete: Yes, | ||||
|     }, | ||||
| ] | ||||
|  | @ -124,6 +124,35 @@ trait Trait { | |||
| 
 | ||||
| // Negative impls don't require any items (in fact, the forbid providing any)
 | ||||
| impl !Trait for () {} | ||||
| "#,
 | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn impl_sized_for_unsized() { | ||||
|         check_diagnostics( | ||||
|             r#" | ||||
| //- minicore: sized
 | ||||
| trait Trait { | ||||
|     type Item | ||||
|     where | ||||
|         Self: Sized; | ||||
| 
 | ||||
|     fn item() | ||||
|     where | ||||
|         Self: Sized; | ||||
| } | ||||
| 
 | ||||
| trait OtherTrait {} | ||||
| 
 | ||||
| impl Trait for () { | ||||
|     type Item = (); | ||||
|     fn item() {} | ||||
| } | ||||
| 
 | ||||
| // Items with Self: Sized bound not required to be implemented for unsized types.
 | ||||
| impl Trait for str {} | ||||
| impl Trait for dyn OtherTrait {} | ||||
|  "#,
 | ||||
|         ) | ||||
|     } | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ dot.workspace = true | |||
| smallvec.workspace = true | ||||
| triomphe.workspace = true | ||||
| nohash-hasher.workspace = true | ||||
| rustc_apfloat = "0.2.2" | ||||
| rustc_apfloat = "0.2.3" | ||||
| 
 | ||||
| # local deps | ||||
| cfg.workspace = true | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ use crate::{ | |||
|     NavigationTarget, RunnableKind, | ||||
|     annotations::fn_references::find_all_methods, | ||||
|     goto_implementation::goto_implementation, | ||||
|     navigation_target, | ||||
|     references::find_all_refs, | ||||
|     runnables::{Runnable, runnables}, | ||||
| }; | ||||
|  | @ -148,16 +149,33 @@ pub(crate) fn annotations( | |||
|             node: InFile<T>, | ||||
|             source_file_id: FileId, | ||||
|         ) -> Option<(TextRange, Option<TextRange>)> { | ||||
|             if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) { | ||||
|             if let Some(name) = node.value.name().map(|name| name.syntax().text_range()) { | ||||
|                 // if we have a name, try mapping that out of the macro expansion as we can put the
 | ||||
|                 // annotation on that name token
 | ||||
|                 // See `test_no_annotations_macro_struct_def` vs `test_annotations_macro_struct_def_call_site`
 | ||||
|                 let res = navigation_target::orig_range_with_focus_r( | ||||
|                     db, | ||||
|                     node.file_id, | ||||
|                     node.value.syntax().text_range(), | ||||
|                     Some(name), | ||||
|                 ); | ||||
|                 if res.call_site.0.file_id == source_file_id { | ||||
|                     if let Some(name_range) = res.call_site.1 { | ||||
|                         return Some((res.call_site.0.range, Some(name_range))); | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|             // otherwise try upmapping the entire node out of attributes
 | ||||
|             let InRealFile { file_id, value } = node.original_ast_node_rooted(db)?; | ||||
|             if file_id.file_id(db) == source_file_id { | ||||
|                     return Some(( | ||||
|                 Some(( | ||||
|                     value.syntax().text_range(), | ||||
|                     value.name().map(|name| name.syntax().text_range()), | ||||
|                     )); | ||||
|                 } | ||||
|             } | ||||
|                 )) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     if config.annotate_method_references { | ||||
|  | @ -913,6 +931,56 @@ m!(); | |||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_annotations_macro_struct_def_call_site() { | ||||
|         check( | ||||
|             r#" | ||||
| //- /lib.rs
 | ||||
| macro_rules! m { | ||||
|     ($name:ident) => { | ||||
|         struct $name {} | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| m! { | ||||
|     Name | ||||
| }; | ||||
| "#,
 | ||||
|             expect![[r#" | ||||
|                 [ | ||||
|                     Annotation { | ||||
|                         range: 83..87, | ||||
|                         kind: HasImpls { | ||||
|                             pos: FilePositionWrapper { | ||||
|                                 file_id: FileId( | ||||
|                                     0, | ||||
|                                 ), | ||||
|                                 offset: 83, | ||||
|                             }, | ||||
|                             data: Some( | ||||
|                                 [], | ||||
|                             ), | ||||
|                         }, | ||||
|                     }, | ||||
|                     Annotation { | ||||
|                         range: 83..87, | ||||
|                         kind: HasReferences { | ||||
|                             pos: FilePositionWrapper { | ||||
|                                 file_id: FileId( | ||||
|                                     0, | ||||
|                                 ), | ||||
|                                 offset: 83, | ||||
|                             }, | ||||
|                             data: Some( | ||||
|                                 [], | ||||
|                             ), | ||||
|                         }, | ||||
|                     }, | ||||
|                 ] | ||||
|             "#]],
 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_annotations_appear_above_whole_item_when_configured_to_do_so() { | ||||
|         check_with_config( | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ pub(crate) fn goto_declaration( | |||
|         .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; | ||||
|     let range = original_token.text_range(); | ||||
|     let info: Vec<NavigationTarget> = sema | ||||
|         .descend_into_macros_no_opaque(original_token) | ||||
|         .descend_into_macros_no_opaque(original_token, false) | ||||
|         .iter() | ||||
|         .filter_map(|token| { | ||||
|             let parent = token.value.parent()?; | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ pub(crate) fn goto_definition( | |||
|     } | ||||
| 
 | ||||
|     let navs = sema | ||||
|         .descend_into_macros_no_opaque(original_token.clone()) | ||||
|         .descend_into_macros_no_opaque(original_token.clone(), false) | ||||
|         .into_iter() | ||||
|         .filter_map(|token| { | ||||
|             let parent = token.value.parent()?; | ||||
|  |  | |||
|  | @ -70,7 +70,7 @@ pub(crate) fn goto_type_definition( | |||
|     } | ||||
| 
 | ||||
|     let range = token.text_range(); | ||||
|     sema.descend_into_macros_no_opaque(token) | ||||
|     sema.descend_into_macros_no_opaque(token,false) | ||||
|         .into_iter() | ||||
|         .filter_map(|token| { | ||||
|             sema | ||||
|  |  | |||
|  | @ -22,9 +22,14 @@ pub(super) fn hints( | |||
|             let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent); | ||||
|             if ast::TypeBound::can_cast(parent.kind()) | ||||
|                 || ast::TypeAnchor::can_cast(parent.kind()) | ||||
|                 || ast::Impl::cast(parent) | ||||
|                     .and_then(|it| it.trait_()) | ||||
|                     .is_some_and(|it| it.syntax() == path.syntax()) | ||||
|                 || ast::Impl::cast(parent).is_some_and(|it| { | ||||
|                     it.trait_().map_or( | ||||
|                         // only show it for impl type if the impl is not incomplete, otherwise we
 | ||||
|                         // are likely typing a trait impl
 | ||||
|                         it.assoc_item_list().is_none_or(|it| it.l_curly_token().is_none()), | ||||
|                         |trait_| trait_.syntax() == path.syntax(), | ||||
|                     ) | ||||
|                 }) | ||||
|             { | ||||
|                 return None; | ||||
|             } | ||||
|  | @ -85,6 +90,7 @@ impl T {} | |||
|   // ^ dyn
 | ||||
| impl T for (T) {} | ||||
|         // ^^^ dyn
 | ||||
| impl T | ||||
| "#,
 | ||||
|         ); | ||||
|     } | ||||
|  |  | |||
|  | @ -867,7 +867,7 @@ pub(crate) fn orig_range_with_focus_r( | |||
|             } | ||||
| 
 | ||||
|             // def site name
 | ||||
|             // FIXME: This can be de improved
 | ||||
|             // FIXME: This can be improved
 | ||||
|             Some((focus_range, _ctxt)) => { | ||||
|                 match value_range { | ||||
|                     // but overall node is in macro input
 | ||||
|  |  | |||
|  | @ -5,11 +5,11 @@ use ast::HasName; | |||
| use cfg::{CfgAtom, CfgExpr}; | ||||
| use hir::{ | ||||
|     AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics, | ||||
|     Symbol, db::HirDatabase, sym, symbols::FxIndexSet, | ||||
|     Symbol, db::HirDatabase, sym, | ||||
| }; | ||||
| use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; | ||||
| use ide_db::{ | ||||
|     FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind, | ||||
|     FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind, | ||||
|     base_db::RootQueryDb, | ||||
|     defs::Definition, | ||||
|     documentation::docs_from_attrs, | ||||
|  |  | |||
|  | @ -222,6 +222,7 @@ define_symbols! { | |||
|     fn_once_output, | ||||
|     fn_once, | ||||
|     async_fn_once, | ||||
|     async_fn_once_output, | ||||
|     async_fn_mut, | ||||
|     async_fn, | ||||
|     fn_ptr_addr, | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| //! for incorporating changes.
 | ||||
| // Note, don't remove any public api from this. This API is consumed by external tools
 | ||||
| // to run rust-analyzer as a library.
 | ||||
| use std::{collections::hash_map::Entry, mem, path::Path, sync}; | ||||
| use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; | ||||
| 
 | ||||
| use crossbeam_channel::{Receiver, unbounded}; | ||||
| use hir_expand::proc_macro::{ | ||||
|  | @ -512,6 +512,10 @@ impl ProcMacroExpander for Expander { | |||
|             Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { | ||||
|         (other as &dyn Any).downcast_ref::<Self>() == Some(self) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
|  |  | |||
|  | @ -197,6 +197,10 @@ fn invocation_fixtures( | |||
|                                         builder.push(tt::Leaf::Punct(*it)) | ||||
|                                     } | ||||
|                                 } | ||||
|                                 Separator::Lifetime(punct, ident) => { | ||||
|                                     builder.push(tt::Leaf::Punct(*punct)); | ||||
|                                     builder.push(tt::Leaf::Ident(ident.clone())); | ||||
|                                 } | ||||
|                             }; | ||||
|                         } | ||||
|                     } | ||||
|  |  | |||
|  | @ -823,7 +823,7 @@ fn match_meta_var<'t>( | |||
|                         "expected token tree", | ||||
|                     ) | ||||
|                 }), | ||||
|                 MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| { | ||||
|                 MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| { | ||||
|                     ExpandError::binding_error( | ||||
|                         span.unwrap_or(delim_span.close), | ||||
|                         "expected lifetime", | ||||
|  | @ -963,6 +963,10 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) -> | |||
|             } | ||||
|             Err(_) => false, | ||||
|         }, | ||||
|         Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) { | ||||
|             Ok(lifetime) => lifetime.sym == ident.sym, | ||||
|             Err(_) => false, | ||||
|         }, | ||||
|     }; | ||||
|     if ok { | ||||
|         *iter = fork; | ||||
|  | @ -983,13 +987,12 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> { | |||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> { | ||||
| fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> { | ||||
|     let punct = iter.expect_single_punct()?; | ||||
|     if punct.char != '\'' { | ||||
|         return Err(()); | ||||
|     } | ||||
|     iter.expect_ident_or_underscore()?; | ||||
|     Ok(()) | ||||
|     iter.expect_ident_or_underscore() | ||||
| } | ||||
| 
 | ||||
| fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) { | ||||
|  |  | |||
|  | @ -497,6 +497,10 @@ fn expand_repeat( | |||
|                         builder.push(tt::Leaf::from(punct)); | ||||
|                     } | ||||
|                 } | ||||
|                 Separator::Lifetime(punct, ident) => { | ||||
|                     builder.push(tt::Leaf::from(*punct)); | ||||
|                     builder.push(tt::Leaf::from(ident.clone())); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -155,6 +155,7 @@ pub(crate) enum Separator { | |||
|     Literal(tt::Literal<Span>), | ||||
|     Ident(tt::Ident<Span>), | ||||
|     Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>), | ||||
|     Lifetime(tt::Punct<Span>, tt::Ident<Span>), | ||||
| } | ||||
| 
 | ||||
| // Note that when we compare a Separator, we just care about its textual value.
 | ||||
|  | @ -170,6 +171,7 @@ impl PartialEq for Separator { | |||
|                 let b_iter = b.iter().map(|b| b.char); | ||||
|                 a_iter.eq(b_iter) | ||||
|             } | ||||
|             (Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
|  | @ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat | |||
|             _ => true, | ||||
|         }; | ||||
|         match tt { | ||||
|             tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { | ||||
|                 return Err(ParseError::InvalidRepeat); | ||||
|             tt::Leaf::Ident(ident) => match separator { | ||||
|                 Separator::Puncts(puncts) if puncts.is_empty() => { | ||||
|                     separator = Separator::Ident(ident.clone()); | ||||
|                 } | ||||
|             tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), | ||||
|                 Separator::Puncts(puncts) => match puncts.as_slice() { | ||||
|                     [tt::Punct { char: '\'', .. }] => { | ||||
|                         separator = Separator::Lifetime(puncts[0], ident.clone()); | ||||
|                     } | ||||
|                     _ => return Err(ParseError::InvalidRepeat), | ||||
|                 }, | ||||
|                 _ => return Err(ParseError::InvalidRepeat), | ||||
|             }, | ||||
|             tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat), | ||||
|             tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), | ||||
|             tt::Leaf::Punct(punct) => { | ||||
|                 let repeat_kind = match punct.char { | ||||
|  |  | |||
|  | @ -3,7 +3,9 @@ | |||
| // FIXME: Move more of the nameres independent tests from
 | ||||
| // crates\hir-def\src\macro_expansion_tests\mod.rs to this
 | ||||
| use expect_test::expect; | ||||
| use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext}; | ||||
| use span::{ | ||||
|     Edition, EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, | ||||
| }; | ||||
| use stdx::format_to; | ||||
| use tt::{TextRange, TextSize}; | ||||
| 
 | ||||
|  | @ -24,7 +26,7 @@ fn check_( | |||
|         def_edition, | ||||
|         SpanAnchor { | ||||
|             file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), | ||||
|             ast_id: ErasedFileAstId::from_raw(0), | ||||
|             ast_id: ROOT_ERASED_FILE_AST_ID, | ||||
|         }, | ||||
|         SyntaxContext::root(Edition::CURRENT), | ||||
|         decl, | ||||
|  | @ -37,7 +39,7 @@ fn check_( | |||
|     }; | ||||
|     let call_anchor = SpanAnchor { | ||||
|         file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), | ||||
|         ast_id: ErasedFileAstId::from_raw(0), | ||||
|         ast_id: ROOT_ERASED_FILE_AST_ID, | ||||
|     }; | ||||
|     let arg_tt = syntax_bridge::parse_to_token_tree( | ||||
|         call_edition, | ||||
|  | @ -110,8 +112,8 @@ fn unbalanced_brace() { | |||
| "#,
 | ||||
|         r#""#, | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..0#ROOT2024 1:0@0..0#ROOT2024 | ||||
|               SUBTREE {} 0:0@9..10#ROOT2024 0:0@11..12#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..0#ROOT2024 1:Root[0000, 0]@0..0#ROOT2024 | ||||
|               SUBTREE {} 0:Root[0000, 0]@9..10#ROOT2024 0:Root[0000, 0]@11..12#ROOT2024 | ||||
| 
 | ||||
|             {}"#]],
 | ||||
|     ); | ||||
|  | @ -133,25 +135,25 @@ fn token_mapping_smoke_test() { | |||
| struct MyTraitMap2 | ||||
| "#,
 | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..20#ROOT2024 1:0@0..20#ROOT2024 | ||||
|               IDENT   struct 0:0@34..40#ROOT2024 | ||||
|               IDENT   MyTraitMap2 1:0@8..19#ROOT2024 | ||||
|               SUBTREE {} 0:0@48..49#ROOT2024 0:0@100..101#ROOT2024 | ||||
|                 IDENT   map 0:0@58..61#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:0@61..62#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:0@63..64#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:0@64..65#ROOT2024 | ||||
|                 IDENT   std 0:0@65..68#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:0@68..69#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:0@69..70#ROOT2024 | ||||
|                 IDENT   collections 0:0@70..81#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:0@81..82#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:0@82..83#ROOT2024 | ||||
|                 IDENT   HashSet 0:0@83..90#ROOT2024 | ||||
|                 PUNCH   < [alone] 0:0@90..91#ROOT2024 | ||||
|                 SUBTREE () 0:0@91..92#ROOT2024 0:0@92..93#ROOT2024 | ||||
|                 PUNCH   > [joint] 0:0@93..94#ROOT2024 | ||||
|                 PUNCH   , [alone] 0:0@94..95#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..20#ROOT2024 1:Root[0000, 0]@0..20#ROOT2024 | ||||
|               IDENT   struct 0:Root[0000, 0]@34..40#ROOT2024 | ||||
|               IDENT   MyTraitMap2 1:Root[0000, 0]@8..19#ROOT2024 | ||||
|               SUBTREE {} 0:Root[0000, 0]@48..49#ROOT2024 0:Root[0000, 0]@100..101#ROOT2024 | ||||
|                 IDENT   map 0:Root[0000, 0]@58..61#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:Root[0000, 0]@61..62#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:Root[0000, 0]@63..64#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:Root[0000, 0]@64..65#ROOT2024 | ||||
|                 IDENT   std 0:Root[0000, 0]@65..68#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:Root[0000, 0]@68..69#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:Root[0000, 0]@69..70#ROOT2024 | ||||
|                 IDENT   collections 0:Root[0000, 0]@70..81#ROOT2024 | ||||
|                 PUNCH   : [joint] 0:Root[0000, 0]@81..82#ROOT2024 | ||||
|                 PUNCH   : [alone] 0:Root[0000, 0]@82..83#ROOT2024 | ||||
|                 IDENT   HashSet 0:Root[0000, 0]@83..90#ROOT2024 | ||||
|                 PUNCH   < [alone] 0:Root[0000, 0]@90..91#ROOT2024 | ||||
|                 SUBTREE () 0:Root[0000, 0]@91..92#ROOT2024 0:Root[0000, 0]@92..93#ROOT2024 | ||||
|                 PUNCH   > [joint] 0:Root[0000, 0]@93..94#ROOT2024 | ||||
|                 PUNCH   , [alone] 0:Root[0000, 0]@94..95#ROOT2024 | ||||
| 
 | ||||
|             struct MyTraitMap2 { | ||||
|                 map: ::std::collections::HashSet<()>, | ||||
|  | @ -180,28 +182,28 @@ fn main() { | |||
| } | ||||
| "#,
 | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..63#ROOT2024 1:0@0..63#ROOT2024 | ||||
|               IDENT   fn 1:0@1..3#ROOT2024 | ||||
|               IDENT   main 1:0@4..8#ROOT2024 | ||||
|               SUBTREE () 1:0@8..9#ROOT2024 1:0@9..10#ROOT2024 | ||||
|               SUBTREE {} 1:0@11..12#ROOT2024 1:0@61..62#ROOT2024 | ||||
|                 LITERAL Integer 1 1:0@17..18#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:0@18..19#ROOT2024 | ||||
|                 LITERAL Float 1.0 1:0@24..27#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:0@27..28#ROOT2024 | ||||
|                 SUBTREE () 1:0@33..34#ROOT2024 1:0@39..40#ROOT2024 | ||||
|                   SUBTREE () 1:0@34..35#ROOT2024 1:0@37..38#ROOT2024 | ||||
|                     LITERAL Integer 1 1:0@35..36#ROOT2024 | ||||
|                     PUNCH   , [alone] 1:0@36..37#ROOT2024 | ||||
|                   PUNCH   , [alone] 1:0@38..39#ROOT2024 | ||||
|                 PUNCH   . [alone] 1:0@40..41#ROOT2024 | ||||
|                 LITERAL Float 0.0 1:0@41..44#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:0@44..45#ROOT2024 | ||||
|                 IDENT   let 1:0@50..53#ROOT2024 | ||||
|                 IDENT   x 1:0@54..55#ROOT2024 | ||||
|                 PUNCH   = [alone] 1:0@56..57#ROOT2024 | ||||
|                 LITERAL Integer 1 1:0@58..59#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:0@59..60#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..63#ROOT2024 1:Root[0000, 0]@0..63#ROOT2024 | ||||
|               IDENT   fn 1:Root[0000, 0]@1..3#ROOT2024 | ||||
|               IDENT   main 1:Root[0000, 0]@4..8#ROOT2024 | ||||
|               SUBTREE () 1:Root[0000, 0]@8..9#ROOT2024 1:Root[0000, 0]@9..10#ROOT2024 | ||||
|               SUBTREE {} 1:Root[0000, 0]@11..12#ROOT2024 1:Root[0000, 0]@61..62#ROOT2024 | ||||
|                 LITERAL Integer 1 1:Root[0000, 0]@17..18#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:Root[0000, 0]@18..19#ROOT2024 | ||||
|                 LITERAL Float 1.0 1:Root[0000, 0]@24..27#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:Root[0000, 0]@27..28#ROOT2024 | ||||
|                 SUBTREE () 1:Root[0000, 0]@33..34#ROOT2024 1:Root[0000, 0]@39..40#ROOT2024 | ||||
|                   SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@37..38#ROOT2024 | ||||
|                     LITERAL Integer 1 1:Root[0000, 0]@35..36#ROOT2024 | ||||
|                     PUNCH   , [alone] 1:Root[0000, 0]@36..37#ROOT2024 | ||||
|                   PUNCH   , [alone] 1:Root[0000, 0]@38..39#ROOT2024 | ||||
|                 PUNCH   . [alone] 1:Root[0000, 0]@40..41#ROOT2024 | ||||
|                 LITERAL Float 0.0 1:Root[0000, 0]@41..44#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:Root[0000, 0]@44..45#ROOT2024 | ||||
|                 IDENT   let 1:Root[0000, 0]@50..53#ROOT2024 | ||||
|                 IDENT   x 1:Root[0000, 0]@54..55#ROOT2024 | ||||
|                 PUNCH   = [alone] 1:Root[0000, 0]@56..57#ROOT2024 | ||||
|                 LITERAL Integer 1 1:Root[0000, 0]@58..59#ROOT2024 | ||||
|                 PUNCH   ; [alone] 1:Root[0000, 0]@59..60#ROOT2024 | ||||
| 
 | ||||
|             fn main(){ | ||||
|                 1; | ||||
|  | @ -227,14 +229,14 @@ fn expr_2021() { | |||
|     const { 1 }, | ||||
| "#,
 | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..25#ROOT2024 1:0@0..25#ROOT2024 | ||||
|               IDENT   _ 1:0@5..6#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:0@36..37#ROOT2024 | ||||
|               SUBTREE () 0:0@34..35#ROOT2024 0:0@34..35#ROOT2024 | ||||
|                 IDENT   const 1:0@12..17#ROOT2024 | ||||
|                 SUBTREE {} 1:0@18..19#ROOT2024 1:0@22..23#ROOT2024 | ||||
|                   LITERAL Integer 1 1:0@20..21#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:0@39..40#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..25#ROOT2024 1:Root[0000, 0]@0..25#ROOT2024 | ||||
|               IDENT   _ 1:Root[0000, 0]@5..6#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:Root[0000, 0]@36..37#ROOT2024 | ||||
|               SUBTREE () 0:Root[0000, 0]@34..35#ROOT2024 0:Root[0000, 0]@34..35#ROOT2024 | ||||
|                 IDENT   const 1:Root[0000, 0]@12..17#ROOT2024 | ||||
|                 SUBTREE {} 1:Root[0000, 0]@18..19#ROOT2024 1:Root[0000, 0]@22..23#ROOT2024 | ||||
|                   LITERAL Integer 1 1:Root[0000, 0]@20..21#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024 | ||||
| 
 | ||||
|             _; | ||||
|             (const  { | ||||
|  | @ -255,13 +257,13 @@ fn expr_2021() { | |||
|         expect![[r#" | ||||
|             ExpandError { | ||||
|                 inner: ( | ||||
|                     1:0@5..6#ROOT2024, | ||||
|                     1:Root[0000, 0]@5..6#ROOT2024, | ||||
|                     NoMatchingRule, | ||||
|                 ), | ||||
|             } | ||||
| 
 | ||||
|             SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:0@39..40#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024 | ||||
| 
 | ||||
|             ;"#]],
 | ||||
|     ); | ||||
|  | @ -279,13 +281,13 @@ fn expr_2021() { | |||
|         expect![[r#" | ||||
|             ExpandError { | ||||
|                 inner: ( | ||||
|                     1:0@5..10#ROOT2024, | ||||
|                     1:Root[0000, 0]@5..10#ROOT2024, | ||||
|                     NoMatchingRule, | ||||
|                 ), | ||||
|             } | ||||
| 
 | ||||
|             SUBTREE $$ 1:0@0..18#ROOT2024 1:0@0..18#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:0@39..40#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..18#ROOT2024 1:Root[0000, 0]@0..18#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024 | ||||
| 
 | ||||
|             ;"#]],
 | ||||
|     ); | ||||
|  | @ -305,26 +307,26 @@ fn expr_2021() { | |||
|     break 'foo bar, | ||||
| "#,
 | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..76#ROOT2024 1:0@0..76#ROOT2024 | ||||
|               LITERAL Integer 4 1:0@5..6#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:0@41..42#ROOT2024 | ||||
|               LITERAL Str literal 1:0@12..21#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:0@41..42#ROOT2024 | ||||
|               SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 | ||||
|                 IDENT   funcall 1:0@27..34#ROOT2024 | ||||
|                 SUBTREE () 1:0@34..35#ROOT2024 1:0@35..36#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:0@41..42#ROOT2024 | ||||
|               SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 | ||||
|                 IDENT   future 1:0@42..48#ROOT2024 | ||||
|                 PUNCH   . [alone] 1:0@48..49#ROOT2024 | ||||
|                 IDENT   await 1:0@49..54#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:0@41..42#ROOT2024 | ||||
|               SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 | ||||
|                 IDENT   break 1:0@60..65#ROOT2024 | ||||
|                 PUNCH   ' [joint] 1:0@66..67#ROOT2024 | ||||
|                 IDENT   foo 1:0@67..70#ROOT2024 | ||||
|                 IDENT   bar 1:0@71..74#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:0@44..45#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..76#ROOT2024 1:Root[0000, 0]@0..76#ROOT2024 | ||||
|               LITERAL Integer 4 1:Root[0000, 0]@5..6#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024 | ||||
|               LITERAL Str literal 1:Root[0000, 0]@12..21#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024 | ||||
|               SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024 | ||||
|                 IDENT   funcall 1:Root[0000, 0]@27..34#ROOT2024 | ||||
|                 SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@35..36#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024 | ||||
|               SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024 | ||||
|                 IDENT   future 1:Root[0000, 0]@42..48#ROOT2024 | ||||
|                 PUNCH   . [alone] 1:Root[0000, 0]@48..49#ROOT2024 | ||||
|                 IDENT   await 1:Root[0000, 0]@49..54#ROOT2024 | ||||
|               PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024 | ||||
|               SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024 | ||||
|                 IDENT   break 1:Root[0000, 0]@60..65#ROOT2024 | ||||
|                 PUNCH   ' [joint] 1:Root[0000, 0]@66..67#ROOT2024 | ||||
|                 IDENT   foo 1:Root[0000, 0]@67..70#ROOT2024 | ||||
|                 IDENT   bar 1:Root[0000, 0]@71..74#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:Root[0000, 0]@44..45#ROOT2024 | ||||
| 
 | ||||
|             4; | ||||
|             "literal"; | ||||
|  | @ -346,13 +348,13 @@ fn expr_2021() { | |||
|         expect![[r#" | ||||
|             ExpandError { | ||||
|                 inner: ( | ||||
|                     1:0@5..6#ROOT2024, | ||||
|                     1:Root[0000, 0]@5..6#ROOT2024, | ||||
|                     NoMatchingRule, | ||||
|                 ), | ||||
|             } | ||||
| 
 | ||||
|             SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:0@44..45#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024 | ||||
|               PUNCH   ; [alone] 0:Root[0000, 0]@44..45#ROOT2024 | ||||
| 
 | ||||
|             ;"#]],
 | ||||
|     ); | ||||
|  | @ -370,88 +372,88 @@ fn minus_belongs_to_literal() { | |||
|     check( | ||||
|         "-1", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@10..11#ROOT2024 | ||||
|               LITERAL Integer 1 0:0@11..12#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@10..11#ROOT2024 | ||||
|               LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024 | ||||
| 
 | ||||
|             -1"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "- 1", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@10..11#ROOT2024 | ||||
|               LITERAL Integer 1 0:0@11..12#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@10..11#ROOT2024 | ||||
|               LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024 | ||||
| 
 | ||||
|             -1"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "-2", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@25..26#ROOT2024 | ||||
|               LITERAL Integer 2 0:0@27..28#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@25..26#ROOT2024 | ||||
|               LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024 | ||||
| 
 | ||||
|             -2"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "- 2", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@25..26#ROOT2024 | ||||
|               LITERAL Integer 2 0:0@27..28#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@25..26#ROOT2024 | ||||
|               LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024 | ||||
| 
 | ||||
|             -2"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "-3.0", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@43..44#ROOT2024 | ||||
|               LITERAL Float 3.0 0:0@45..48#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@43..44#ROOT2024 | ||||
|               LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024 | ||||
| 
 | ||||
|             -3.0"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "- 3.0", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024 | ||||
|               PUNCH   - [alone] 0:0@43..44#ROOT2024 | ||||
|               LITERAL Float 3.0 0:0@45..48#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024 | ||||
|               PUNCH   - [alone] 0:Root[0000, 0]@43..44#ROOT2024 | ||||
|               LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024 | ||||
| 
 | ||||
|             -3.0"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "@1", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024 | ||||
|               LITERAL Integer 1 1:0@1..2#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024 | ||||
|               LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024 | ||||
| 
 | ||||
|             1"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "@-1", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 1:0@1..2#ROOT2024 | ||||
|               LITERAL Integer 1 1:0@2..3#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024 | ||||
|               PUNCH   - [alone] 1:Root[0000, 0]@1..2#ROOT2024 | ||||
|               LITERAL Integer 1 1:Root[0000, 0]@2..3#ROOT2024 | ||||
| 
 | ||||
|             -1"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "@1.0", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024 | ||||
|               LITERAL Float 1.0 1:0@1..4#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024 | ||||
|               LITERAL Float 1.0 1:Root[0000, 0]@1..4#ROOT2024 | ||||
| 
 | ||||
|             1.0"#]],
 | ||||
|     ); | ||||
|     check( | ||||
|         "@-1.0", | ||||
|         expect![[r#" | ||||
|             SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024 | ||||
|               PUNCH   - [alone] 1:0@1..2#ROOT2024 | ||||
|               LITERAL Float 1.0 1:0@2..5#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024 | ||||
|               PUNCH   - [alone] 1:Root[0000, 0]@1..2#ROOT2024 | ||||
|               LITERAL Float 1.0 1:Root[0000, 0]@2..5#ROOT2024 | ||||
| 
 | ||||
|             -1.0"#]],
 | ||||
|     ); | ||||
|  | @ -460,16 +462,16 @@ fn minus_belongs_to_literal() { | |||
|         expect![[r#" | ||||
|             ExpandError { | ||||
|                 inner: ( | ||||
|                     1:0@1..2#ROOT2024, | ||||
|                     1:Root[0000, 0]@1..2#ROOT2024, | ||||
|                     BindingError( | ||||
|                         "expected literal", | ||||
|                     ), | ||||
|                 ), | ||||
|             } | ||||
| 
 | ||||
|             SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024 | ||||
|               PUNCH   - [joint] 1:0@1..2#ROOT2024 | ||||
|               PUNCH   - [alone] 1:0@2..3#ROOT2024 | ||||
|             SUBTREE $$ 1:Root[0000, 0]@0..6#ROOT2024 1:Root[0000, 0]@0..6#ROOT2024 | ||||
|               PUNCH   - [joint] 1:Root[0000, 0]@1..2#ROOT2024 | ||||
|               PUNCH   - [alone] 1:Root[0000, 0]@2..3#ROOT2024 | ||||
| 
 | ||||
|             --"#]],
 | ||||
|     ); | ||||
|  |  | |||
|  | @ -22,9 +22,10 @@ pub const HAS_GLOBAL_SPANS: u32 = 3; | |||
| pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4; | ||||
| /// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field.
 | ||||
| pub const EXTENDED_LEAF_DATA: u32 = 5; | ||||
| pub const HASHED_AST_ID: u32 = 6; | ||||
| 
 | ||||
| /// Current API version of the proc-macro protocol.
 | ||||
| pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA; | ||||
| pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID; | ||||
| 
 | ||||
| /// Represents requests sent from the client to the proc-macro-srv.
 | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
|  | @ -201,7 +202,9 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) | |||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use intern::{Symbol, sym}; | ||||
|     use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TextSize}; | ||||
|     use span::{ | ||||
|         Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize, | ||||
|     }; | ||||
|     use tt::{ | ||||
|         Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree, | ||||
|         TopSubtreeBuilder, | ||||
|  | @ -215,7 +218,7 @@ mod tests { | |||
|                 span::FileId::from_raw(0xe4e4e), | ||||
|                 span::Edition::CURRENT, | ||||
|             ), | ||||
|             ast_id: ErasedFileAstId::from_raw(0), | ||||
|             ast_id: ROOT_ERASED_FILE_AST_ID, | ||||
|         }; | ||||
| 
 | ||||
|         let mut builder = TopSubtreeBuilder::new(Delimiter { | ||||
|  |  | |||
|  | @ -12,13 +12,13 @@ pub mod legacy_protocol { | |||
| mod process; | ||||
| 
 | ||||
| use paths::{AbsPath, AbsPathBuf}; | ||||
| use span::Span; | ||||
| use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; | ||||
| use std::{fmt, io, sync::Arc, time::SystemTime}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     legacy_protocol::msg::{ | ||||
|         ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, PanicMessage, | ||||
|         RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap, | ||||
|         ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, HASHED_AST_ID, | ||||
|         PanicMessage, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap, | ||||
|         deserialize_span_data_index_map, flat::serialize_span_data_index_map, | ||||
|     }, | ||||
|     process::ProcMacroServerProcess, | ||||
|  | @ -161,6 +161,38 @@ impl ProcMacro { | |||
|         self.kind | ||||
|     } | ||||
| 
 | ||||
|     fn needs_fixup_change(&self) -> bool { | ||||
|         let version = self.process.version(); | ||||
|         (RUST_ANALYZER_SPAN_SUPPORT..HASHED_AST_ID).contains(&version) | ||||
|     } | ||||
| 
 | ||||
|     /// On some server versions, the fixup ast id is different than ours. So change it to match.
 | ||||
|     fn change_fixup_to_match_old_server(&self, tt: &mut tt::TopSubtree<Span>) { | ||||
|         const OLD_FIXUP_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(!0 - 1); | ||||
|         let change_ast_id = |ast_id: &mut ErasedFileAstId| { | ||||
|             if *ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { | ||||
|                 *ast_id = OLD_FIXUP_AST_ID; | ||||
|             } else if *ast_id == OLD_FIXUP_AST_ID { | ||||
|                 // Swap between them, that means no collision plus the change can be reversed by doing itself.
 | ||||
|                 *ast_id = FIXUP_ERASED_FILE_AST_ID_MARKER; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         for tt in &mut tt.0 { | ||||
|             match tt { | ||||
|                 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { span, .. })) | ||||
|                 | tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { span, .. })) | ||||
|                 | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { span, .. })) => { | ||||
|                     change_ast_id(&mut span.anchor.ast_id); | ||||
|                 } | ||||
|                 tt::TokenTree::Subtree(subtree) => { | ||||
|                     change_ast_id(&mut subtree.delimiter.open.anchor.ast_id); | ||||
|                     change_ast_id(&mut subtree.delimiter.close.anchor.ast_id); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Expands the procedural macro by sending an expansion request to the server.
 | ||||
|     /// This includes span information and environmental context.
 | ||||
|     pub fn expand( | ||||
|  | @ -173,6 +205,20 @@ impl ProcMacro { | |||
|         mixed_site: Span, | ||||
|         current_dir: String, | ||||
|     ) -> Result<Result<tt::TopSubtree<Span>, PanicMessage>, ServerError> { | ||||
|         let (mut subtree, mut attr) = (subtree, attr); | ||||
|         let (mut subtree_changed, mut attr_changed); | ||||
|         if self.needs_fixup_change() { | ||||
|             subtree_changed = tt::TopSubtree::from_subtree(subtree); | ||||
|             self.change_fixup_to_match_old_server(&mut subtree_changed); | ||||
|             subtree = subtree_changed.view(); | ||||
| 
 | ||||
|             if let Some(attr) = &mut attr { | ||||
|                 attr_changed = tt::TopSubtree::from_subtree(*attr); | ||||
|                 self.change_fixup_to_match_old_server(&mut attr_changed); | ||||
|                 *attr = attr_changed.view(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let version = self.process.version(); | ||||
| 
 | ||||
|         let mut span_data_table = SpanDataIndexMap::default(); | ||||
|  | @ -205,15 +251,23 @@ impl ProcMacro { | |||
|         let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?; | ||||
| 
 | ||||
|         match response { | ||||
|             Response::ExpandMacro(it) => { | ||||
|                 Ok(it.map(|tree| FlatTree::to_subtree_resolved(tree, version, &span_data_table))) | ||||
|             Response::ExpandMacro(it) => Ok(it.map(|tree| { | ||||
|                 let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); | ||||
|                 if self.needs_fixup_change() { | ||||
|                     self.change_fixup_to_match_old_server(&mut expanded); | ||||
|                 } | ||||
|                 expanded | ||||
|             })), | ||||
|             Response::ExpandMacroExtended(it) => Ok(it.map(|resp| { | ||||
|                 FlatTree::to_subtree_resolved( | ||||
|                 let mut expanded = FlatTree::to_subtree_resolved( | ||||
|                     resp.tree, | ||||
|                     version, | ||||
|                     &deserialize_span_data_index_map(&resp.span_data_table), | ||||
|                 ) | ||||
|                 ); | ||||
|                 if self.needs_fixup_change() { | ||||
|                     self.change_fixup_to_match_old_server(&mut expanded); | ||||
|                 } | ||||
|                 expanded | ||||
|             })), | ||||
|             _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), | ||||
|         } | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bors
						bors