diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 85c0542ad3d..c91a5497262 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -28,7 +28,8 @@ use crate::{ lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AttrDefId, GenericParamId, ItemTreeLoc, LocalFieldId, Lookup, MacroId, VariantId, + AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, + VariantId, }; /// Desugared attributes of an item post `cfg_attr` expansion. diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index 5efa3e8d9e0..ba7d06272af 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -6,6 +6,7 @@ use either::Either; use hir_expand::{attrs::collect_attrs, HirFileId}; +use syntax::ast; use crate::{ db::DefDatabase, @@ -17,8 +18,9 @@ use crate::{ item_tree::ItemTreeNode, nameres::DefMap, src::{HasChildSource, HasSource}, - AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, ImplId, ItemTreeLoc, Lookup, MacroId, - ModuleDefId, ModuleId, TraitId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc, + LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId, + VariantId, }; pub trait ChildBySource { @@ -59,14 +61,6 @@ impl ChildBySource for ImplId { } } -fn add_assoc_item(db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId, item: AssocItemId) { - match item { - AssocItemId::FunctionId(func) => insert_item_loc(db, res, file_id, func, keys::FUNCTION), - AssocItemId::ConstId(konst) => insert_item_loc(db, res, file_id, konst, keys::CONST), - AssocItemId::TypeAliasId(ty) => insert_item_loc(db, res, file_id, ty, keys::TYPE_ALIAS), - } -} - impl ChildBySource for ModuleId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let def_map = self.def_map(db); @@ -118,14 +112,6 @@ impl ChildBySource for ItemScope { file_id: HirFileId, item: ModuleDefId, ) { - macro_rules! insert { - ($map:ident[$key:path].$insert:ident($id:ident)) => {{ - let loc = $id.lookup(db); - if loc.id.file_id() == file_id { - $map[$key].$insert(loc.source(db).value, $id) - } - }}; - } match item { ModuleDefId::FunctionId(id) => { insert_item_loc(db, map, file_id, id, keys::FUNCTION) @@ -145,9 +131,13 @@ impl ChildBySource for ItemScope { AdtId::EnumId(id) => insert_item_loc(db, map, file_id, id, keys::ENUM), }, ModuleDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => insert!(map[keys::MACRO2].insert(id)), - MacroId::MacroRulesId(id) => insert!(map[keys::MACRO_RULES].insert(id)), - MacroId::ProcMacroId(id) => insert!(map[keys::PROC_MACRO].insert(id)), + MacroId::Macro2Id(id) => insert_item_loc(db, map, file_id, id, keys::MACRO2), + MacroId::MacroRulesId(id) => { + insert_item_loc(db, map, file_id, id, keys::MACRO_RULES) + } + MacroId::ProcMacroId(id) => { + insert_item_loc(db, map, file_id, id, keys::PROC_MACRO) + } }, ModuleDefId::ModuleId(_) | ModuleDefId::EnumVariantId(_) @@ -207,6 +197,40 @@ impl ChildBySource for DefWithBodyId { } } +impl ChildBySource for GenericDefId { + fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { + let (gfile_id, generic_params_list) = self.file_id_and_params_of(db); + if gfile_id != file_id { + return; + } + + let generic_params = db.generic_params(*self); + let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); + let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); + + // For traits the first type index is `Self`, skip it. + if let GenericDefId::TraitId(_) = *self { + toc_idx_iter.next().unwrap(); // advance_by(1); + } + + if let Some(generic_params_list) = generic_params_list { + for (local_id, ast_param) in + toc_idx_iter.zip(generic_params_list.type_or_const_params()) + { + let id = TypeOrConstParamId { parent: *self, local_id }; + match ast_param { + ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id), + ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id), + } + } + for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) { + let id = LifetimeParamId { parent: *self, local_id }; + res[keys::LIFETIME_PARAM].insert(ast_param, id); + } + } + } +} + fn insert_item_loc( db: &dyn DefDatabase, res: &mut DynMap, @@ -224,3 +248,11 @@ fn insert_item_loc( res[key].insert(loc.source(db).value, id) } } + +fn add_assoc_item(db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId, item: AssocItemId) { + match item { + AssocItemId::FunctionId(func) => insert_item_loc(db, res, file_id, func, keys::FUNCTION), + AssocItemId::ConstId(konst) => insert_item_loc(db, res, file_id, konst, keys::CONST), + AssocItemId::TypeAliasId(ty) => insert_item_loc(db, res, file_id, ty, keys::TYPE_ALIAS), + } +} diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 5986b7df3d9..540f643ae7d 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -10,7 +10,7 @@ use hir_expand::{ HirFileId, InFile, }; use intern::Interned; -use la_arena::{Arena, ArenaMap}; +use la_arena::Arena; use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use syntax::ast::{self, HasName, HasVisibility}; use triomphe::Arc; @@ -22,13 +22,11 @@ use crate::{ lang_item::LangItem, lower::LowerCtx, nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, - src::HasChildSource, - src::HasSource, trace::Trace, tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, type_ref::TypeRef, visibility::RawVisibility, - EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, + EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, }; /// Note that we use `StructData` for unions as well! @@ -387,46 +385,6 @@ impl VariantData { } } -impl HasChildSource for VariantId { - type Value = Either; - - fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - let item_tree; - let (src, fields, 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()), - &item_tree[lookup.id.value].fields, - 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()), - &item_tree[lookup.id.value].fields, - lookup.container, - ) - } - VariantId::UnionId(it) => { - let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - &item_tree[lookup.id.value].fields, - lookup.container, - ) - } - }; - let mut trace = Trace::new_for_map(); - lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields); - src.with_value(trace.into_map()) - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum StructKind { Tuple, @@ -434,7 +392,7 @@ pub enum StructKind { Unit, } -fn lower_struct( +pub(crate) fn lower_struct( db: &dyn DefDatabase, trace: &mut Trace>, ast: &InFile, diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 0edd5e61688..1d2c7c3a55f 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -3,31 +3,27 @@ //! generic parameters. See also the `Generics` type and the `generics_of` query //! in rustc. -use base_db::FileId; use either::Either; use hir_expand::{ name::{AsName, Name}, - ExpandResult, HirFileId, InFile, + ExpandResult, }; use intern::Interned; -use la_arena::{Arena, ArenaMap, Idx}; +use la_arena::{Arena, Idx}; use once_cell::unsync::Lazy; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use triomphe::Arc; use crate::{ - child_by_source::ChildBySource, db::DefDatabase, - dyn_map::{keys, DynMap}, expander::Expander, - item_tree::ItemTree, + item_tree::{GenericsItemTreeNode, ItemTree}, lower::LowerCtx, nameres::{DefMap, MacroSubNs}, - src::{HasChildSource, HasSource}, type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, - AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, - LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, + AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LocalTypeOrConstParamId, Lookup, + TypeOrConstParamId, TypeParamId, }; /// Data about a generic type parameter (to a function, struct, impl, ...). @@ -418,13 +414,18 @@ impl GenericParams { }) } }; - macro_rules! id_to_generics { - ($id:ident) => {{ - let id = $id.lookup(db).id; - let tree = id.item_tree(db); - let item = &tree[id.value]; - enabled_params(&item.generic_params, &tree) - }}; + fn id_to_generics( + db: &dyn DefDatabase, + id: impl for<'db> Lookup< + Database<'db> = dyn DefDatabase + 'db, + Data = impl ItemTreeLoc, + >, + enabled_params: impl Fn(&Interned, &ItemTree) -> Interned, + ) -> Interned { + let id = id.lookup(db).item_tree_id(); + let tree = id.item_tree(db); + let item = &tree[id.value]; + enabled_params(item.generic_params(), &tree) } match def { @@ -457,13 +458,13 @@ impl GenericParams { Interned::new(generic_params.finish()) } } - GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id), - GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id), - GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id), - GenericDefId::TraitId(id) => id_to_generics!(id), - GenericDefId::TraitAliasId(id) => id_to_generics!(id), - GenericDefId::TypeAliasId(id) => id_to_generics!(id), - GenericDefId::ImplId(id) => id_to_generics!(id), + GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params), GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { Interned::new(GenericParams { type_or_consts: Default::default(), @@ -507,130 +508,3 @@ impl GenericParams { }) } } - -fn file_id_and_params_of( - db: &dyn DefDatabase, - def: GenericDefId, -) -> (HirFileId, Option) { - match def { - GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None), - GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it), - GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it), - GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it), - 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), - // We won't be using this ID anyway - GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None), - } -} - -fn file_id_and_params_of_item_loc( - db: &dyn DefDatabase, - def: impl for<'db> Lookup = dyn DefDatabase + 'db, Data = Loc>, -) -> (HirFileId, Option) -where - Loc: HasSource, - Loc::Value: HasGenericParams, -{ - let src = def.lookup(db).source(db); - (src.file_id, src.value.generic_param_list()) -} - -impl HasChildSource for GenericDefId { - type Value = Either; - fn child_source( - &self, - db: &dyn DefDatabase, - ) -> InFile> { - let generic_params = db.generic_params(*self); - let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); - - let (file_id, generic_params_list) = file_id_and_params_of(db, *self); - - let mut params = ArenaMap::default(); - - // For traits and trait aliases the first type index is `Self`, we need to add it before - // the other params. - match *self { - GenericDefId::TraitId(id) => { - let trait_ref = id.lookup(db).source(db).value; - let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref))); - } - GenericDefId::TraitAliasId(id) => { - let alias = id.lookup(db).source(db).value; - let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias))); - } - _ => {} - } - - if let Some(generic_params_list) = generic_params_list { - for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) { - params.insert(idx, Either::Left(ast_param)); - } - } - - InFile::new(file_id, params) - } -} - -impl HasChildSource for GenericDefId { - type Value = ast::LifetimeParam; - fn child_source( - &self, - db: &dyn DefDatabase, - ) -> InFile> { - let generic_params = db.generic_params(*self); - let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); - - let (file_id, generic_params_list) = file_id_and_params_of(db, *self); - - let mut params = ArenaMap::default(); - - if let Some(generic_params_list) = generic_params_list { - for (idx, ast_param) in idx_iter.zip(generic_params_list.lifetime_params()) { - params.insert(idx, ast_param); - } - } - - InFile::new(file_id, params) - } -} - -impl ChildBySource for GenericDefId { - fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let (gfile_id, generic_params_list) = file_id_and_params_of(db, *self); - if gfile_id != file_id { - return; - } - - let generic_params = db.generic_params(*self); - let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); - let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); - - // For traits the first type index is `Self`, skip it. - if let GenericDefId::TraitId(_) = *self { - toc_idx_iter.next().unwrap(); // advance_by(1); - } - - if let Some(generic_params_list) = generic_params_list { - for (local_id, ast_param) in - toc_idx_iter.zip(generic_params_list.type_or_const_params()) - { - let id = TypeOrConstParamId { parent: *self, local_id }; - match ast_param { - ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id), - ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id), - } - } - for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) { - let id = LifetimeParamId { parent: *self, local_id }; - res[keys::LIFETIME_PARAM].insert(ast_param, id); - } - } - } -} diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 96b606ec1db..be16a5e31a2 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -347,6 +347,9 @@ pub trait ItemTreeNode: Clone { fn lookup(tree: &ItemTree, index: Idx) -> &Self; fn attr_owner(id: FileItemTreeId) -> AttrOwner; } +pub trait GenericsItemTreeNode: ItemTreeNode { + fn generic_params(&self) -> &Interned; +} pub struct FileItemTreeId(Idx); @@ -473,7 +476,7 @@ impl Hash for ItemTreeId { } macro_rules! mod_items { - ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { + ( $( $typ:ident $(<$generic_params:ident>)? in $fld:ident -> $ast:ty ),+ $(,)? ) => { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ModItem { $( @@ -513,6 +516,14 @@ macro_rules! mod_items { &self.data().$fld[index] } } + + $( + impl GenericsItemTreeNode for $typ { + fn generic_params(&self) -> &Interned { + &self.$generic_params + } + } + )? )+ }; } @@ -521,16 +532,16 @@ mod_items! { Use in uses -> ast::Use, ExternCrate in extern_crates -> ast::ExternCrate, ExternBlock in extern_blocks -> ast::ExternBlock, - Function in functions -> ast::Fn, - Struct in structs -> ast::Struct, - Union in unions -> ast::Union, - Enum in enums -> ast::Enum, + Function in functions -> ast::Fn, + Struct in structs -> ast::Struct, + Union in unions -> ast::Union, + Enum in enums -> ast::Enum, Const in consts -> ast::Const, Static in statics -> ast::Static, - Trait in traits -> ast::Trait, - TraitAlias in trait_aliases -> ast::TraitAlias, - Impl in impls -> ast::Impl, - TypeAlias in type_aliases -> ast::TypeAlias, + Trait in traits -> ast::Trait, + TraitAlias in trait_aliases -> ast::TraitAlias, + Impl in impls -> ast::Impl, + TypeAlias in type_aliases -> ast::TypeAlias, Mod in mods -> ast::Module, MacroCall in macro_calls -> ast::MacroCall, MacroRules in macro_rules -> ast::MacroRules, diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 1cc81589094..e0aa3ae6123 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -658,7 +658,7 @@ impl<'a> Ctx<'a> { fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId { let vis = - RawVisibility::from_ast_with_span_map(self.db, item.visibility(), self.span_map()); + RawVisibility::from_opt_ast_with_span_map(self.db, item.visibility(), self.span_map()); self.data().vis.alloc(vis) } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index df1f61ae5ff..589e57cb6b7 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -87,7 +87,7 @@ use hir_expand::{ use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; -use span::Span; +use span::{FileId, Span}; use stdx::impl_from; use syntax::{ast, AstNode}; @@ -103,114 +103,6 @@ use crate::{ }, }; -/// A `ModuleId` that is always a crate's root module. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct CrateRootModuleId { - krate: CrateId, -} - -impl CrateRootModuleId { - pub fn def_map(&self, db: &dyn DefDatabase) -> Arc { - db.crate_def_map(self.krate) - } - - pub fn krate(self) -> CrateId { - self.krate - } -} - -impl PartialEq for CrateRootModuleId { - fn eq(&self, other: &ModuleId) -> bool { - other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate - } -} -impl PartialEq for ModuleId { - fn eq(&self, other: &CrateRootModuleId) -> bool { - other == self - } -} - -impl From for ModuleId { - fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { - ModuleId { krate, block: None, local_id: DefMap::ROOT } - } -} - -impl From for ModuleDefId { - fn from(value: CrateRootModuleId) -> Self { - ModuleDefId::ModuleId(value.into()) - } -} - -impl From for CrateRootModuleId { - fn from(krate: CrateId) -> Self { - CrateRootModuleId { krate } - } -} - -impl TryFrom for CrateRootModuleId { - type Error = (); - - fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result { - if block.is_none() && local_id == DefMap::ROOT { - Ok(CrateRootModuleId { krate }) - } else { - Err(()) - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ModuleId { - krate: CrateId, - /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the - /// `BlockId` of that block expression. If `None`, this module is part of the crate-level - /// `DefMap` of `krate`. - block: Option, - /// The module's ID in its originating `DefMap`. - pub local_id: LocalModuleId, -} - -impl ModuleId { - pub fn def_map(self, db: &dyn DefDatabase) -> Arc { - match self.block { - Some(block) => db.block_def_map(block), - None => db.crate_def_map(self.krate), - } - } - - pub fn krate(self) -> CrateId { - self.krate - } - - pub fn name(self, db: &dyn DefDatabase) -> Option { - let def_map = self.def_map(db); - let parent = def_map[self.local_id].parent?; - def_map[parent].children.iter().find_map(|(name, module_id)| { - if *module_id == self.local_id { - Some(name.clone()) - } else { - None - } - }) - } - - pub fn containing_module(self, db: &dyn DefDatabase) -> Option { - self.def_map(db).containing_module(self.local_id) - } - - pub fn containing_block(self) -> Option { - self.block - } - - pub fn is_block_module(self) -> bool { - self.block.is_some() && self.local_id == DefMap::ROOT - } -} - -/// An ID of a module, **local** to a `DefMap`. -pub type LocalModuleId = Idx; - #[derive(Debug)] pub struct ItemLoc { pub container: ModuleId, @@ -322,35 +214,6 @@ pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); impl_loc!(EnumLoc, id: Enum, container: ModuleId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EnumVariantId(salsa::InternId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EnumVariantLoc { - pub id: ItemTreeId, - pub parent: EnumId, - pub index: u32, -} -impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant); -impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct FieldId { - pub parent: VariantId, - pub local_id: LocalFieldId, -} - -pub type LocalFieldId = Idx; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TupleId(pub u32); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TupleFieldId { - pub tuple: TupleId, - pub index: u32, -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); type ConstLoc = AssocItemLoc; @@ -406,13 +269,16 @@ impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_e impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroExpander { - Declarative, - BuiltIn(BuiltinFnLikeExpander), - BuiltInAttr(BuiltinAttrExpander), - BuiltInDerive(BuiltinDeriveExpander), - BuiltInEager(EagerExpander), +pub struct EnumVariantId(salsa::InternId); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumVariantLoc { + pub id: ItemTreeId, + pub parent: EnumId, + pub index: u32, } +impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant); +impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct Macro2Id(salsa::InternId); @@ -448,6 +314,14 @@ bitflags::bitflags! { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MacroExpander { + Declarative, + BuiltIn(BuiltinFnLikeExpander), + BuiltInAttr(BuiltinAttrExpander), + BuiltInDerive(BuiltinDeriveExpander), + BuiltInEager(EagerExpander), +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ProcMacroId(salsa::InternId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -471,6 +345,146 @@ pub struct BlockLoc { } impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); +/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and +/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct ConstBlockId(salsa::InternId); +impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const); + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct ConstBlockLoc { + /// The parent of the anonymous const block. + pub parent: DefWithBodyId, + /// The root expression of this const block in the parent body. + pub root: hir::ExprId, +} + +/// A `ModuleId` that is always a crate's root module. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct CrateRootModuleId { + krate: CrateId, +} + +impl CrateRootModuleId { + pub fn def_map(&self, db: &dyn DefDatabase) -> Arc { + db.crate_def_map(self.krate) + } + + pub fn krate(self) -> CrateId { + self.krate + } +} + +impl PartialEq for CrateRootModuleId { + fn eq(&self, other: &ModuleId) -> bool { + other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate + } +} + +impl From for CrateRootModuleId { + fn from(krate: CrateId) -> Self { + CrateRootModuleId { krate } + } +} + +impl TryFrom for CrateRootModuleId { + type Error = (); + + fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result { + if block.is_none() && local_id == DefMap::ROOT { + Ok(CrateRootModuleId { krate }) + } else { + Err(()) + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ModuleId { + krate: CrateId, + /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the + /// `BlockId` of that block expression. If `None`, this module is part of the crate-level + /// `DefMap` of `krate`. + block: Option, + /// The module's ID in its originating `DefMap`. + pub local_id: LocalModuleId, +} + +impl ModuleId { + pub fn def_map(self, db: &dyn DefDatabase) -> Arc { + match self.block { + Some(block) => db.block_def_map(block), + None => db.crate_def_map(self.krate), + } + } + + pub fn krate(self) -> CrateId { + self.krate + } + + pub fn name(self, db: &dyn DefDatabase) -> Option { + let def_map = self.def_map(db); + let parent = def_map[self.local_id].parent?; + def_map[parent].children.iter().find_map(|(name, module_id)| { + if *module_id == self.local_id { + Some(name.clone()) + } else { + None + } + }) + } + + pub fn containing_module(self, db: &dyn DefDatabase) -> Option { + self.def_map(db).containing_module(self.local_id) + } + + pub fn containing_block(self) -> Option { + self.block + } + + pub fn is_block_module(self) -> bool { + self.block.is_some() && self.local_id == DefMap::ROOT + } +} + +impl PartialEq for ModuleId { + fn eq(&self, other: &CrateRootModuleId) -> bool { + other == self + } +} + +impl From for ModuleId { + fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { + ModuleId { krate, block: None, local_id: DefMap::ROOT } + } +} + +impl From for ModuleDefId { + fn from(value: CrateRootModuleId) -> Self { + ModuleDefId::ModuleId(value.into()) + } +} + +/// An ID of a module, **local** to a `DefMap`. +pub type LocalModuleId = Idx; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct FieldId { + pub parent: VariantId, + pub local_id: LocalFieldId, +} + +pub type LocalFieldId = Idx; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TupleId(pub u32); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TupleFieldId { + pub tuple: TupleId, + pub index: u32, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TypeOrConstParamId { pub parent: GenericDefId, @@ -611,20 +625,6 @@ impl_from!( for ModuleDefId ); -/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and -/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct ConstBlockId(salsa::InternId); -impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const); - -#[derive(Debug, Hash, PartialEq, Eq, Clone)] -pub struct ConstBlockLoc { - /// The parent of the anonymous const block. - pub parent: DefWithBodyId, - /// The root expression of this const block in the parent body. - pub root: hir::ExprId, -} - /// Something that holds types, required for the current const arg lowering implementation as they /// need to be able to query where they are defined. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] @@ -892,6 +892,39 @@ impl_from!( for GenericDefId ); +impl GenericDefId { + fn file_id_and_params_of( + self, + db: &dyn DefDatabase, + ) -> (HirFileId, Option) { + fn file_id_and_params_of_item_loc( + db: &dyn DefDatabase, + def: impl for<'db> Lookup = dyn DefDatabase + 'db, Data = Loc>, + ) -> (HirFileId, Option) + where + Loc: src::HasSource, + Loc::Value: ast::HasGenericParams, + { + let src = def.lookup(db).source(db); + (src.file_id, ast::HasGenericParams::generic_param_list(&src.value)) + } + + match self { + GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it), + GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it), + GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None), + GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it), + GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it), + GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it), + 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), + // We won't be using this ID anyway + GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None), + } + } +} + impl From for GenericDefId { fn from(item: AssocItemId) -> Self { match item { @@ -1224,6 +1257,34 @@ impl HasModule for GenericDefId { } } +impl HasModule for AttrDefId { + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + match self { + AttrDefId::ModuleId(it) => *it, + AttrDefId::FieldId(it) => it.parent.module(db), + AttrDefId::AdtId(it) => it.module(db), + AttrDefId::FunctionId(it) => it.module(db), + AttrDefId::EnumVariantId(it) => it.module(db), + AttrDefId::StaticId(it) => it.module(db), + AttrDefId::ConstId(it) => it.module(db), + AttrDefId::TraitId(it) => it.module(db), + AttrDefId::TraitAliasId(it) => it.module(db), + AttrDefId::TypeAliasId(it) => it.module(db), + AttrDefId::ImplId(it) => it.module(db), + AttrDefId::ExternBlockId(it) => it.module(db), + AttrDefId::GenericParamId(it) => match it { + GenericParamId::TypeParamId(it) => it.parent(), + GenericParamId::ConstParamId(it) => it.parent(), + GenericParamId::LifetimeParamId(it) => it.parent, + } + .module(db), + AttrDefId::MacroId(it) => it.module(db), + AttrDefId::ExternCrateId(it) => it.module(db), + AttrDefId::UseId(it) => it.module(db), + } + } +} + impl ModuleDefId { /// Returns the module containing `self` (or `self`, if `self` is itself a module). /// @@ -1245,34 +1306,6 @@ impl ModuleDefId { } } -impl AttrDefId { - pub fn krate(&self, db: &dyn DefDatabase) -> CrateId { - match *self { - AttrDefId::ModuleId(it) => it.krate, - AttrDefId::FieldId(it) => it.parent.krate(db), - AttrDefId::AdtId(it) => it.krate(db), - AttrDefId::FunctionId(it) => it.krate(db), - AttrDefId::EnumVariantId(it) => it.krate(db), - AttrDefId::StaticId(it) => it.krate(db), - AttrDefId::ConstId(it) => it.krate(db), - AttrDefId::TraitId(it) => it.krate(db), - AttrDefId::TraitAliasId(it) => it.krate(db), - AttrDefId::TypeAliasId(it) => it.krate(db), - AttrDefId::ImplId(it) => it.krate(db), - AttrDefId::ExternBlockId(it) => it.krate(db), - AttrDefId::GenericParamId(it) => match it { - GenericParamId::TypeParamId(it) => it.parent(), - GenericParamId::ConstParamId(it) => it.parent(), - GenericParamId::LifetimeParamId(it) => it.parent, - } - .krate(db), - AttrDefId::MacroId(it) => it.krate(db), - AttrDefId::ExternCrateId(it) => it.krate(db), - AttrDefId::UseId(it) => it.krate(db), - } - } -} - /// A helper trait for converting to MacroCallId pub trait AsMacroCall { fn as_call_id( diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 7a9c4ea0169..db47d743c5a 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -27,9 +27,9 @@ use crate::{ visibility::{RawVisibility, Visibility}, AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, - ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, - ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, - TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId, + ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, + MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, + TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId, }; #[derive(Debug, Clone)] @@ -248,6 +248,7 @@ impl Resolver { RawVisibility::Public => Some(Visibility::Public), } } + pub fn resolve_path_in_value_ns( &self, db: &dyn DefDatabase, @@ -1014,13 +1015,13 @@ impl HasResolver for CrateRootModuleId { impl HasResolver for TraitId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for TraitAliasId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } @@ -1036,25 +1037,25 @@ impl + Copy> HasResolver for T { impl HasResolver for FunctionId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } impl HasResolver for ConstId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for StaticId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for TypeAliasId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } @@ -1071,19 +1072,19 @@ impl HasResolver for ImplId { impl HasResolver for ExternBlockId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { // Same as parent's - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for ExternCrateId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for UseId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } @@ -1170,18 +1171,28 @@ impl HasResolver for MacroId { impl HasResolver for Macro2Id { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for ProcMacroId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } impl HasResolver for MacroRulesId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.lookup(db).container.resolver(db) + lookup_resolver(db, self) } } + +fn lookup_resolver<'db>( + db: &(dyn DefDatabase + 'db), + lookup: impl Lookup< + Database<'db> = dyn DefDatabase + 'db, + Data = impl ItemTreeLoc, + >, +) -> Resolver { + lookup.lookup(db).container().resolver(db) +} diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index d820456b92c..4283f003f89 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -1,10 +1,15 @@ //! Utilities for mapping between hir IDs and the surface syntax. +use either::Either; use hir_expand::InFile; use la_arena::ArenaMap; use syntax::ast; -use crate::{db::DefDatabase, item_tree::ItemTreeNode, ItemTreeLoc, Lookup, UseId}; +use crate::{ + data::adt::lower_struct, db::DefDatabase, item_tree::ItemTreeNode, trace::Trace, GenericDefId, + ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, UseId, + VariantId, +}; pub trait HasSource { type Value; @@ -49,3 +54,105 @@ impl HasChildSource> for UseId { ) } } + +impl HasChildSource for GenericDefId { + type Value = Either; + fn child_source( + &self, + db: &dyn DefDatabase, + ) -> InFile> { + let generic_params = db.generic_params(*self); + let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); + + let (file_id, generic_params_list) = self.file_id_and_params_of(db); + + let mut params = ArenaMap::default(); + + // For traits and trait aliases the first type index is `Self`, we need to add it before + // the other params. + match *self { + GenericDefId::TraitId(id) => { + let trait_ref = id.lookup(db).source(db).value; + let idx = idx_iter.next().unwrap(); + params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref))); + } + GenericDefId::TraitAliasId(id) => { + let alias = id.lookup(db).source(db).value; + let idx = idx_iter.next().unwrap(); + params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias))); + } + _ => {} + } + + if let Some(generic_params_list) = generic_params_list { + for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) { + params.insert(idx, Either::Left(ast_param)); + } + } + + InFile::new(file_id, params) + } +} + +impl HasChildSource for GenericDefId { + type Value = ast::LifetimeParam; + fn child_source( + &self, + db: &dyn DefDatabase, + ) -> InFile> { + let generic_params = db.generic_params(*self); + let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); + + let (file_id, generic_params_list) = self.file_id_and_params_of(db); + + let mut params = ArenaMap::default(); + + if let Some(generic_params_list) = generic_params_list { + for (idx, ast_param) in idx_iter.zip(generic_params_list.lifetime_params()) { + params.insert(idx, ast_param); + } + } + + InFile::new(file_id, params) + } +} + +impl HasChildSource for VariantId { + type Value = Either; + + fn child_source(&self, db: &dyn DefDatabase) -> InFile> { + let item_tree; + let (src, fields, 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()), + &item_tree[lookup.id.value].fields, + 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()), + &item_tree[lookup.id.value].fields, + lookup.container, + ) + } + VariantId::UnionId(it) => { + let lookup = it.lookup(db); + item_tree = lookup.id.item_tree(db); + ( + lookup.source(db).map(|it| it.kind()), + &item_tree[lookup.id.value].fields, + lookup.container, + ) + } + }; + let mut trace = Trace::new_for_map(); + lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields); + src.with_value(trace.into_map()) + } +} diff --git a/crates/hir-def/src/trace.rs b/crates/hir-def/src/trace.rs index 04d5b266194..da50ee8dc7a 100644 --- a/crates/hir-def/src/trace.rs +++ b/crates/hir-def/src/trace.rs @@ -11,6 +11,8 @@ //! projections. use la_arena::{Arena, ArenaMap, Idx, RawIdx}; +// FIXME: This isn't really used anymore, at least not in a way where it does anything useful. +// Check if we should get rid of this or make proper use of it instead. pub(crate) struct Trace { arena: Option>, map: Option, V>>, diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 7ed48237f4c..0f3fac1cecd 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -37,10 +37,14 @@ impl RawVisibility { db: &dyn DefDatabase, node: InFile>, ) -> RawVisibility { + let node = match node.transpose() { + None => return RawVisibility::private(), + Some(node) => node, + }; Self::from_ast_with_span_map(db, node.value, db.span_map(node.file_id).as_ref()) } - pub(crate) fn from_ast_with_span_map( + pub(crate) fn from_opt_ast_with_span_map( db: &dyn DefDatabase, node: Option, span_map: SpanMapRef<'_>, @@ -49,29 +53,28 @@ impl RawVisibility { None => return RawVisibility::private(), Some(node) => node, }; - match node.kind() { + Self::from_ast_with_span_map(db, node, span_map) + } + + fn from_ast_with_span_map( + db: &dyn DefDatabase, + node: ast::Visibility, + span_map: SpanMapRef<'_>, + ) -> RawVisibility { + let path = match node.kind() { ast::VisibilityKind::In(path) => { let path = ModPath::from_src(db.upcast(), path, span_map); - let path = match path { + match path { None => return RawVisibility::private(), Some(path) => path, - }; - RawVisibility::Module(path, VisibilityExplicitness::Explicit) + } } - ast::VisibilityKind::PubCrate => { - let path = ModPath::from_kind(PathKind::Crate); - RawVisibility::Module(path, VisibilityExplicitness::Explicit) - } - ast::VisibilityKind::PubSuper => { - let path = ModPath::from_kind(PathKind::Super(1)); - RawVisibility::Module(path, VisibilityExplicitness::Explicit) - } - ast::VisibilityKind::PubSelf => { - let path = ModPath::from_kind(PathKind::Super(0)); - RawVisibility::Module(path, VisibilityExplicitness::Explicit) - } - ast::VisibilityKind::Pub => RawVisibility::Public, - } + ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate), + ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)), + ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)), + ast::VisibilityKind::Pub => return RawVisibility::Public, + }; + RawVisibility::Module(path, VisibilityExplicitness::Explicit) } pub fn resolve( @@ -94,6 +97,10 @@ pub enum Visibility { } impl Visibility { + pub(crate) fn is_visible_from_other_crate(self) -> bool { + matches!(self, Visibility::Public) + } + #[tracing::instrument(skip_all)] pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { let to_module = match self { @@ -105,24 +112,33 @@ impl Visibility { return false; } let def_map = from_module.def_map(db); - self.is_visible_from_def_map(db, &def_map, from_module.local_id) - } - - pub(crate) fn is_visible_from_other_crate(self) -> bool { - matches!(self, Visibility::Public) + Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id) } pub(crate) fn is_visible_from_def_map( self, db: &dyn DefDatabase, def_map: &DefMap, - mut from_module: LocalModuleId, + from_module: LocalModuleId, ) -> bool { - let mut to_module = match self { + let to_module = match self { Visibility::Module(m, _) => m, 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; + } + Self::is_visible_from_def_map_(db, def_map, to_module, from_module) + } + fn is_visible_from_def_map_( + db: &dyn DefDatabase, + def_map: &DefMap, + mut to_module: ModuleId, + mut from_module: LocalModuleId, + ) -> bool { + debug_assert_eq!(to_module.krate, def_map.krate()); // `to_module` might be the root module of a block expression. Those have the same // visibility as the containing module (even though no items are directly nameable from // there, getting this right is important for method resolution). @@ -130,20 +146,25 @@ impl Visibility { // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're // currently computing, so we must not call the `def_map` query for it. - let mut arc; + let def_map_block = def_map.block_id(); loop { - let to_module_def_map = - if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { + match (to_module.block, def_map_block) { + // to_module is not a block, so there is no parent def map to use + (None, _) => (), + (Some(a), Some(b)) if a == b => { cov_mark::hit!(is_visible_from_same_block_def_map); - def_map - } else { - arc = to_module.def_map(db); - &arc - }; - match to_module_def_map.parent() { - Some(parent) => to_module = parent, - None => break, + if let Some(parent) = def_map.parent() { + to_module = parent; + } + } + _ => { + if let Some(parent) = to_module.def_map(db).parent() { + to_module = parent; + continue; + } + } } + break; } // from_module needs to be a descendant of to_module @@ -176,30 +197,25 @@ impl Visibility { /// visible in unrelated modules). pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option { match (self, other) { - (Visibility::Module(_, _) | Visibility::Public, Visibility::Public) - | (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public), - (Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => { + (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public), + (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { if mod_a.krate != mod_b.krate { return None; } - let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| { - let parent_id = def_map[m].parent?; - Some(parent_id) - }); - let mut b_ancestors = iter::successors(Some(mod_b.local_id), |&m| { - let parent_id = def_map[m].parent?; - Some(parent_id) - }); + 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, vis_b)); + return Some(Visibility::Module(mod_b, expl_b)); } if b_ancestors.any(|m| m == mod_a.local_id) { // A is above B - return Some(Visibility::Module(mod_a, vis_a)); + return Some(Visibility::Module(mod_a, expl_a)); } None @@ -208,7 +224,8 @@ impl Visibility { } } -/// Whether the item was imported through `pub(crate) use` or just `use`. +/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without +/// visibility. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum VisibilityExplicitness { Explicit, diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs index 3179a632e26..e91e64c81b0 100644 --- a/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/crates/ide-diagnostics/src/handlers/private_field.rs @@ -83,6 +83,32 @@ fn main() { }; strukt.field; } +"#, + ); + } + + #[test] + fn block_module_madness2() { + check_diagnostics( + r#" +fn main() { + use crate as ForceParentBlockDefMap; + let strukt = { + use crate as ForceParentBlockDefMap; + { + pub struct Struct { + field: (), + } + { + use crate as ForceParentBlockDefMap; + { + Struct { field: () } + } + } + } + }; + strukt.field; +} "#, ); }