From d2feaae5d69525bca020df32a40e40f8a9394a80 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 02:17:50 +0800 Subject: [PATCH 1/7] feat(hir): introduce symbol identity types --- crates/hir/src/db.rs | 9 ++ crates/hir/src/lib.rs | 1 + crates/hir/src/symbol.rs | 341 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 351 insertions(+) create mode 100644 crates/hir/src/symbol.rs diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 61cb9cd0..9533cc73 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -29,6 +29,7 @@ use crate::{ impl_intern_key, impl_intern_lookup, scope::{BlockScope, GenerateBlockScope, ModuleScope, SubroutineScope, UnitScope}, semantics::pathres::PathResolution, + symbol::{DefId, DefLoc, ScopeId, ScopeLoc}, type_infer::TyResult, }; @@ -59,6 +60,12 @@ pub trait InternDb: SourceRootDb { #[salsa::interned] fn intern_module_def(&self, module_def: ModuleDef) -> ModuleDefId; + + #[salsa::interned] + fn intern_def(&self, def: DefLoc) -> DefId; + + #[salsa::interned] + fn intern_scope(&self, scope: ScopeLoc) -> ScopeId; } impl_intern!(BuiltinDataTyId, BuiltinDataTy, intern_ty, lookup_intern_ty); @@ -73,6 +80,8 @@ impl_intern!( impl_intern!(MacroCallId, MacroCallLoc, intern_macro_call, lookup_intern_macro_call); impl_intern!(MacroFileId, MacroFileLoc, intern_macro_file, lookup_intern_macro_file); impl_intern!(ModuleDefId, ModuleDef, intern_module_def, lookup_intern_module_def); +impl_intern!(DefId, DefLoc, intern_def, lookup_intern_def); +impl_intern!(ScopeId, ScopeLoc, intern_scope, lookup_intern_scope); #[salsa::query_group(HirDbStorage)] pub trait HirDb: InternDb { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5e85aa03..0643085d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -13,4 +13,5 @@ pub mod region_tree; pub mod scope; pub mod semantics; pub mod source_map; +pub mod symbol; pub mod type_infer; diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs new file mode 100644 index 00000000..4770ace7 --- /dev/null +++ b/crates/hir/src/symbol.rs @@ -0,0 +1,341 @@ +use rustc_hash::FxHashMap; +use smallvec::SmallVec; +use utils::impl_from; + +use crate::{ + base_db::salsa, + container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, + db::InternDb, + def_id::ModuleDefOrigin, + file::HirFileId, + hir_def::{ + Ident, + block::BlockId, + expr::declarator::DeclId, + file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, + module::{ + ModuleId, generate::GenerateBlockId, instantiation::InstanceId, port::NonAnsiPortId, + }, + stmt::StmtId, + subroutine::{SubroutineId, SubroutinePortId}, + typedef::TypedefId, + }, +}; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct DefId(pub salsa::InternId); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum DefLoc { + Module(ModuleId), + Config(InFile), + Library(InFile), + Udp(InFile), + Block(BlockId), + GenerateBlock(GenerateBlockId), + Subroutine(SubroutineId), + SubroutinePort(InSubroutine), + NonAnsiPort(InModule), + Decl(InContainer), + Typedef(InContainer), + Instance(InModule), + Stmt(InContainer), +} + +impl_from! { DefLoc => + Module(ModuleId), + Config(InFile), + Library(InFile), + Udp(InFile), + Block(BlockId), + GenerateBlock(GenerateBlockId), + Subroutine(SubroutineId), + SubroutinePort(InSubroutine), + NonAnsiPort(InModule), + Decl(InContainer), + Typedef(InContainer), + Instance(InModule), + Stmt(InContainer), +} + +impl From for DefLoc { + fn from(origin: ModuleDefOrigin) -> Self { + match origin { + ModuleDefOrigin::ModuleId(id) => Self::Module(id), + ModuleDefOrigin::Config(id) => Self::Config(id), + ModuleDefOrigin::Library(id) => Self::Library(id), + ModuleDefOrigin::Udp(id) => Self::Udp(id), + ModuleDefOrigin::BlockId(id) => Self::Block(id), + ModuleDefOrigin::GenerateBlockId(id) => Self::GenerateBlock(id), + ModuleDefOrigin::SubroutineId(id) => Self::Subroutine(id), + ModuleDefOrigin::SubroutinePort(id) => Self::SubroutinePort(id), + ModuleDefOrigin::NonAnsiPort(id) => Self::NonAnsiPort(id), + ModuleDefOrigin::Decl(id) => Self::Decl(id), + ModuleDefOrigin::Typedef(id) => Self::Typedef(id), + ModuleDefOrigin::Instance(id) => Self::Instance(id), + ModuleDefOrigin::Stmt(id) => Self::Stmt(id), + } + } +} + +impl DefId { + pub fn new(db: &dyn InternDb, loc: impl Into) -> Self { + db.intern_def(loc.into()) + } + + pub fn loc(self, db: &dyn InternDb) -> DefLoc { + db.lookup_intern_def(self) + } + + pub fn as_module(self, db: &dyn InternDb) -> Option { + match self.loc(db) { + DefLoc::Module(id) => Some(id), + _ => None, + } + } + + pub fn as_config(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Config(id) => Some(id), + _ => None, + } + } + + pub fn as_library(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Library(id) => Some(id), + _ => None, + } + } + + pub fn as_udp(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Udp(id) => Some(id), + _ => None, + } + } + + pub fn as_block(self, db: &dyn InternDb) -> Option { + match self.loc(db) { + DefLoc::Block(id) => Some(id), + _ => None, + } + } + + pub fn as_generate_block(self, db: &dyn InternDb) -> Option { + match self.loc(db) { + DefLoc::GenerateBlock(id) => Some(id), + _ => None, + } + } + + pub fn as_subroutine(self, db: &dyn InternDb) -> Option { + match self.loc(db) { + DefLoc::Subroutine(id) => Some(id), + _ => None, + } + } + + pub fn as_subroutine_port(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::SubroutinePort(id) => Some(id), + _ => None, + } + } + + pub fn as_non_ansi_port(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::NonAnsiPort(id) => Some(id), + _ => None, + } + } + + pub fn as_decl(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Decl(id) => Some(id), + _ => None, + } + } + + pub fn as_typedef(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Typedef(id) => Some(id), + _ => None, + } + } + + pub fn as_instance(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Instance(id) => Some(id), + _ => None, + } + } + + pub fn as_stmt(self, db: &dyn InternDb) -> Option> { + match self.loc(db) { + DefLoc::Stmt(id) => Some(id), + _ => None, + } + } +} + +#[non_exhaustive] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum DefKind { + Module, + Interface, + Package, + Program, + Class, + Covergroup, + Checker, + Udp, + Config, + Library, + Subroutine, + SubroutinePort, + Typedef, + Enum, + Struct, + Net, + Variable, + Param, + Port, + Instance, + ClassField, + Method, + Modport, + ClockingBlock, + Sequence, + Property, +} + +impl DefKind { + pub fn symbol_kind(self) -> SymbolKind { + match self { + DefKind::Module => SymbolKind::Module, + DefKind::Interface => SymbolKind::Interface, + DefKind::Package + | DefKind::Program + | DefKind::Class + | DefKind::Covergroup + | DefKind::Checker + | DefKind::Modport + | DefKind::ClockingBlock + | DefKind::Sequence + | DefKind::Property => SymbolKind::Unknown, + DefKind::Udp => SymbolKind::Primitive, + DefKind::Config => SymbolKind::Config, + DefKind::Library => SymbolKind::Library, + DefKind::Subroutine | DefKind::Method => SymbolKind::Fn, + DefKind::SubroutinePort | DefKind::Port => SymbolKind::PortDecl, + DefKind::Typedef | DefKind::Enum => SymbolKind::Typedef, + DefKind::Struct => SymbolKind::Struct, + DefKind::Net => SymbolKind::NetDecl, + DefKind::Variable | DefKind::ClassField => SymbolKind::DataDecl, + DefKind::Param => SymbolKind::ParamDecl, + DefKind::Instance => SymbolKind::Instance, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct ScopeId(pub salsa::InternId); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ScopeLoc { + File(HirFileId), + Module(ModuleId), + GenerateBlock(GenerateBlockId), + Block(BlockId), + Subroutine(SubroutineId), +} + +impl_from! { ScopeLoc => + File(HirFileId), + Module(ModuleId), + GenerateBlock(GenerateBlockId), + Block(BlockId), + Subroutine(SubroutineId), +} + +impl From for ScopeLoc { + fn from(cont_id: ContainerId) -> Self { + match cont_id { + ContainerId::HirFileId(id) => ScopeLoc::File(id), + ContainerId::ModuleId(id) => ScopeLoc::Module(id), + ContainerId::GenerateBlockId(id) => ScopeLoc::GenerateBlock(id), + ContainerId::BlockId(id) => ScopeLoc::Block(id), + ContainerId::SubroutineId(id) => ScopeLoc::Subroutine(id), + } + } +} + +impl ScopeId { + pub fn new(db: &dyn InternDb, loc: impl Into) -> Self { + db.intern_scope(loc.into()) + } + + pub fn loc(self, db: &dyn InternDb) -> ScopeLoc { + db.lookup_intern_scope(self) + } +} + +#[non_exhaustive] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ScopeKind { + File, + Package, + Module, + Interface, + Program, + Class, + GenerateBlock, + Block, + Subroutine, + Covergroup, + ClockingBlock, + Checker, +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct NameScope { + pub types: FxHashMap>, + pub values: FxHashMap>, + pub assertions: FxHashMap>, + pub imports: SmallVec<[Import; 2]>, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)] +pub struct Import { + pub named: Option, + pub wildcard_pkg: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum SymbolKind { + Module, + Config, + Primitive, + NonAnsiPortLabel, + PortDecl, + ParamDecl, + NetDecl, + DataDecl, + Genvar, + Specparam, + Typedef, + Struct, + Instance, + Block, + Stmt, + Fn, + Generate, + Specify, + Interface, + Library, + Region, + Unknown, +} From c5daa907ee66648915def003b3560cbbe6ac8ee4 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 02:53:55 +0800 Subject: [PATCH 2/7] refactor(hir): store module definition origins as def ids --- crates/hir/src/def_id.rs | 223 +++++++++++++++------------- crates/hir/src/semantics/pathres.rs | 9 +- crates/hir/src/symbol.rs | 21 --- crates/ide/src/code_lens.rs | 2 +- crates/ide/src/navigation_target.rs | 29 ++-- crates/ide/src/render.rs | 73 +++++---- crates/ide/src/semantic_index.rs | 2 +- 7 files changed, 178 insertions(+), 181 deletions(-) diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index 4b6ae0a2..6c96c75a 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -6,7 +6,6 @@ use syntax::{ }; use utils::{ get::{Get, GetRef}, - impl_from, line_index::TextRange, }; @@ -15,160 +14,178 @@ use crate::{ container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, db::HirDb, hir_def::{ - block::{BlockId, BlockLoc}, - expr::declarator::{DeclId, DeclaratorParent}, - file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, - module::{ - ModuleId, - generate::{GenerateBlockId, GenerateBlockLoc}, - instantiation::InstanceId, - port::NonAnsiPortId, - }, - stmt::StmtId, - subroutine::{SubroutineId, SubroutinePortId}, - typedef::TypedefId, + block::BlockLoc, + expr::declarator::DeclaratorParent, + module::generate::GenerateBlockLoc, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, + symbol::{DefId, DefLoc}, }; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ModuleDefOrigin { - ModuleId(ModuleId), - Config(InFile), - Library(InFile), - Udp(InFile), - BlockId(BlockId), - GenerateBlockId(GenerateBlockId), - SubroutineId(SubroutineId), - SubroutinePort(InSubroutine), + Module(DefId), + Config(DefId), + Library(DefId), + Udp(DefId), + Block(DefId), + GenerateBlock(DefId), + Subroutine(DefId), + SubroutinePort(DefId), - NonAnsiPort(InModule), - Decl(InContainer), - Typedef(InContainer), - Instance(InModule), - Stmt(InContainer), -} - -impl_from! { ModuleDefOrigin => - ModuleId, - Config(InFile), - Library(InFile), - Udp(InFile), - BlockId, - GenerateBlockId, - SubroutineId, - SubroutinePort(InSubroutine), - NonAnsiPort(InModule), - Decl(InContainer), - Typedef(InContainer), - Instance(InModule), - Stmt(InContainer), + NonAnsiPort(DefId), + Decl(DefId), + Typedef(DefId), + Instance(DefId), + Stmt(DefId), } impl ModuleDefOrigin { + pub fn from_loc(db: &dyn HirDb, loc: impl Into) -> Self { + let loc = loc.into(); + let def_id = DefId::new(db, loc); + Self::from_def_loc(def_id, loc) + } + + fn from_def_loc(def_id: DefId, loc: DefLoc) -> Self { + match loc { + DefLoc::Module(_) => Self::Module(def_id), + DefLoc::Config(_) => Self::Config(def_id), + DefLoc::Library(_) => Self::Library(def_id), + DefLoc::Udp(_) => Self::Udp(def_id), + DefLoc::Block(_) => Self::Block(def_id), + DefLoc::GenerateBlock(_) => Self::GenerateBlock(def_id), + DefLoc::Subroutine(_) => Self::Subroutine(def_id), + DefLoc::SubroutinePort(_) => Self::SubroutinePort(def_id), + DefLoc::NonAnsiPort(_) => Self::NonAnsiPort(def_id), + DefLoc::Decl(_) => Self::Decl(def_id), + DefLoc::Typedef(_) => Self::Typedef(def_id), + DefLoc::Instance(_) => Self::Instance(def_id), + DefLoc::Stmt(_) => Self::Stmt(def_id), + } + } + + pub fn def_id(&self) -> DefId { + match *self { + Self::Module(def_id) + | Self::Config(def_id) + | Self::Library(def_id) + | Self::Udp(def_id) + | Self::Block(def_id) + | Self::GenerateBlock(def_id) + | Self::Subroutine(def_id) + | Self::SubroutinePort(def_id) + | Self::NonAnsiPort(def_id) + | Self::Decl(def_id) + | Self::Typedef(def_id) + | Self::Instance(def_id) + | Self::Stmt(def_id) => def_id, + } + } + + pub fn loc(&self, db: &dyn HirDb) -> DefLoc { + self.def_id().loc(db) + } + #[inline] pub fn container_id(&self, db: &dyn HirDb) -> ContainerId { - match *self { - ModuleDefOrigin::ModuleId(InFile { file_id, .. }) => file_id.into(), - ModuleDefOrigin::Config(InFile { file_id, .. }) => file_id.into(), - ModuleDefOrigin::Library(InFile { file_id, .. }) => file_id.into(), - ModuleDefOrigin::Udp(InFile { file_id, .. }) => file_id.into(), - ModuleDefOrigin::BlockId(block_id) => block_id.lookup(db).cont_id, - ModuleDefOrigin::GenerateBlockId(generate_block_id) => { - generate_block_id.lookup(db).cont_id - } - ModuleDefOrigin::SubroutineId(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), - ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, .. }) => { + match self.loc(db) { + DefLoc::Module(InFile { file_id, .. }) => file_id.into(), + DefLoc::Config(InFile { file_id, .. }) => file_id.into(), + DefLoc::Library(InFile { file_id, .. }) => file_id.into(), + DefLoc::Udp(InFile { file_id, .. }) => file_id.into(), + DefLoc::Block(block_id) => block_id.lookup(db).cont_id, + DefLoc::GenerateBlock(generate_block_id) => generate_block_id.lookup(db).cont_id, + DefLoc::Subroutine(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), + DefLoc::SubroutinePort(InSubroutine { subroutine, .. }) => { ContainerId::SubroutineId(subroutine) } - ModuleDefOrigin::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), - ModuleDefOrigin::Decl(InContainer { cont_id, .. }) => cont_id, - ModuleDefOrigin::Typedef(InContainer { cont_id, .. }) => cont_id, - ModuleDefOrigin::Instance(InModule { module_id, .. }) => module_id.into(), - ModuleDefOrigin::Stmt(InContainer { cont_id, .. }) => cont_id, + DefLoc::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), + DefLoc::Decl(InContainer { cont_id, .. }) => cont_id, + DefLoc::Typedef(InContainer { cont_id, .. }) => cont_id, + DefLoc::Instance(InModule { module_id, .. }) => module_id.into(), + DefLoc::Stmt(InContainer { cont_id, .. }) => cont_id, } } pub fn name(&self, db: &dyn HirDb) -> Option { - match *self { - ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + match self.loc(db) { + DefLoc::Module(InFile { value, file_id }) => { file_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Config(InFile { value, file_id }) => { + DefLoc::Config(InFile { value, file_id }) => { file_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Library(InFile { value, file_id }) => { + DefLoc::Library(InFile { value, file_id }) => { file_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Udp(InFile { value, file_id }) => { + DefLoc::Udp(InFile { value, file_id }) => { file_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::BlockId(block_id) => { + DefLoc::Block(block_id) => { let BlockLoc { cont_id, src: InFile { value, file_id: _ } } = block_id.lookup(db); let cont = cont_id.to_container(db); value.hir(&cont, &cont_id.to_container_src_map(db))?.name.clone() } - ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + DefLoc::GenerateBlock(generate_block_id) => { db.generate_block(generate_block_id).name.clone() } - ModuleDefOrigin::SubroutineId(subroutine_id) => { - db.subroutine(subroutine_id).name.clone() - } - ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + DefLoc::Subroutine(subroutine_id) => db.subroutine(subroutine_id).name.clone(), + DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { db.subroutine(subroutine).ports.get(value.0 as usize)?.name.clone() } - ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + DefLoc::NonAnsiPort(InModule { value, module_id }) => { module_id.to_container(db).get(value).label.clone() } - ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + DefLoc::Decl(InContainer { value, cont_id }) => { cont_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + DefLoc::Typedef(InContainer { value, cont_id }) => { cont_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Instance(InModule { value, module_id }) => { + DefLoc::Instance(InModule { value, module_id }) => { module_id.to_container(db).get(value).name.clone() } - ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + DefLoc::Stmt(InContainer { value, cont_id }) => { cont_id.to_container(db).get(value).label.clone() } } } pub fn name_range(&self, db: &dyn HirDb) -> Option> { - match *self { - ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + match self.loc(db) { + DefLoc::Module(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::Config(InFile { value, file_id }) => { + DefLoc::Config(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::Library(InFile { value, file_id }) => { + DefLoc::Library(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::Udp(InFile { value, file_id }) => { + DefLoc::Udp(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::BlockId(block_id) => { + DefLoc::Block(block_id) => { let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); let range = value.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + DefLoc::GenerateBlock(generate_block_id) => { let GenerateBlockLoc { src: InFile { value, file_id }, .. } = generate_block_id.lookup(db); let range = value.name_range()?; Some(InFile::new(file_id, range)) } - ModuleDefOrigin::SubroutineId(subroutine_id) => { + DefLoc::Subroutine(subroutine_id) => { let src = subroutine_id.lookup(db).src; Some(InFile::new(src.file_id, src.value.name_or_full_range())) } - ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { let src = subroutine.lookup(db).src; let tree = db.parse(src.file_id); let func = src.value.to_node(&tree)?; @@ -185,23 +202,23 @@ impl ModuleDefOrigin { let range = declarator.name()?.text_range_in(declarator.syntax())?; Some(InFile::new(src.file_id, range)) } - ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + DefLoc::NonAnsiPort(InModule { value, module_id }) => { let range = module_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(module_id.file_id, range)) } - ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + DefLoc::Decl(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(cont_id.file_id(db).into(), range)) } - ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + DefLoc::Typedef(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(cont_id.file_id(db).into(), range)) } - ModuleDefOrigin::Instance(InModule { value, module_id }) => { + DefLoc::Instance(InModule { value, module_id }) => { let range = module_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(module_id.file_id, range)) } - ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + DefLoc::Stmt(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.name_range()?; Some(InFile::new(cont_id.file_id(db).into(), range)) } @@ -209,40 +226,40 @@ impl ModuleDefOrigin { } pub fn range(&self, db: &dyn HirDb) -> Option> { - Some(match *self { - ModuleDefOrigin::ModuleId(InFile { value, file_id }) => { + Some(match self.loc(db) { + DefLoc::Module(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.range(); InFile::new(file_id, range) } - ModuleDefOrigin::Config(InFile { value, file_id }) => { + DefLoc::Config(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.range(); InFile::new(file_id, range) } - ModuleDefOrigin::Library(InFile { value, file_id }) => { + DefLoc::Library(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.range(); InFile::new(file_id, range) } - ModuleDefOrigin::Udp(InFile { value, file_id }) => { + DefLoc::Udp(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.range(); InFile::new(file_id, range) } - ModuleDefOrigin::BlockId(block_id) => { + DefLoc::Block(block_id) => { let BlockLoc { src: InFile { value, file_id }, .. } = block_id.lookup(db); let range = value.range(); InFile::new(file_id, range) } - ModuleDefOrigin::GenerateBlockId(generate_block_id) => { + DefLoc::GenerateBlock(generate_block_id) => { let GenerateBlockLoc { src: InFile { value, file_id }, .. } = generate_block_id.lookup(db); let range = value.range(); InFile::new(file_id, range) } - ModuleDefOrigin::SubroutineId(subroutine_id) => { + DefLoc::Subroutine(subroutine_id) => { let src = subroutine_id.lookup(db).src; let range = src.value.range(); InFile::new(src.file_id, range) } - ModuleDefOrigin::SubroutinePort(InSubroutine { subroutine, value }) => { + DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { let src = subroutine.lookup(db).src; let tree = db.parse(src.file_id); let func = src.value.to_node(&tree)?; @@ -255,23 +272,23 @@ impl ModuleDefOrigin { let range = port.syntax().text_range()?; InFile::new(src.file_id, range) } - ModuleDefOrigin::NonAnsiPort(InModule { value, module_id }) => { + DefLoc::NonAnsiPort(InModule { value, module_id }) => { let range = module_id.to_container_src_map(db).get(value)?.range(); InFile::new(module_id.file_id, range) } - ModuleDefOrigin::Decl(InContainer { value, cont_id }) => { + DefLoc::Decl(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.range(); InFile::new(cont_id.file_id(db).into(), range) } - ModuleDefOrigin::Typedef(InContainer { value, cont_id }) => { + DefLoc::Typedef(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.range(); InFile::new(cont_id.file_id(db).into(), range) } - ModuleDefOrigin::Instance(InModule { value, module_id }) => { + DefLoc::Instance(InModule { value, module_id }) => { let range = module_id.to_container_src_map(db).get(value)?.range(); InFile::new(module_id.file_id, range) } - ModuleDefOrigin::Stmt(InContainer { value, cont_id }) => { + DefLoc::Stmt(InContainer { value, cont_id }) => { let range = cont_id.to_container_src_map(db).get(value)?.range(); InFile::new(cont_id.file_id(db).into(), range) } @@ -359,7 +376,7 @@ impl ModuleDefId { } fn is_port_decl_origin(db: &dyn HirDb, origin: &ModuleDefOrigin) -> bool { - let ModuleDefOrigin::Decl(decl_id) = origin else { + let DefLoc::Decl(decl_id) = origin.loc(db) else { return false; }; matches!( diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index 6c6372ae..5087276b 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -24,6 +24,7 @@ use crate::{ typedef::TypedefId, }, scope::{self, BlockEntry, GenerateBlockEntry, ModuleEntry, SubroutineEntry, UnitEntry}, + symbol::DefLoc, }; impl SemanticsImpl<'_> { @@ -97,13 +98,13 @@ pub enum PathResolution { impl PathResolution { pub fn to_def_id(self, db: &dyn HirDb) -> Option { - let module_def = ModuleDef::from_origins(self.origins())?; + let module_def = ModuleDef::from_origins(self.origins(db))?; Some(db.intern_module_def(module_def)) } - fn origins(self) -> SmallVec<[ModuleDefOrigin; 3]> { + fn origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 3]> { let mut res = smallvec![]; - let mut add_source = |source| res.push(source); + let mut add_source = |source: DefLoc| res.push(ModuleDefOrigin::from_loc(db, source)); match self { PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { @@ -129,7 +130,7 @@ impl PathResolution { } #[inline] - fn pick(self) -> Option { + fn pick(self) -> Option { match self { PathResolution::Module(module_id) => Some(module_id.into()), PathResolution::Config(config_id) => Some(config_id.into()), diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs index 4770ace7..8a51c3d7 100644 --- a/crates/hir/src/symbol.rs +++ b/crates/hir/src/symbol.rs @@ -6,7 +6,6 @@ use crate::{ base_db::salsa, container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, db::InternDb, - def_id::ModuleDefOrigin, file::HirFileId, hir_def::{ Ident, @@ -59,26 +58,6 @@ impl_from! { DefLoc => Stmt(InContainer), } -impl From for DefLoc { - fn from(origin: ModuleDefOrigin) -> Self { - match origin { - ModuleDefOrigin::ModuleId(id) => Self::Module(id), - ModuleDefOrigin::Config(id) => Self::Config(id), - ModuleDefOrigin::Library(id) => Self::Library(id), - ModuleDefOrigin::Udp(id) => Self::Udp(id), - ModuleDefOrigin::BlockId(id) => Self::Block(id), - ModuleDefOrigin::GenerateBlockId(id) => Self::GenerateBlock(id), - ModuleDefOrigin::SubroutineId(id) => Self::Subroutine(id), - ModuleDefOrigin::SubroutinePort(id) => Self::SubroutinePort(id), - ModuleDefOrigin::NonAnsiPort(id) => Self::NonAnsiPort(id), - ModuleDefOrigin::Decl(id) => Self::Decl(id), - ModuleDefOrigin::Typedef(id) => Self::Typedef(id), - ModuleDefOrigin::Instance(id) => Self::Instance(id), - ModuleDefOrigin::Stmt(id) => Self::Stmt(id), - } - } -} - impl DefId { pub fn new(db: &dyn InternDb, loc: impl Into) -> Self { db.intern_def(loc.into()) diff --git a/crates/ide/src/code_lens.rs b/crates/ide/src/code_lens.rs index 83c71f63..972e470c 100644 --- a/crates/ide/src/code_lens.rs +++ b/crates/ide/src/code_lens.rs @@ -87,7 +87,7 @@ pub(crate) fn code_lens_resolve(db: &RootDb, mut kind: CodeLensKind) -> CodeLens }; let module_id = ModuleId::new(hir_file_id, local_module_id); - let def = ModuleDefOrigin::ModuleId(module_id); + let def = ModuleDefOrigin::from_loc(sema.db, module_id); let def = hir::def_id::ModuleDef::from_origins([def]) .expect("module definition should have an origin"); let def = sema.db.intern_module_def(def); diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 7b699343..c0ec3d67 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -19,6 +19,7 @@ use hir::{ typedef::TypedefId, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, + symbol::DefLoc, }; use smol_str::SmolStr; use syntax::{ @@ -59,20 +60,20 @@ pub(crate) trait ToNav { impl ToNav for ModuleDefOrigin { fn to_nav(&self, db: &RootDb) -> Option { - match self { - ModuleDefOrigin::ModuleId(module_id) => module_id.to_nav(db), - ModuleDefOrigin::Config(config_id) => config_id.to_nav(db), - ModuleDefOrigin::Library(library_id) => library_id.to_nav(db), - ModuleDefOrigin::Udp(udp_id) => udp_id.to_nav(db), - ModuleDefOrigin::BlockId(block_id) => block_id.to_nav(db), - ModuleDefOrigin::GenerateBlockId(generate_block_id) => generate_block_id.to_nav(db), - ModuleDefOrigin::SubroutineId(subroutine_id) => subroutine_id.to_nav(db), - ModuleDefOrigin::SubroutinePort(subroutine_port_id) => subroutine_port_id.to_nav(db), - ModuleDefOrigin::NonAnsiPort(nonansi_port_id) => nonansi_port_id.to_nav(db), - ModuleDefOrigin::Decl(decl_id) => decl_id.to_nav(db), - ModuleDefOrigin::Typedef(typedef_id) => typedef_id.to_nav(db), - ModuleDefOrigin::Instance(instance_id) => instance_id.to_nav(db), - ModuleDefOrigin::Stmt(stmt_id) => stmt_id.to_nav(db), + match self.loc(db) { + DefLoc::Module(module_id) => module_id.to_nav(db), + DefLoc::Config(config_id) => config_id.to_nav(db), + DefLoc::Library(library_id) => library_id.to_nav(db), + DefLoc::Udp(udp_id) => udp_id.to_nav(db), + DefLoc::Block(block_id) => block_id.to_nav(db), + DefLoc::GenerateBlock(generate_block_id) => generate_block_id.to_nav(db), + DefLoc::Subroutine(subroutine_id) => subroutine_id.to_nav(db), + DefLoc::SubroutinePort(subroutine_port_id) => subroutine_port_id.to_nav(db), + DefLoc::NonAnsiPort(nonansi_port_id) => nonansi_port_id.to_nav(db), + DefLoc::Decl(decl_id) => decl_id.to_nav(db), + DefLoc::Typedef(typedef_id) => typedef_id.to_nav(db), + DefLoc::Instance(instance_id) => instance_id.to_nav(db), + DefLoc::Stmt(stmt_id) => stmt_id.to_nav(db), } } } diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index 854c7b5d..9237a1f5 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -24,6 +24,7 @@ use hir::{ }, region_tree::RegionParent, semantics::Semantics, + symbol::DefLoc, }; use itertools::Itertools; use syntax::{ @@ -285,22 +286,22 @@ fn render_def_origin( fn render_definition_title(db: &RootDb, origin: &ModuleDefOrigin) -> Option { let name = origin.name(db)?; - let kind = match origin { - ModuleDefOrigin::ModuleId(_) => "Module", - ModuleDefOrigin::Config(_) => "Config", - ModuleDefOrigin::Library(_) => "Library", - ModuleDefOrigin::Udp(_) => "Primitive", - ModuleDefOrigin::BlockId(_) => "Block", - ModuleDefOrigin::GenerateBlockId(_) => "Generate block", - ModuleDefOrigin::SubroutineId(subroutine_id) => match db.subroutine(*subroutine_id).kind { + let kind = match origin.loc(db) { + DefLoc::Module(_) => "Module", + DefLoc::Config(_) => "Config", + DefLoc::Library(_) => "Library", + DefLoc::Udp(_) => "Primitive", + DefLoc::Block(_) => "Block", + DefLoc::GenerateBlock(_) => "Generate block", + DefLoc::Subroutine(subroutine_id) => match db.subroutine(subroutine_id).kind { SubroutineKind::Task => "Task", SubroutineKind::Function { .. } => "Function", }, - ModuleDefOrigin::SubroutinePort(_) | ModuleDefOrigin::NonAnsiPort(_) => "Port", - ModuleDefOrigin::Decl(decl_id) => render_decl_title_kind(db, *decl_id)?, - ModuleDefOrigin::Typedef(_) => "Typedef", - ModuleDefOrigin::Instance(_) => "Instance", - ModuleDefOrigin::Stmt(_) => "Statement", + DefLoc::SubroutinePort(_) | DefLoc::NonAnsiPort(_) => "Port", + DefLoc::Decl(decl_id) => render_decl_title_kind(db, decl_id)?, + DefLoc::Typedef(_) => "Typedef", + DefLoc::Instance(_) => "Instance", + DefLoc::Stmt(_) => "Statement", }; Some(format!("{kind} {}", inline_code(name.as_str()))) @@ -328,16 +329,14 @@ fn render_decl_title_kind(db: &RootDb, decl_id: InContainer) -> Option<& fn render_signature(sema: &Semantics, origin: &ModuleDefOrigin) -> Option { let db = sema.db; - match origin { - ModuleDefOrigin::ModuleId(module_id) => render_module_signature(db, *module_id), - ModuleDefOrigin::SubroutineId(subroutine_id) => { - render_subroutine_signature(db, *subroutine_id) - } - ModuleDefOrigin::SubroutinePort(port_id) => render_subroutine_port_signature(db, *port_id), - ModuleDefOrigin::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, *port_id), - ModuleDefOrigin::Decl(decl_id) => render_decl_signature(db, *decl_id), - ModuleDefOrigin::Typedef(typedef) => typedef.display_signature(db).ok(), - ModuleDefOrigin::Instance(instance_id) => render_instance_signature(db, *instance_id), + match origin.loc(db) { + DefLoc::Module(module_id) => render_module_signature(db, module_id), + DefLoc::Subroutine(subroutine_id) => render_subroutine_signature(db, subroutine_id), + DefLoc::SubroutinePort(port_id) => render_subroutine_port_signature(db, port_id), + DefLoc::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, port_id), + DefLoc::Decl(decl_id) => render_decl_signature(db, decl_id), + DefLoc::Typedef(typedef) => typedef.display_signature(db).ok(), + DefLoc::Instance(instance_id) => render_instance_signature(db, instance_id), _ => render_label_signature(db, origin), } } @@ -622,20 +621,20 @@ fn render_data_ty(db: &RootDb, container: ContainerId, ty: DataTy) -> Option Option { let name = origin.name(db)?; - let kind = match origin { - ModuleDefOrigin::Config(_) => "config", - ModuleDefOrigin::Library(_) => "library", - ModuleDefOrigin::Udp(_) => "primitive", - ModuleDefOrigin::BlockId(_) => "block", - ModuleDefOrigin::GenerateBlockId(_) => "generate", - ModuleDefOrigin::Instance(_) => "instance", - ModuleDefOrigin::Stmt(_) => "statement", - ModuleDefOrigin::Typedef(_) => "typedef", - ModuleDefOrigin::ModuleId(_) - | ModuleDefOrigin::SubroutineId(_) - | ModuleDefOrigin::SubroutinePort(_) - | ModuleDefOrigin::NonAnsiPort(_) - | ModuleDefOrigin::Decl(_) => return None, + let kind = match origin.loc(db) { + DefLoc::Config(_) => "config", + DefLoc::Library(_) => "library", + DefLoc::Udp(_) => "primitive", + DefLoc::Block(_) => "block", + DefLoc::GenerateBlock(_) => "generate", + DefLoc::Instance(_) => "instance", + DefLoc::Stmt(_) => "statement", + DefLoc::Typedef(_) => "typedef", + DefLoc::Module(_) + | DefLoc::Subroutine(_) + | DefLoc::SubroutinePort(_) + | DefLoc::NonAnsiPort(_) + | DefLoc::Decl(_) => return None, }; Some(format!("{kind} {name}")) } diff --git a/crates/ide/src/semantic_index.rs b/crates/ide/src/semantic_index.rs index 3e8ba205..4a02a39e 100644 --- a/crates/ide/src/semantic_index.rs +++ b/crates/ide/src/semantic_index.rs @@ -163,7 +163,7 @@ impl ModuleIndex { impl SemanticModuleDefinition { fn new(db: &dyn HirDb, module_id: ModuleId) -> Option { - let origin = ModuleDefOrigin::ModuleId(module_id); + let origin = ModuleDefOrigin::from_loc(db, module_id); let name = origin.name(db)?; let InFile { file_id, value: name_range } = origin.name_range(db)?; let InFile { value: full_range, .. } = origin.range(db)?; From c258ee2119b9352d7097138a552f576d0032cd05 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 02:58:47 +0800 Subject: [PATCH 3/7] refactor(hir): rename container ids to scope ids --- crates/hir/src/container.rs | 89 ++++++++++++----------- crates/hir/src/db.rs | 6 +- crates/hir/src/def_id.rs | 12 ++- crates/hir/src/hir_def/aggregate.rs | 4 +- crates/hir/src/hir_def/block.rs | 8 +- crates/hir/src/hir_def/file.rs | 6 +- crates/hir/src/hir_def/module.rs | 6 +- crates/hir/src/hir_def/module/generate.rs | 8 +- crates/hir/src/hir_def/proc.rs | 4 +- crates/hir/src/hir_def/stmt.rs | 4 +- crates/hir/src/hir_def/subroutine.rs | 20 ++--- crates/hir/src/hir_def/typedef.rs | 4 +- crates/hir/src/semantics.rs | 4 +- crates/hir/src/semantics/hir_to_def.rs | 24 +++--- crates/hir/src/semantics/pathres.rs | 25 +++---- crates/hir/src/semantics/resolver.rs | 9 +-- crates/hir/src/semantics/source_to_def.rs | 20 ++--- crates/hir/src/symbol.rs | 46 +----------- crates/hir/src/type_infer.rs | 80 ++++++++++---------- crates/ide/src/completion/engine/expr.rs | 28 +++---- crates/ide/src/navigation_target.rs | 4 +- crates/ide/src/references/search.rs | 18 ++--- crates/ide/src/render.rs | 12 +-- 23 files changed, 197 insertions(+), 244 deletions(-) diff --git a/crates/hir/src/container.rs b/crates/hir/src/container.rs index 67d50589..875ad21b 100644 --- a/crates/hir/src/container.rs +++ b/crates/hir/src/container.rs @@ -27,27 +27,28 @@ use crate::{ typedef::{Typedef, TypedefId, TypedefSrc}, }, region_tree::RegionTree, + symbol::ScopeKind, }; define_enum_deriving_from! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] - pub enum ContainerId { - HirFileId(HirFileId), - ModuleId(ModuleId), - GenerateBlockId(GenerateBlockId), - BlockId(BlockId), - SubroutineId(SubroutineId), + pub enum ScopeId { + File(HirFileId), + Module(ModuleId), + GenerateBlock(GenerateBlockId), + Block(BlockId), + Subroutine(SubroutineId), } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub struct InContainer { pub value: T, - pub cont_id: ContainerId, + pub cont_id: ScopeId, } impl InContainer { - pub fn new(cont_id: ContainerId, value: T) -> InContainer { + pub fn new(cont_id: ScopeId, value: T) -> InContainer { InContainer { value, cont_id } } @@ -78,7 +79,7 @@ impl InSubroutine { impl From> for InContainer { fn from(item: InSubroutine) -> InContainer { - InContainer::new(ContainerId::SubroutineId(item.subroutine), item.value) + InContainer::new(ScopeId::Subroutine(item.subroutine), item.value) } } @@ -121,40 +122,46 @@ define_container_id! { InBlock[block_id: BlockId], } -impl ContainerId { +impl ScopeId { + pub fn kind(self) -> ScopeKind { + match self { + ScopeId::File(_) => ScopeKind::File, + ScopeId::Module(_) => ScopeKind::Module, + ScopeId::GenerateBlock(_) => ScopeKind::GenerateBlock, + ScopeId::Block(_) => ScopeKind::Block, + ScopeId::Subroutine(_) => ScopeKind::Subroutine, + } + } + pub fn file_id(self, db: &dyn InternDb) -> FileId { match self { - ContainerId::HirFileId(file_id) => file_id.file_id(), - ContainerId::ModuleId(module_id) => module_id.file_id(), - ContainerId::GenerateBlockId(generate_block_id) => generate_block_id.file_id(db), - ContainerId::BlockId(block_id) => block_id.file_id(db), - ContainerId::SubroutineId(subroutine_id) => { - subroutine_id.lookup(db).src.file_id.file_id() - } + ScopeId::File(file_id) => file_id.file_id(), + ScopeId::Module(module_id) => module_id.file_id(), + ScopeId::GenerateBlock(generate_block_id) => generate_block_id.file_id(db), + ScopeId::Block(block_id) => block_id.file_id(db), + ScopeId::Subroutine(subroutine_id) => subroutine_id.lookup(db).src.file_id.file_id(), } } pub fn to_container(self, db: &dyn HirDb) -> Container { match self { - ContainerId::HirFileId(file_id) => file_id.to_container(db).into(), - ContainerId::ModuleId(module_id) => module_id.to_container(db).into(), - ContainerId::GenerateBlockId(generate_block_id) => { - generate_block_id.to_container(db).into() - } - ContainerId::BlockId(block_id) => block_id.to_container(db).into(), - ContainerId::SubroutineId(subroutine_id) => db.subroutine(subroutine_id).into(), + ScopeId::File(file_id) => file_id.to_container(db).into(), + ScopeId::Module(module_id) => module_id.to_container(db).into(), + ScopeId::GenerateBlock(generate_block_id) => generate_block_id.to_container(db).into(), + ScopeId::Block(block_id) => block_id.to_container(db).into(), + ScopeId::Subroutine(subroutine_id) => db.subroutine(subroutine_id).into(), } } pub fn to_container_src_map(self, db: &dyn HirDb) -> ContainerSrcMap { match self { - ContainerId::HirFileId(file_id) => file_id.to_container_src_map(db).into(), - ContainerId::ModuleId(module_id) => module_id.to_container_src_map(db).into(), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => file_id.to_container_src_map(db).into(), + ScopeId::Module(module_id) => module_id.to_container_src_map(db).into(), + ScopeId::GenerateBlock(generate_block_id) => { generate_block_id.to_container_src_map(db).into() } - ContainerId::BlockId(block_id) => block_id.to_container_src_map(db).into(), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => block_id.to_container_src_map(db).into(), + ScopeId::Subroutine(subroutine_id) => { db.subroutine_with_source_map(subroutine_id).1.into() } } @@ -282,30 +289,30 @@ impl AsRef for ContainerSrcMap { } /// Parents of a scope. -pub struct ContainerParent<'db> { +pub struct ScopeParent<'db> { db: &'db dyn InternDb, - cont_id: Option, + cont_id: Option, } -impl ContainerParent<'_> { - pub fn start_from(db: &dyn InternDb, cont_id: ContainerId) -> ContainerParent<'_> { - ContainerParent { db, cont_id: Some(cont_id) } +impl ScopeParent<'_> { + pub fn start_from(db: &dyn InternDb, cont_id: ScopeId) -> ScopeParent<'_> { + ScopeParent { db, cont_id: Some(cont_id) } } } -impl Iterator for ContainerParent<'_> { - type Item = ContainerId; +impl Iterator for ScopeParent<'_> { + type Item = ScopeId; fn next(&mut self) -> Option { let next = self.cont_id; self.cont_id = match self.cont_id? { - ContainerId::HirFileId(_) => None, - ContainerId::ModuleId(module_id) => Some(module_id.file_id.into()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(_) => None, + ScopeId::Module(module_id) => Some(module_id.file_id.into()), + ScopeId::GenerateBlock(generate_block_id) => { Some(generate_block_id.lookup(self.db).cont_id) } - ContainerId::BlockId(block_id) => Some(block_id.lookup(self.db).cont_id), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(block_id.lookup(self.db).cont_id), + ScopeId::Subroutine(subroutine_id) => { Some(subroutine_id.lookup(self.db).cont_id.into()) } }; diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 9533cc73..4a57328f 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -29,7 +29,7 @@ use crate::{ impl_intern_key, impl_intern_lookup, scope::{BlockScope, GenerateBlockScope, ModuleScope, SubroutineScope, UnitScope}, semantics::pathres::PathResolution, - symbol::{DefId, DefLoc, ScopeId, ScopeLoc}, + symbol::{DefId, DefLoc}, type_infer::TyResult, }; @@ -63,9 +63,6 @@ pub trait InternDb: SourceRootDb { #[salsa::interned] fn intern_def(&self, def: DefLoc) -> DefId; - - #[salsa::interned] - fn intern_scope(&self, scope: ScopeLoc) -> ScopeId; } impl_intern!(BuiltinDataTyId, BuiltinDataTy, intern_ty, lookup_intern_ty); @@ -81,7 +78,6 @@ impl_intern!(MacroCallId, MacroCallLoc, intern_macro_call, lookup_intern_macro_c impl_intern!(MacroFileId, MacroFileLoc, intern_macro_file, lookup_intern_macro_file); impl_intern!(ModuleDefId, ModuleDef, intern_module_def, lookup_intern_module_def); impl_intern!(DefId, DefLoc, intern_def, lookup_intern_def); -impl_intern!(ScopeId, ScopeLoc, intern_scope, lookup_intern_scope); #[salsa::query_group(HirDbStorage)] pub trait HirDb: InternDb { diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index 6c96c75a..a49ff767 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -11,12 +11,10 @@ use utils::{ use crate::{ base_db::{intern::Lookup, salsa}, - container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, + container::{InContainer, InFile, InModule, InSubroutine, ScopeId}, db::HirDb, hir_def::{ - block::BlockLoc, - expr::declarator::DeclaratorParent, - module::generate::GenerateBlockLoc, + block::BlockLoc, expr::declarator::DeclaratorParent, module::generate::GenerateBlockLoc, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, symbol::{DefId, DefLoc}, @@ -88,7 +86,7 @@ impl ModuleDefOrigin { } #[inline] - pub fn container_id(&self, db: &dyn HirDb) -> ContainerId { + pub fn container_id(&self, db: &dyn HirDb) -> ScopeId { match self.loc(db) { DefLoc::Module(InFile { file_id, .. }) => file_id.into(), DefLoc::Config(InFile { file_id, .. }) => file_id.into(), @@ -98,7 +96,7 @@ impl ModuleDefOrigin { DefLoc::GenerateBlock(generate_block_id) => generate_block_id.lookup(db).cont_id, DefLoc::Subroutine(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), DefLoc::SubroutinePort(InSubroutine { subroutine, .. }) => { - ContainerId::SubroutineId(subroutine) + ScopeId::Subroutine(subroutine) } DefLoc::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), DefLoc::Decl(InContainer { cont_id, .. }) => cont_id, @@ -365,7 +363,7 @@ impl ModuleDefId { }) } - pub fn container_id(self, db: &dyn HirDb) -> Option { + pub fn container_id(self, db: &dyn HirDb) -> Option { let origins = self.origins(db); let container_id = origins.first().map(|origin| origin.container_id(db))?; debug_assert! { diff --git a/crates/hir/src/hir_def/aggregate.rs b/crates/hir/src/hir_def/aggregate.rs index f12acfec..6165b6d5 100644 --- a/crates/hir/src/hir_def/aggregate.rs +++ b/crates/hir/src/hir_def/aggregate.rs @@ -10,7 +10,7 @@ use utils::text_edit::TextRange; use super::{Ident, expr::data_ty::DataTy, lower_ident_opt}; use crate::{ - container::{ContainerId, InContainer}, + container::{InContainer, ScopeId}, source_map::{FromSourceAst, IsNamedSrc, IsSrc, SourceAst, ToAstNode, root_token_in}, }; @@ -40,7 +40,7 @@ pub type StructId = Idx; pub(crate) fn lower_struct_def( struct_ty: StructUnionType, - container_id: ContainerId, + container_id: ScopeId, mut lower_data_ty: impl FnMut(DataType) -> DataTy, ) -> StructDef { let kind = match struct_ty { diff --git a/crates/hir/src/hir_def/block.rs b/crates/hir/src/hir_def/block.rs index e7022626..9d475d53 100644 --- a/crates/hir/src/hir_def/block.rs +++ b/crates/hir/src/hir_def/block.rs @@ -33,7 +33,7 @@ use super::{ }; use crate::{ base_db::intern::Lookup, - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, region_tree::{RegionTree, RegionTreeBuilder}, @@ -212,7 +212,7 @@ pub struct BlockId(pub salsa::InternId); #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct BlockLoc { - pub cont_id: ContainerId, + pub cont_id: ScopeId, pub src: InFile, } @@ -235,7 +235,7 @@ impl_lower_declaration!(LowerBlockCtx<'_>, block, block_source_map); impl LowerBlockCtx<'_> { fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { - let container_id = ContainerId::BlockId(self.block_id); + let container_id = ScopeId::Block(self.block_id); let struct_def = lower_struct_def(struct_ty, container_id, |ty| self.expr_ctx().lower_data_ty(ty)); @@ -259,7 +259,7 @@ impl LowerBlockCtx<'_> { let lowered_ty = lower_typedef_data_ty( self, data_ty, - ContainerId::BlockId(self.block_id), + ScopeId::Block(self.block_id), |ctx, struct_ty| ctx.lower_struct_type(struct_ty), |ctx, ty| ctx.expr_ctx().lower_data_ty(ty), ); diff --git a/crates/hir/src/hir_def/file.rs b/crates/hir/src/hir_def/file.rs index 61d77714..a8957618 100644 --- a/crates/hir/src/hir_def/file.rs +++ b/crates/hir/src/hir_def/file.rs @@ -36,7 +36,7 @@ use super::{ typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }; use crate::{ - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::lower_ident_opt, @@ -175,7 +175,7 @@ impl LowerProc for LowerFileCtx<'_> { impl LowerFileCtx<'_> { fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { - let container_id = ContainerId::HirFileId(self.file_id); + let container_id = ScopeId::File(self.file_id); let struct_def = lower_struct_def(struct_ty, container_id, |ty| self.expr_ctx().lower_data_ty(ty)); @@ -198,7 +198,7 @@ impl LowerFileCtx<'_> { let lowered_ty = lower_typedef_data_ty( self, data_ty, - ContainerId::HirFileId(self.file_id), + ScopeId::File(self.file_id), |ctx, struct_ty| ctx.lower_struct_type(struct_ty), |ctx, ty| ctx.expr_ctx().lower_data_ty(ty), ); diff --git a/crates/hir/src/hir_def/module.rs b/crates/hir/src/hir_def/module.rs index c8ceeb41..ef8796b7 100644 --- a/crates/hir/src/hir_def/module.rs +++ b/crates/hir/src/hir_def/module.rs @@ -53,7 +53,7 @@ use super::{ typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }; use crate::{ - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, region_tree::{RegionTree, RegionTreeBuilder}, @@ -355,7 +355,7 @@ impl LowerProc for LowerModuleCtx<'_> { impl LowerModuleCtx<'_> { fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { - let container_id = ContainerId::ModuleId(self.module_id); + let container_id = ScopeId::Module(self.module_id); let struct_def = lower_struct_def(struct_ty, container_id, |ty| self.expr_ctx().lower_data_ty(ty)); @@ -379,7 +379,7 @@ impl LowerModuleCtx<'_> { let lowered_ty = lower_typedef_data_ty( self, data_ty, - ContainerId::ModuleId(self.module_id), + ScopeId::Module(self.module_id), |ctx, struct_ty| ctx.lower_struct_type(struct_ty), |ctx, ty| ctx.expr_ctx().lower_data_ty(ty), ); diff --git a/crates/hir/src/hir_def/module/generate.rs b/crates/hir/src/hir_def/module/generate.rs index 78ee6b5f..0cfbc778 100644 --- a/crates/hir/src/hir_def/module/generate.rs +++ b/crates/hir/src/hir_def/module/generate.rs @@ -24,7 +24,7 @@ use super::{ }; use crate::{ base_db::intern::Lookup, - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::{ @@ -397,7 +397,7 @@ pub struct GenerateBlockId(pub salsa::InternId); #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct GenerateBlockLoc { - pub cont_id: ContainerId, + pub cont_id: ScopeId, pub src: InFile, } @@ -453,7 +453,7 @@ impl LowerProc for LowerGenerateBlockCtx<'_> { impl LowerGenerateBlockCtx<'_> { fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { - let container_id = ContainerId::GenerateBlockId(self.generate_block_id); + let container_id = ScopeId::GenerateBlock(self.generate_block_id); let struct_def = lower_struct_def(struct_ty, container_id, |ty| self.expr_ctx().lower_data_ty(ty)); @@ -477,7 +477,7 @@ impl LowerGenerateBlockCtx<'_> { let lowered_ty = lower_typedef_data_ty( self, data_ty, - ContainerId::GenerateBlockId(self.generate_block_id), + ScopeId::GenerateBlock(self.generate_block_id), |ctx, struct_ty| ctx.lower_struct_type(struct_ty), |ctx, ty| ctx.expr_ctx().lower_data_ty(ty), ); diff --git a/crates/hir/src/hir_def/proc.rs b/crates/hir/src/hir_def/proc.rs index 670feb7a..fe066216 100644 --- a/crates/hir/src/hir_def/proc.rs +++ b/crates/hir/src/hir_def/proc.rs @@ -6,7 +6,7 @@ use super::{ stmt::impl_lower_stmt, }; use crate::{ - container::ContainerId, + container::ScopeId, db::InternDb, file::HirFileId, hir_def::{ @@ -62,7 +62,7 @@ pub(crate) trait LowerProc: LowerStmt { pub(crate) struct LowerProcCtx<'a> { pub(crate) db: &'a dyn InternDb, pub(crate) file_id: HirFileId, - pub(crate) cont_id: ContainerId, + pub(crate) cont_id: ScopeId, pub(crate) procs: &'a mut Arena, pub(crate) proc_srcs: &'a mut SourceMap, diff --git a/crates/hir/src/hir_def/stmt.rs b/crates/hir/src/hir_def/stmt.rs index e65822a9..675161c6 100644 --- a/crates/hir/src/hir_def/stmt.rs +++ b/crates/hir/src/hir_def/stmt.rs @@ -20,7 +20,7 @@ use super::{ lower_ident_opt, }; use crate::{ - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::InternDb, file::HirFileId, hir_def::{alloc_idx_and_src, lower_named_label_opt}, @@ -180,7 +180,7 @@ pub(in crate::hir_def) macro impl_lower_stmt { pub(crate) struct LowerStmtCtx<'a> { pub(crate) db: &'a dyn InternDb, pub(crate) file_id: HirFileId, - pub(crate) cont_id: ContainerId, + pub(crate) cont_id: ScopeId, pub(crate) stmts: &'a mut Arena, pub(crate) stmt_srcs: &'a mut SourceMap, diff --git a/crates/hir/src/hir_def/subroutine.rs b/crates/hir/src/hir_def/subroutine.rs index 9f30953f..4dbf2102 100644 --- a/crates/hir/src/hir_def/subroutine.rs +++ b/crates/hir/src/hir_def/subroutine.rs @@ -31,7 +31,7 @@ use super::{ }; use crate::{ base_db::intern::Lookup, - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::{ @@ -176,7 +176,7 @@ impl From for SubroutineContainerId { } } -impl From for ContainerId { +impl From for ScopeId { fn from(cont_id: SubroutineContainerId) -> Self { match cont_id { SubroutineContainerId::HirFileId(file_id) => file_id.into(), @@ -186,15 +186,15 @@ impl From for ContainerId { } } -impl TryFrom for SubroutineContainerId { +impl TryFrom for SubroutineContainerId { type Error = (); - fn try_from(cont_id: ContainerId) -> Result { + fn try_from(cont_id: ScopeId) -> Result { match cont_id { - ContainerId::HirFileId(file_id) => Ok(file_id.into()), - ContainerId::ModuleId(module_id) => Ok(module_id.into()), - ContainerId::GenerateBlockId(generate_block_id) => Ok(generate_block_id.into()), - ContainerId::BlockId(_) | ContainerId::SubroutineId(_) => Err(()), + ScopeId::File(file_id) => Ok(file_id.into()), + ScopeId::Module(module_id) => Ok(module_id.into()), + ScopeId::GenerateBlock(generate_block_id) => Ok(generate_block_id.into()), + ScopeId::Block(_) | ScopeId::Subroutine(_) => Err(()), } } } @@ -279,8 +279,8 @@ impl_lower_stmt!(LowerSubroutineBodyCtx<'_>, subroutine_id, subroutine, subrouti impl_lower_declaration!(LowerSubroutineBodyCtx<'_>, subroutine, subroutine_source_map); impl LowerSubroutineBodyCtx<'_> { - fn container_id(&self) -> ContainerId { - ContainerId::SubroutineId(self.subroutine_id) + fn container_id(&self) -> ScopeId { + ScopeId::Subroutine(self.subroutine_id) } fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { diff --git a/crates/hir/src/hir_def/typedef.rs b/crates/hir/src/hir_def/typedef.rs index 4e3088f9..5800e5e2 100644 --- a/crates/hir/src/hir_def/typedef.rs +++ b/crates/hir/src/hir_def/typedef.rs @@ -9,7 +9,7 @@ use utils::text_edit::TextRange; use super::{Ident, aggregate::StructId, expr::data_ty::DataTy}; use crate::{ - container::{ContainerId, InContainer}, + container::{InContainer, ScopeId}, source_map::{FromSourceAst, IsNamedSrc, IsSrc, SourceAst, ToAstNode, root_token_in}, }; @@ -92,7 +92,7 @@ impl TypedefSrc { pub(crate) fn lower_typedef_data_ty( ctx: &mut Ctx, data_ty: ast::DataType, - container_id: ContainerId, + container_id: ScopeId, mut lower_struct_type: impl FnMut(&mut Ctx, ast::StructUnionType) -> StructId, mut lower_data_ty: impl FnMut(&mut Ctx, ast::DataType) -> DataTy, ) -> DataTy { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 246eb1a5..930e9722 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -12,7 +12,7 @@ use utils::text_edit::TextSize; use vfs::FileId; use crate::{ - container::{ContainerId, InContainer, InFile}, + container::{InContainer, InFile, ScopeId}, db::HirDb, file::HirFileId, hir_def::{ @@ -114,7 +114,7 @@ impl<'db> SemanticsImpl<'db> { ParsedFile { file_id, tree: self.db.parse(file_id) } } - pub fn container_for_node(&self, file_id: HirFileId, node: SyntaxNode) -> Option { + pub fn container_for_node(&self, file_id: HirFileId, node: SyntaxNode) -> Option { self.with_ctx(|ctx| Some(ctx.find_container(InFile::new(file_id, node)))) } diff --git a/crates/hir/src/semantics/hir_to_def.rs b/crates/hir/src/semantics/hir_to_def.rs index 93f1ab60..8afda2ab 100644 --- a/crates/hir/src/semantics/hir_to_def.rs +++ b/crates/hir/src/semantics/hir_to_def.rs @@ -4,7 +4,7 @@ use utils::get::GetRef; use super::{Source2DefCtx, pathres::PathResolution}; use crate::{ container::{ - ContainerId, ContainerParent, InBlock, InContainer, InGenerateBlock, InModule, InSubroutine, + InBlock, InContainer, InGenerateBlock, InModule, InSubroutine, ScopeId, ScopeParent, }, hir_def::{ Ident, @@ -49,23 +49,23 @@ impl Source2DefCtx<'_, '_> { }; match cont_id { - ContainerId::HirFileId(file_id) => { + ScopeId::File(file_id) => { let file = db.hir_file(file_id); resolve(file.get(expr_id)) } - ContainerId::ModuleId(in_file) => { + ScopeId::Module(in_file) => { let module = db.module(in_file); resolve(module.get(expr_id)) } - ContainerId::BlockId(block_id) => { + ScopeId::Block(block_id) => { let block = db.block(block_id); resolve(block.get(expr_id)) } - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let generate_block = db.generate_block(generate_block_id); resolve(generate_block.get(expr_id)) } - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Subroutine(subroutine_id) => { let subroutine = db.subroutine(subroutine_id); resolve(subroutine.get(expr_id)) } @@ -77,28 +77,28 @@ impl Source2DefCtx<'_, '_> { InContainer { cont_id, value: ident }: InContainer, ) -> Option { let db = self.db; - let res = ContainerParent::start_from(db, cont_id).find_map(|id| match id { - ContainerId::HirFileId(_) => { + let res = ScopeParent::start_from(db, cont_id).find_map(|id| match id { + ScopeId::File(_) => { let scope = db.unit_scope(); let entry = scope.get(&ident)?; Some(entry.into()) } - ContainerId::ModuleId(module_id) => { + ScopeId::Module(module_id) => { let scope = db.module_scope(module_id); let entry = scope.get(&ident)?; Some(InModule::new(module_id, entry).into()) } - ContainerId::BlockId(block_id) => { + ScopeId::Block(block_id) => { let scope = db.block_scope(block_id); let entry = scope.get(&ident)?; Some(InBlock::new(block_id, entry).into()) } - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let scope = db.generate_block_scope(generate_block_id); let entry = scope.get(&ident)?; Some(InGenerateBlock::new(generate_block_id, entry).into()) } - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Subroutine(subroutine_id) => { let scope = db.subroutine_scope(subroutine_id); let entry = scope.get(&ident)?; Some(InSubroutine::new(subroutine_id, entry).into()) diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index 5087276b..a192e7a5 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -4,8 +4,7 @@ use syntax::{SyntaxNode, SyntaxTokenWithParent}; use super::SemanticsImpl; use crate::{ container::{ - ContainerId, ContainerParent, InBlock, InContainer, InFile, InGenerateBlock, InModule, - InSubroutine, + InBlock, InContainer, InFile, InGenerateBlock, InModule, InSubroutine, ScopeId, ScopeParent, }, db::HirDb, def_id::{ModuleDef, ModuleDefId, ModuleDefOrigin}, @@ -40,31 +39,31 @@ impl SemanticsImpl<'_> { }) } - pub(in crate::semantics) fn find_container(&self, node: InFile) -> ContainerId { + pub(in crate::semantics) fn find_container(&self, node: InFile) -> ScopeId { self.with_ctx(|ctx| ctx.find_container(node)) } - pub fn resolve_name(&self, cont_id: ContainerId, ident: &Ident) -> Option { + pub fn resolve_name(&self, cont_id: ScopeId, ident: &Ident) -> Option { resolve_name(self.db, cont_id, ident) } } -pub fn resolve_name(db: &dyn HirDb, cont_id: ContainerId, ident: &Ident) -> Option { - ContainerParent::start_from(db, cont_id).find_map(|id| match id { - ContainerId::HirFileId(_) => db.unit_scope().get(ident).map(PathResolution::from), - ContainerId::ModuleId(module_id) => db +pub fn resolve_name(db: &dyn HirDb, cont_id: ScopeId, ident: &Ident) -> Option { + ScopeParent::start_from(db, cont_id).find_map(|id| match id { + ScopeId::File(_) => db.unit_scope().get(ident).map(PathResolution::from), + ScopeId::Module(module_id) => db .module_scope(module_id) .get(ident) .map(|entry| PathResolution::from(InModule::new(module_id, entry))), - ContainerId::GenerateBlockId(generate_block_id) => db + ScopeId::GenerateBlock(generate_block_id) => db .generate_block_scope(generate_block_id) .get(ident) .map(|entry| PathResolution::from(InGenerateBlock::new(generate_block_id, entry))), - ContainerId::BlockId(block_id) => db + ScopeId::Block(block_id) => db .block_scope(block_id) .get(ident) .map(|entry| PathResolution::from(InBlock::new(block_id, entry))), - ContainerId::SubroutineId(subroutine_id) => db + ScopeId::Subroutine(subroutine_id) => db .subroutine_scope(subroutine_id) .get(ident) .map(|entry| PathResolution::from(InSubroutine::new(subroutine_id, entry))), @@ -108,7 +107,7 @@ impl PathResolution { match self { PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ContainerId = module.into(); + let container: ScopeId = module.into(); if let Some(label) = label { add_source(InModule::new(module, label).into()); } @@ -148,7 +147,7 @@ impl PathResolution { Some(InContainer::new(decl_id.module_id.into(), decl_id.value).into()) } PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ContainerId = module.into(); + let container: ScopeId = module.into(); if let Some(label) = label { Some(InModule::new(module, label).into()) } else if let Some(port_decl) = port_decl { diff --git a/crates/hir/src/semantics/resolver.rs b/crates/hir/src/semantics/resolver.rs index 478b7122..b329f7ac 100644 --- a/crates/hir/src/semantics/resolver.rs +++ b/crates/hir/src/semantics/resolver.rs @@ -3,7 +3,7 @@ use utils::get::Get; use super::SemanticsImpl; use crate::{ - container::{ContainerId, InContainer, InFile, InModule}, + container::{InContainer, InFile, InModule, ScopeId}, file::HirFileId, hir_def::{ expr::{ExprId, ExprSrc}, @@ -22,7 +22,7 @@ impl SemanticsImpl<'_> { instance: ast::HierarchicalInstance, ) -> Option> { let db = self.db; - let ContainerId::ModuleId(module_id) = + let ScopeId::Module(module_id) = self.find_container(InFile::new(file_id, instance.syntax())) else { return None; @@ -40,7 +40,7 @@ impl SemanticsImpl<'_> { instantiation: ast::HierarchyInstantiation, ) -> Option> { let db = self.db; - let ContainerId::ModuleId(module_id) = + let ScopeId::Module(module_id) = self.find_container(InFile::new(file_id, instantiation.syntax())) else { return None; @@ -60,8 +60,7 @@ impl SemanticsImpl<'_> { conn: ast::PortConnection, ) -> Option> { let db = self.db; - let ContainerId::ModuleId(module_id) = - self.find_container(InFile::new(file_id, conn.syntax())) + let ScopeId::Module(module_id) = self.find_container(InFile::new(file_id, conn.syntax())) else { return None; }; diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 779d9012..b08e52b5 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -9,7 +9,7 @@ use utils::get::{Get, GetRef}; use super::hir_to_def::Hir2DefCache; use crate::{ - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, db::HirDb, file::HirFileId, hir_def::{ @@ -27,7 +27,7 @@ use crate::{ #[derive(Default, Debug)] pub(super) struct Source2DefCache { - container_map: FxHashMap, ContainerId>, + container_map: FxHashMap, ScopeId>, } pub(super) struct Source2DefCtx<'db, 'cache> { @@ -74,28 +74,28 @@ impl Source2DefCtx<'_, '_> { let container = self.find_container(InFile::new(file_id, node)); let block_id = match container { - ContainerId::HirFileId(file_id) => { + ScopeId::File(file_id) => { let (file, file_src_map) = self.db.hir_file_with_source_map(file_id); let local_block_id = find_local_block_id(&file_src_map.stmt_srcs, block_src)?; file.get(local_block_id).block_id } - ContainerId::ModuleId(module_id) => { + ScopeId::Module(module_id) => { let (module, module_src_map) = self.db.module_with_source_map(module_id); let local_block_id = find_local_block_id(&module_src_map.stmt_srcs, block_src)?; module.get(local_block_id).block_id } - ContainerId::BlockId(block_id) => { + ScopeId::Block(block_id) => { let (block, block_src_map) = self.db.block_with_source_map(block_id); let local_block_id = *block_src_map.block_srcs.get(&block_src)?; block.get(local_block_id).block_id } - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let (generate_block, generate_block_src_map) = self.db.generate_block_with_source_map(generate_block_id); let local_block_id = generate_block_src_map.get(block_src)?; generate_block.get(local_block_id).block_id } - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Subroutine(subroutine_id) => { let (subroutine, subroutine_src_map) = self.db.subroutine_with_source_map(subroutine_id); let local_block_id = *subroutine_src_map.block_srcs.get(&block_src)?; @@ -106,7 +106,7 @@ impl Source2DefCtx<'_, '_> { Some(block_id) } - fn container_to_def(&mut self, file_id: HirFileId, node: SyntaxNode) -> Option { + fn container_to_def(&mut self, file_id: HirFileId, node: SyntaxNode) -> Option { let cont_id = match_ast! { node, ast::ModuleDeclaration[module] => { let src = ModuleSrc::from_ast(file_id, module); @@ -194,7 +194,7 @@ impl Source2DefCtx<'_, '_> { &mut self, file_id: HirFileId, member: ast::Member, - ) -> Option { + ) -> Option { if matches!(member, ast::Member::GenerateBlock(_) | ast::Member::LoopGenerate(_)) { return None; } @@ -242,7 +242,7 @@ impl Source2DefCtx<'_, '_> { pub(super) fn find_container( &mut self, InFile { value: node, file_id }: InFile, - ) -> ContainerId { + ) -> ScopeId { let in_file = InFile::new(file_id, SyntaxNodePtr::from_node(node)); if let Some(container_id) = self.source_cache.container_map.get(&in_file) { diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs index 8a51c3d7..34eb74ee 100644 --- a/crates/hir/src/symbol.rs +++ b/crates/hir/src/symbol.rs @@ -4,9 +4,8 @@ use utils::impl_from; use crate::{ base_db::salsa, - container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, + container::{InContainer, InFile, InModule, InSubroutine}, db::InternDb, - file::HirFileId, hir_def::{ Ident, block::BlockId, @@ -219,49 +218,6 @@ impl DefKind { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct ScopeId(pub salsa::InternId); - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum ScopeLoc { - File(HirFileId), - Module(ModuleId), - GenerateBlock(GenerateBlockId), - Block(BlockId), - Subroutine(SubroutineId), -} - -impl_from! { ScopeLoc => - File(HirFileId), - Module(ModuleId), - GenerateBlock(GenerateBlockId), - Block(BlockId), - Subroutine(SubroutineId), -} - -impl From for ScopeLoc { - fn from(cont_id: ContainerId) -> Self { - match cont_id { - ContainerId::HirFileId(id) => ScopeLoc::File(id), - ContainerId::ModuleId(id) => ScopeLoc::Module(id), - ContainerId::GenerateBlockId(id) => ScopeLoc::GenerateBlock(id), - ContainerId::BlockId(id) => ScopeLoc::Block(id), - ContainerId::SubroutineId(id) => ScopeLoc::Subroutine(id), - } - } -} - -impl ScopeId { - pub fn new(db: &dyn InternDb, loc: impl Into) -> Self { - db.intern_scope(loc.into()) - } - - pub fn loc(self, db: &dyn InternDb) -> ScopeLoc { - db.lookup_intern_scope(self) - } -} - #[non_exhaustive] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ScopeKind { diff --git a/crates/hir/src/type_infer.rs b/crates/hir/src/type_infer.rs index 4bf8ba00..1a777354 100644 --- a/crates/hir/src/type_infer.rs +++ b/crates/hir/src/type_infer.rs @@ -3,7 +3,7 @@ use triomphe::Arc; use utils::get::GetRef; use crate::{ - container::{ContainerId, InContainer, InGenerateBlock, InModule, InSubroutine}, + container::{InContainer, InGenerateBlock, InModule, InSubroutine, ScopeId}, db::HirDb, hir_def::{ Ident, @@ -25,7 +25,7 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinTy { - Data { id: BuiltinDataTyId, container: ContainerId }, + Data { id: BuiltinDataTyId, container: ScopeId }, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -72,7 +72,7 @@ pub enum TyClass { String, } -pub fn normalize_data_ty(db: &dyn HirDb, container: ContainerId, data_ty: DataTy) -> TyResult { +pub fn normalize_data_ty(db: &dyn HirDb, container: ScopeId, data_ty: DataTy) -> TyResult { normalize_data_ty_inner(db, container, data_ty, &mut FxHashSet::default()) } @@ -268,7 +268,7 @@ pub fn packed_bit_width(db: &dyn HirDb, ty: &Ty) -> Option { fn normalize_data_ty_inner( db: &dyn HirDb, - container: ContainerId, + container: ScopeId, data_ty: DataTy, seen: &mut FxHashSet>, ) -> TyResult { @@ -290,7 +290,7 @@ fn normalize_data_ty_inner( fn type_of_named_data_ty( db: &dyn HirDb, - container: ContainerId, + container: ScopeId, named: NamedDataTy, seen: &mut FxHashSet>, ) -> TyResult { @@ -417,8 +417,8 @@ fn data_ty_of_decl(db: &dyn HirDb, decl: InContainer) -> Option } } -fn port_decl_ty(db: &dyn HirDb, cont_id: ContainerId, port_decl_id: PortDeclId) -> Option { - let ContainerId::ModuleId(module_id) = cont_id else { +fn port_decl_ty(db: &dyn HirDb, cont_id: ScopeId, port_decl_id: PortDeclId) -> Option { + let ScopeId::Module(module_id) = cont_id else { return None; }; let module = db.module(module_id); @@ -427,7 +427,7 @@ fn port_decl_ty(db: &dyn HirDb, cont_id: ContainerId, port_decl_id: PortDeclId) fn for_init_decl_ty( db: &dyn HirDb, - cont_id: ContainerId, + cont_id: ScopeId, stmt_id: crate::hir_def::stmt::StmtId, decl_id: DeclId, ) -> Option { @@ -445,7 +445,7 @@ fn type_of_subroutine_port_impl(db: &dyn HirDb, port: InSubroutine usize { } } -fn eval_const_i128(db: &dyn HirDb, container: ContainerId, expr_id: ExprId) -> Option { +fn eval_const_i128(db: &dyn HirDb, container: ScopeId, expr_id: ExprId) -> Option { match expr_of(db, InContainer::new(container, expr_id))? { Expr::Literal(Literal::Int(int)) => int.get_single_word().map(|v| v as i128), Expr::Unary { op, expr } => { @@ -510,13 +510,13 @@ fn eval_const_i128(db: &dyn HirDb, container: ContainerId, expr_id: ExprId) -> O fn expr_of(db: &dyn HirDb, expr: InContainer) -> Option { match expr.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(expr.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(expr.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(expr.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(expr.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(expr.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(expr.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(expr.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(expr.value).clone()) } } @@ -527,13 +527,13 @@ fn decl_of( decl: InContainer, ) -> Option { match decl.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(decl.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(decl.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(decl.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(decl.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(decl.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(decl.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(decl.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(decl.value).clone()) } } @@ -544,13 +544,13 @@ fn declaration_of( decl: InContainer, ) -> Option { match decl.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(decl.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(decl.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(decl.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(decl.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(decl.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(decl.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(decl.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(decl.value).clone()) } } @@ -561,13 +561,13 @@ fn typedef_of( typedef: InContainer, ) -> Option { match typedef.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(typedef.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(typedef.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(typedef.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(typedef.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(typedef.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(typedef.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(typedef.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(typedef.value).clone()) } } @@ -578,13 +578,13 @@ fn struct_of( struct_id: InContainer, ) -> Option { match struct_id.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(struct_id.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(struct_id.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(struct_id.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(struct_id.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(struct_id.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(struct_id.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(struct_id.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(struct_id.value).clone()) } } @@ -595,13 +595,13 @@ fn stmt_of( stmt: InContainer, ) -> Option { match stmt.cont_id { - ContainerId::HirFileId(file_id) => Some(db.hir_file(file_id).get(stmt.value).clone()), - ContainerId::ModuleId(module_id) => Some(db.module(module_id).get(stmt.value).clone()), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => Some(db.hir_file(file_id).get(stmt.value).clone()), + ScopeId::Module(module_id) => Some(db.module(module_id).get(stmt.value).clone()), + ScopeId::GenerateBlock(generate_block_id) => { Some(db.generate_block(generate_block_id).get(stmt.value).clone()) } - ContainerId::BlockId(block_id) => Some(db.block(block_id).get(stmt.value).clone()), - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Block(block_id) => Some(db.block(block_id).get(stmt.value).clone()), + ScopeId::Subroutine(subroutine_id) => { Some(db.subroutine(subroutine_id).get(stmt.value).clone()) } } diff --git a/crates/ide/src/completion/engine/expr.rs b/crates/ide/src/completion/engine/expr.rs index c38add31..0f85f0ff 100644 --- a/crates/ide/src/completion/engine/expr.rs +++ b/crates/ide/src/completion/engine/expr.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use hir::{ - container::{ContainerId, ContainerParent, InContainer, InSubroutine}, + container::{InContainer, InSubroutine, ScopeId, ScopeParent}, db::HirDb, file::HirFileId, hir_def::{ @@ -68,7 +68,7 @@ fn complete_expression_impl( if let Some(container_id) = container_id_at_offset(&sema, file_id, root, position.offset) { current_module_id = module_id_for_container(db, container_id); - for container_id in ContainerParent::start_from(db, container_id) { + for container_id in ScopeParent::start_from(db, container_id) { collect_container_names(db, container_id, &mut names); } } @@ -102,7 +102,7 @@ fn container_id_at_offset( file_id: HirFileId, root: SyntaxNode<'_>, offset: TextSize, -) -> Option { +) -> Option { let elem = root.covering_element(utils::line_index::TextRange::empty(offset)); let node = elem.as_node().or_else(|| elem.parent())?; sema.container_for_node(file_id, node) @@ -110,13 +110,13 @@ fn container_id_at_offset( fn collect_container_names( db: &RootDb, - container_id: ContainerId, + container_id: ScopeId, names: &mut BTreeMap, ) { match container_id { - ContainerId::HirFileId(file_id) => collect_file_names(db, file_id, names), - ContainerId::ModuleId(module_id) => collect_module_names(db, module_id, names), - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::File(file_id) => collect_file_names(db, file_id, names), + ScopeId::Module(module_id) => collect_module_names(db, module_id, names), + ScopeId::GenerateBlock(generate_block_id) => { let scope = db.generate_block_scope(generate_block_id); for (ident, entry) in scope.iter() { match entry { @@ -134,7 +134,7 @@ fn collect_container_names( } } } - ContainerId::BlockId(block_id) => { + ScopeId::Block(block_id) => { let scope = db.block_scope(block_id); for (ident, entry) in scope.iter() { if let BlockEntry::DeclId(decl_id) = entry { @@ -144,7 +144,7 @@ fn collect_container_names( } } } - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Subroutine(subroutine_id) => { let scope = db.subroutine_scope(subroutine_id); for (ident, entry) in scope.iter() { match entry { @@ -175,7 +175,7 @@ fn collect_file_names(db: &RootDb, file_id: HirFileId, names: &mut BTreeMap Ty { match db.subroutine(subroutine_id).kind { SubroutineKind::Function { return_ty: Some(return_ty) } => { - normalize_data_ty(db, ContainerId::SubroutineId(subroutine_id), return_ty).ty + normalize_data_ty(db, ScopeId::Subroutine(subroutine_id), return_ty).ty } SubroutineKind::Function { return_ty: None } | SubroutineKind::Task => Ty::Unknown, } } -fn module_id_for_container(db: &RootDb, container_id: ContainerId) -> Option { - ContainerParent::start_from(db, container_id).find_map(|container_id| match container_id { - ContainerId::ModuleId(module_id) => Some(module_id), +fn module_id_for_container(db: &RootDb, container_id: ScopeId) -> Option { + ScopeParent::start_from(db, container_id).find_map(|container_id| match container_id { + ScopeId::Module(module_id) => Some(module_id), _ => None, }) } diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index c0ec3d67..09b19a57 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -1,6 +1,6 @@ use hir::{ base_db::intern::Lookup, - container::{ContainerId, InContainer, InFile, InModule, InSubroutine}, + container::{InContainer, InFile, InModule, InSubroutine, ScopeId}, db::HirDb, def_id::ModuleDefOrigin, hir_def::{ @@ -171,7 +171,7 @@ impl ToNav for GenerateBlockId { impl ToNav for SubroutineId { fn to_nav(&self, db: &RootDb) -> Option { let loc = self.lookup(db); - let cont_id: ContainerId = loc.cont_id.into(); + let cont_id: ScopeId = loc.cont_id.into(); let cont_name = cont_id.to_container(db).name().cloned(); let name = db.subroutine(*self).name.clone(); let focus_range = loc.src.value.name_range(); diff --git a/crates/ide/src/references/search.rs b/crates/ide/src/references/search.rs index 5509e50f..62d727c9 100644 --- a/crates/ide/src/references/search.rs +++ b/crates/ide/src/references/search.rs @@ -5,7 +5,7 @@ use hir::{ source_db::{SourceDb, SourceRootDb}, source_root::SourceRootId, }, - container::{ContainerId, InFile}, + container::{InFile, ScopeId}, def_id::ModuleDefId, semantics::Semantics, source_map::IsSrc, @@ -46,9 +46,7 @@ impl SearchScope { return search_scope.unwrap_or_default(); }; let container_id = match container_id { - ContainerId::ModuleId(InFile { file_id, .. }) if def.is_port(db) => { - file_id.into() - } + ScopeId::Module(InFile { file_id, .. }) if def.is_port(db) => file_id.into(), cont => cont, }; @@ -73,10 +71,10 @@ impl SearchScope { SearchScope(res) } - fn from_conts(db: &RootDb, cont: ContainerId) -> Self { + fn from_conts(db: &RootDb, cont: ScopeId) -> Self { match cont { - ContainerId::HirFileId(_) => Self::all(db), - ContainerId::ModuleId(InFile { value: local_module_id, file_id }) => { + ScopeId::File(_) => Self::all(db), + ScopeId::Module(InFile { value: local_module_id, file_id }) => { if let Some(range) = file_id.to_container_src_map(db).get(local_module_id).map(|src| src.range()) { @@ -85,15 +83,15 @@ impl SearchScope { Self::all(db) } } - ContainerId::BlockId(block_id) => { + ScopeId::Block(block_id) => { let range = block_id.lookup(db).src.value.range(); Self::single_range(block_id.file_id(db), range) } - ContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let src = generate_block_id.lookup(db).src; Self::single_range(src.file_id.file_id(), src.value.range()) } - ContainerId::SubroutineId(subroutine_id) => { + ScopeId::Subroutine(subroutine_id) => { let src = subroutine_id.lookup(db).src; Self::single_range(src.file_id.file_id(), src.value.range()) } diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index 9237a1f5..22249997 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -3,7 +3,7 @@ use hir::{ intern::Lookup, source_db::{SourceDb, SourceRootDb}, }, - container::{ContainerId, ContainerParent, InContainer, InFile, InModule, InSubroutine}, + container::{InContainer, InFile, InModule, InSubroutine, ScopeId, ScopeParent}, db::HirDb, def_id::{ModuleDefId, ModuleDefOrigin}, display::HirDisplay, @@ -525,7 +525,7 @@ fn render_decl_signature(db: &RootDb, decl_id: InContainer) -> Option { - let ContainerId::ModuleId(module_id) = decl_id.cont_id else { + let ScopeId::Module(module_id) = decl_id.cont_id else { return None; }; let module = db.module(module_id); @@ -555,7 +555,7 @@ fn render_decl_signature(db: &RootDb, decl_id: InContainer) -> Option Option { let ty = render_data_ty(db, cont_id, declaration.ty()).unwrap_or_default(); @@ -615,7 +615,7 @@ fn render_initializer(db: &RootDb, decl_id: InContainer) -> Option Option { +fn render_data_ty(db: &RootDb, container: ScopeId, ty: DataTy) -> Option { InContainer::new(container, ty).display_source(db).ok() } @@ -685,7 +685,7 @@ fn render_scope_fact(sema: &Semantics, origin: &ModuleDefOrigin) -> Opti let mut containers = Vec::new(); - for cont_id in ContainerParent::start_from(db, cont_id) { + for cont_id in ScopeParent::start_from(db, cont_id) { let src_map = cont_id.to_container_src_map(db); if let Some(region_tree) = src_map.region_tree() @@ -696,7 +696,7 @@ fn render_scope_fact(sema: &Semantics, origin: &ModuleDefOrigin) -> Opti } } - if !matches!(cont_id, ContainerId::HirFileId(_)) { + if !matches!(cont_id, ScopeId::File(_)) { if let Some(name) = cont_id.to_container(db).name() { containers.push(name.to_string()); } else { From 88807ba93ceacf78f9da381c1f16dcd62ea11736 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 03:31:38 +0800 Subject: [PATCH 4/7] refactor(hir): cut over scopes to def ids (cherry picked from commit a2d0d47760bbe2ad1324adb447a48de87041d4ab) --- crates/hir/src/db.rs | 27 +- crates/hir/src/def_id.rs | 172 ++--- crates/hir/src/scope.rs | 648 +++++++++--------- crates/hir/src/semantics/hir_to_def.rs | 102 ++- crates/hir/src/semantics/pathres.rs | 221 ++---- crates/hir/src/symbol.rs | 129 ++++ crates/hir/src/type_infer.rs | 136 ++-- .../handlers/convert_port_declarations.rs | 30 +- crates/ide/src/code_lens.rs | 6 +- crates/ide/src/completion/engine/expr.rs | 126 ++-- crates/ide/src/completion/engine/keywords.rs | 5 +- .../ide/src/completion/engine/paren_list.rs | 8 +- crates/ide/src/completion/engine/port_list.rs | 32 +- .../ide/src/completion/engine/typed_filter.rs | 63 +- crates/ide/src/definitions.rs | 28 +- crates/ide/src/inlay_hint.rs | 60 +- crates/ide/src/lib.rs | 66 +- crates/ide/src/module_resolution.rs | 65 +- crates/ide/src/navigation_target.rs | 30 +- crates/ide/src/rename.rs | 22 +- crates/ide/src/render.rs | 20 +- crates/ide/src/semantic_index.rs | 25 +- crates/ide/src/semantic_tokens.rs | 86 ++- crates/ide/src/semantic_tokens/port.rs | 39 +- 24 files changed, 1099 insertions(+), 1047 deletions(-) diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 4a57328f..b1b3cae5 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -27,9 +27,8 @@ use crate::{ typedef::TypedefId, }, impl_intern_key, impl_intern_lookup, - scope::{BlockScope, GenerateBlockScope, ModuleScope, SubroutineScope, UnitScope}, semantics::pathres::PathResolution, - symbol::{DefId, DefLoc}, + symbol::{DefId, DefLoc, NameScope}, type_infer::TyResult, }; @@ -118,23 +117,23 @@ pub trait HirDb: InternDb { fn generate_block(&self, generate_block_id: GenerateBlockId) -> Arc; - #[salsa::invoke(UnitScope::unit_scope_query)] - fn unit_scope(&self) -> Arc; + #[salsa::invoke(NameScope::unit_scope_query)] + fn unit_scope(&self) -> Arc; - #[salsa::invoke(UnitScope::file_scope_query)] - fn file_scope(&self, file_id: HirFileId) -> Arc; + #[salsa::invoke(NameScope::file_scope_query)] + fn file_scope(&self, file_id: HirFileId) -> Arc; - #[salsa::invoke(ModuleScope::module_scope_query)] - fn module_scope(&self, module_id: ModuleId) -> Arc; + #[salsa::invoke(NameScope::module_scope_query)] + fn module_scope(&self, module_id: ModuleId) -> Arc; - #[salsa::invoke(GenerateBlockScope::generate_block_scope_query)] - fn generate_block_scope(&self, generate_block_id: GenerateBlockId) -> Arc; + #[salsa::invoke(NameScope::generate_block_scope_query)] + fn generate_block_scope(&self, generate_block_id: GenerateBlockId) -> Arc; - #[salsa::invoke(BlockScope::block_scope_query)] - fn block_scope(&self, block_id: BlockId) -> Arc; + #[salsa::invoke(NameScope::block_scope_query)] + fn block_scope(&self, block_id: BlockId) -> Arc; - #[salsa::invoke(SubroutineScope::subroutine_scope_query)] - fn subroutine_scope(&self, subroutine_id: SubroutineId) -> Arc; + #[salsa::invoke(NameScope::subroutine_scope_query)] + fn subroutine_scope(&self, subroutine_id: SubroutineId) -> Arc; #[salsa::invoke(crate::type_infer::type_of_decl_query)] fn type_of_decl(&self, decl: InContainer) -> Arc; diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index a49ff767..be2d1890 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -14,79 +14,16 @@ use crate::{ container::{InContainer, InFile, InModule, InSubroutine, ScopeId}, db::HirDb, hir_def::{ - block::BlockLoc, expr::declarator::DeclaratorParent, module::generate::GenerateBlockLoc, + block::BlockLoc, declaration::Declaration, expr::declarator::DeclaratorParent, + module::generate::GenerateBlockLoc, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, - symbol::{DefId, DefLoc}, + symbol::{DefId, DefKind, DefLoc}, }; -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum ModuleDefOrigin { - Module(DefId), - Config(DefId), - Library(DefId), - Udp(DefId), - Block(DefId), - GenerateBlock(DefId), - Subroutine(DefId), - SubroutinePort(DefId), - - NonAnsiPort(DefId), - Decl(DefId), - Typedef(DefId), - Instance(DefId), - Stmt(DefId), -} - -impl ModuleDefOrigin { - pub fn from_loc(db: &dyn HirDb, loc: impl Into) -> Self { - let loc = loc.into(); - let def_id = DefId::new(db, loc); - Self::from_def_loc(def_id, loc) - } - - fn from_def_loc(def_id: DefId, loc: DefLoc) -> Self { - match loc { - DefLoc::Module(_) => Self::Module(def_id), - DefLoc::Config(_) => Self::Config(def_id), - DefLoc::Library(_) => Self::Library(def_id), - DefLoc::Udp(_) => Self::Udp(def_id), - DefLoc::Block(_) => Self::Block(def_id), - DefLoc::GenerateBlock(_) => Self::GenerateBlock(def_id), - DefLoc::Subroutine(_) => Self::Subroutine(def_id), - DefLoc::SubroutinePort(_) => Self::SubroutinePort(def_id), - DefLoc::NonAnsiPort(_) => Self::NonAnsiPort(def_id), - DefLoc::Decl(_) => Self::Decl(def_id), - DefLoc::Typedef(_) => Self::Typedef(def_id), - DefLoc::Instance(_) => Self::Instance(def_id), - DefLoc::Stmt(_) => Self::Stmt(def_id), - } - } - - pub fn def_id(&self) -> DefId { - match *self { - Self::Module(def_id) - | Self::Config(def_id) - | Self::Library(def_id) - | Self::Udp(def_id) - | Self::Block(def_id) - | Self::GenerateBlock(def_id) - | Self::Subroutine(def_id) - | Self::SubroutinePort(def_id) - | Self::NonAnsiPort(def_id) - | Self::Decl(def_id) - | Self::Typedef(def_id) - | Self::Instance(def_id) - | Self::Stmt(def_id) => def_id, - } - } - - pub fn loc(&self, db: &dyn HirDb) -> DefLoc { - self.def_id().loc(db) - } - +impl DefId { #[inline] - pub fn container_id(&self, db: &dyn HirDb) -> ScopeId { + pub fn container_id(self, db: &dyn HirDb) -> ScopeId { match self.loc(db) { DefLoc::Module(InFile { file_id, .. }) => file_id.into(), DefLoc::Config(InFile { file_id, .. }) => file_id.into(), @@ -106,7 +43,41 @@ impl ModuleDefOrigin { } } - pub fn name(&self, db: &dyn HirDb) -> Option { + pub fn kind(self, db: &dyn HirDb) -> DefKind { + match self.loc(db) { + DefLoc::Module(_) => DefKind::Module, + DefLoc::Config(_) => DefKind::Config, + DefLoc::Library(_) => DefKind::Library, + DefLoc::Udp(_) => DefKind::Udp, + DefLoc::Block(_) => DefKind::Block, + DefLoc::GenerateBlock(_) => DefKind::GenerateBlock, + DefLoc::Subroutine(_) => DefKind::Subroutine, + DefLoc::SubroutinePort(_) => DefKind::SubroutinePort, + DefLoc::NonAnsiPort(_) => DefKind::NonAnsiPort, + DefLoc::Decl(InContainer { value, cont_id }) => { + let container = cont_id.to_container(db); + let decl = container.get(value); + match decl.parent { + DeclaratorParent::PortDeclId(_) => DefKind::Port, + DeclaratorParent::StmtId(_) => DefKind::Variable, + DeclaratorParent::DeclarationId(declaration_id) => { + match container.get(declaration_id) { + Declaration::DataDecl(_) => DefKind::Variable, + Declaration::NetDecl(_) => DefKind::Net, + Declaration::ParamDecl(_) => DefKind::Param, + Declaration::GenvarDecl(_) => DefKind::Genvar, + Declaration::SpecparamDecl(_) => DefKind::Specparam, + } + } + } + } + DefLoc::Typedef(_) => DefKind::Typedef, + DefLoc::Instance(_) => DefKind::Instance, + DefLoc::Stmt(_) => DefKind::Stmt, + } + } + + pub fn name(self, db: &dyn HirDb) -> Option { match self.loc(db) { DefLoc::Module(InFile { value, file_id }) => { file_id.to_container(db).get(value).name.clone() @@ -150,7 +121,7 @@ impl ModuleDefOrigin { } } - pub fn name_range(&self, db: &dyn HirDb) -> Option> { + pub fn name_range(self, db: &dyn HirDb) -> Option> { match self.loc(db) { DefLoc::Module(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.name_range()?; @@ -223,7 +194,7 @@ impl ModuleDefOrigin { } } - pub fn range(&self, db: &dyn HirDb) -> Option> { + pub fn range(self, db: &dyn HirDb) -> Option> { Some(match self.loc(db) { DefLoc::Module(InFile { value, file_id }) => { let range = file_id.to_container_src_map(db).get(value)?.range(); @@ -295,25 +266,23 @@ impl ModuleDefOrigin { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ModuleDef { - origins: SmallVec<[ModuleDefOrigin; 3]>, -} +pub struct ModuleDef(pub SmallVec<[DefId; 3]>); impl ModuleDef { - pub fn from_origins(origins: impl IntoIterator) -> Option { - let mut origins = origins.into_iter().collect::>(); - origins.sort_unstable(); - origins.dedup(); + pub fn from_def_ids(def_ids: impl IntoIterator) -> Option { + let mut def_ids = def_ids.into_iter().collect::>(); + def_ids.sort_unstable(); + def_ids.dedup(); - (!origins.is_empty()).then_some(ModuleDef { origins }) + (!def_ids.is_empty()).then_some(ModuleDef(def_ids)) } - pub fn origins(&self) -> &[ModuleDefOrigin] { - &self.origins + pub fn def_ids(&self) -> &[DefId] { + &self.0 } - fn into_origins(self) -> SmallVec<[ModuleDefOrigin; 3]> { - self.origins + fn into_def_ids(self) -> SmallVec<[DefId; 3]> { + self.0 } } @@ -322,33 +291,32 @@ impl ModuleDef { pub struct ModuleDefId(pub salsa::InternId); impl ModuleDefId { - pub fn origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 3]> { - db.lookup_intern_module_def(self).into_origins() + pub fn origins(self, db: &dyn HirDb) -> SmallVec<[DefId; 3]> { + db.lookup_intern_module_def(self).into_def_ids() } - pub fn declaration_origin(self, db: &dyn HirDb) -> Option { + pub fn declaration_origin(self, db: &dyn HirDb) -> Option { let origins = self.origins(db); - if origins.iter().any(|origin| matches!(origin, ModuleDefOrigin::NonAnsiPort(_))) { - return origins.iter().copied().find(|origin| is_port_decl_origin(db, origin)).or_else( - || { - origins - .iter() - .copied() - .find(|origin| matches!(origin, ModuleDefOrigin::Decl(_))) - }, - ); + if origins.iter().any(|origin| origin.kind(db) == DefKind::NonAnsiPort) { + return origins + .iter() + .copied() + .find(|origin| is_port_decl_origin(db, *origin)) + .or_else(|| { + origins.iter().copied().find(|origin| matches!(origin.loc(db), DefLoc::Decl(_))) + }); } origins.first().copied() } - pub fn def_origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 2]> { + pub fn def_origins(self, db: &dyn HirDb) -> SmallVec<[DefId; 2]> { let origins = self.origins(db); - if origins.iter().any(|origin| matches!(origin, ModuleDefOrigin::NonAnsiPort(_))) { + if origins.iter().any(|origin| origin.kind(db) == DefKind::NonAnsiPort) { return origins .iter() .copied() - .filter(|origin| matches!(origin, ModuleDefOrigin::Decl(_))) + .filter(|origin| matches!(origin.loc(db), DefLoc::Decl(_))) .collect(); } @@ -356,10 +324,8 @@ impl ModuleDefId { } pub fn is_port(self, db: &dyn HirDb) -> bool { - self.origins(db).iter().any(|origin| match origin { - ModuleDefOrigin::NonAnsiPort(_) => true, - ModuleDefOrigin::Decl(_) => is_port_decl_origin(db, origin), - _ => false, + self.origins(db).iter().any(|origin| { + origin.kind(db) == DefKind::NonAnsiPort || is_port_decl_origin(db, *origin) }) } @@ -373,7 +339,7 @@ impl ModuleDefId { } } -fn is_port_decl_origin(db: &dyn HirDb, origin: &ModuleDefOrigin) -> bool { +fn is_port_decl_origin(db: &dyn HirDb, origin: DefId) -> bool { let DefLoc::Decl(decl_id) = origin.loc(db) else { return false; }; diff --git a/crates/hir/src/scope.rs b/crates/hir/src/scope.rs index 9e962e65..befae1cb 100644 --- a/crates/hir/src/scope.rs +++ b/crates/hir/src/scope.rs @@ -1,282 +1,96 @@ -use rustc_hash::FxHashMap; -use smallvec::SmallVec; use smol_str::SmolStr; use triomphe::Arc; -use utils::{ - define_enum_deriving_from, - get::{Get, GetRef}, -}; +use utils::get::{Get, GetRef}; use crate::{ - container::InFile, + container::{InContainer, InFile, InModule, InSubroutine}, db::HirDb, file::HirFileId, hir_def::{ - Ident, - block::{BlockId, BlockInfo}, - expr::declarator::{DeclId, DeclaratorParent}, - file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, + block::BlockInfo, + expr::declarator::DeclaratorParent, module::{ - Module, ModuleId, + Module, generate::GenerateBlockId, - instantiation::InstanceId, - port::{NonAnsiPortId, PortDeclId, Ports}, + port::{PortDeclId, Ports}, }, - stmt::{StmtId, StmtKind}, - subroutine::{SubroutineId, SubroutineLoc, SubroutinePortId}, - typedef::TypedefId, + stmt::StmtKind, + subroutine::{SubroutineLoc, SubroutinePortId}, }, + symbol::{DefId, DefLoc, NameScope}, }; -define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum UnitEntry { - ModuleId, - FiledConfigDeclId, - FiledLibraryDeclId, - FiledUdpDeclId, - FiledDeclId, - FiledTypedefId, - } -} - -pub type FiledDeclId = InFile; -pub type FiledConfigDeclId = InFile; -pub type FiledLibraryDeclId = InFile; -pub type FiledUdpDeclId = InFile; -pub type FiledTypedefId = InFile; - -define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ModuleEntry { - DeclId, - TypedefId, - GenerateBlockId, - NonAnsiPortEntry, - AnsiPortEntry, - InstanceId, - StmtId, - BlockId, - SubroutineId, - } -} - -define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] - pub enum GenerateBlockEntry { - DeclId, - TypedefId, - GenerateBlockId, - StmtId, - BlockId, - SubroutineId, - } -} - -#[derive(Default, Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct NonAnsiPortEntry { - // explicit label for port - pub label: Option, - pub port_decl: Option, - pub data_decl: Option, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct AnsiPortEntry(pub DeclId); - -define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] - pub enum BlockEntry { - StmtId, - DeclId, - TypedefId, - BlockId, - } +fn def_id(db: &dyn HirDb, loc: impl Into) -> DefId { + DefId::new(db, loc) } -define_enum_deriving_from! { - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] - pub enum SubroutineEntry { - StmtId, - DeclId, - TypedefId, - BlockId, - SubroutinePortId, - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Scope { - entries: FxHashMap, -} - -impl Default for Scope { - fn default() -> Self { - Scope { entries: FxHashMap::default() } - } -} - -impl Scope { - pub(crate) fn insert(&mut self, ident: &Ident, entry: Entry) -> Option { - self.entries.insert(ident.clone(), entry) - } - - pub(crate) fn insert_opt(&mut self, ident: &Option, entry: Entry) -> Option { - self.insert(ident.as_ref()?, entry) - } - - pub fn get(&self, ident: &Ident) -> Option { - self.entries.get(ident).copied() - } - - pub fn iter(&self) -> impl Iterator + '_ { - self.entries.iter().map(|(k, v)| (k, *v)) - } - - pub(crate) fn get_mut(&mut self, ident: &Ident) -> Option<&mut Entry> { - self.entries.get_mut(ident) - } -} - -pub type ModuleScope = Scope; -pub type GenerateBlockScope = Scope; -pub type BlockScope = Scope; -pub type SubroutineScope = Scope; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ScopeResolution { - Unique(Entry), - Ambiguous(SmallVec<[Entry; 2]>), - Unresolved, -} - -impl ScopeResolution { - pub fn unique(self) -> Option { - match self { - ScopeResolution::Unique(entry) => Some(entry), - ScopeResolution::Ambiguous(_) | ScopeResolution::Unresolved => None, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Default)] -pub struct UnitScope { - entries: FxHashMap>, -} - -impl UnitScope { - fn insert(&mut self, ident: &Ident, entry: UnitEntry) { - self.entries.entry(ident.clone()).or_default().push(entry); - } - - fn insert_opt(&mut self, ident: &Option, entry: UnitEntry) { - if let Some(ident) = ident { - self.insert(ident, entry); - } - } - - pub fn resolve(&self, ident: &Ident) -> ScopeResolution { - match self.entries.get(ident).map(SmallVec::as_slice) { - Some([entry]) => ScopeResolution::Unique(*entry), - Some(entries) => ScopeResolution::Ambiguous(SmallVec::from_slice(entries)), - None => ScopeResolution::Unresolved, - } - } - - pub fn get(&self, ident: &Ident) -> Option { - self.resolve(ident).unique() - } - - pub fn resolve_module(&self, ident: &Ident) -> ScopeResolution { - let entries = self - .entries - .get(ident) - .into_iter() - .flat_map(|entries| entries.iter()) - .filter_map(|entry| match entry { - UnitEntry::ModuleId(module_id) => Some(*module_id), - UnitEntry::FiledConfigDeclId(_) - | UnitEntry::FiledLibraryDeclId(_) - | UnitEntry::FiledUdpDeclId(_) - | UnitEntry::FiledDeclId(_) - | UnitEntry::FiledTypedefId(_) => None, - }) - .collect::>(); - - match entries.as_slice() { - [module_id] => ScopeResolution::Unique(*module_id), - [] => ScopeResolution::Unresolved, - _ => ScopeResolution::Ambiguous(entries), - } - } - - pub fn iter(&self) -> impl Iterator + '_ { - self.entries - .iter() - .flat_map(|(ident, entries)| entries.iter().map(move |entry| (ident, *entry))) - } -} - -// TODO: diagnostics - -impl UnitScope { - pub fn unit_scope_query(db: &dyn HirDb) -> Arc { - let mut scope = UnitScope::default(); +impl NameScope { + pub fn unit_scope_query(db: &dyn HirDb) -> Arc { + let mut scope = NameScope::default(); for file_id in db.files().iter() { let file_id = HirFileId::File(*file_id); let file_scope = db.file_scope(file_id); - for (ident, entry) in file_scope.iter() { - scope.insert(ident, entry); - } + scope.extend_from(&file_scope); } Arc::new(scope) } - pub(super) fn file_scope_query(db: &dyn HirDb, file_id: HirFileId) -> Arc { - let mut scope = UnitScope::default(); + pub(super) fn file_scope_query(db: &dyn HirDb, file_id: HirFileId) -> Arc { + let mut scope = NameScope::default(); let hir_file = db.hir_file(file_id); for (module_id, module_info) in hir_file.modules.iter() { - scope.insert_opt(&module_info.name, InFile::new(file_id, module_id).into()); + scope.insert_value_opt(&module_info.name, def_id(db, InFile::new(file_id, module_id))); } for (decl_id, decl) in hir_file.decls.iter() { - scope.insert_opt(&decl.name, InFile::new(file_id, decl_id).into()); + scope.insert_value_opt( + &decl.name, + def_id(db, InContainer::new(file_id.into(), decl_id)), + ); } for (config_decl_id, config_decl) in hir_file.config_decls.iter() { - scope.insert_opt(&config_decl.name, InFile::new(file_id, config_decl_id).into()); + scope.insert_value_opt( + &config_decl.name, + def_id(db, InFile::new(file_id, config_decl_id)), + ); } for (udp_decl_id, udp_decl) in hir_file.udp_decls.iter() { - scope.insert_opt(&udp_decl.name, InFile::new(file_id, udp_decl_id).into()); + scope.insert_value_opt(&udp_decl.name, def_id(db, InFile::new(file_id, udp_decl_id))); } for (library_decl_id, library_decl) in hir_file.library_decls.iter() { - scope.insert_opt(&library_decl.name, InFile::new(file_id, library_decl_id).into()); + scope.insert_value_opt( + &library_decl.name, + def_id(db, InFile::new(file_id, library_decl_id)), + ); } for (typedef_id, typedef) in hir_file.typedefs.iter() { - scope.insert_opt(&typedef.name, InFile::new(file_id, typedef_id).into()); + scope.insert_type_opt( + &typedef.name, + def_id(db, InContainer::new(file_id.into(), typedef_id)), + ); } Arc::new(scope) } -} -impl ModuleScope { - pub fn module_scope_query(db: &dyn HirDb, module_id: ModuleId) -> Arc { - let mut scope = Scope::default(); + pub fn module_scope_query( + db: &dyn HirDb, + module_id: crate::hir_def::module::ModuleId, + ) -> Arc { + let mut scope = NameScope::default(); let (module, module_src_map) = db.module_with_source_map(module_id); let file_id = HirFileId::File(module_id.file_id()); - // handle labels of non-ansi ports if let Ports::NonAnsi { ports, .. } = &module.ports { for (port_id, port) in ports.iter() { - let entry = NonAnsiPortEntry { label: Some(port_id), ..Default::default() }.into(); - scope.insert_opt(&port.label, entry); + scope.insert_value_opt(&port.label, def_id(db, InModule::new(module_id, port_id))); } } @@ -289,46 +103,28 @@ impl ModuleScope { src: InFile::new(file_id, src), local_id: local_subroutine_id, }); - scope.insert_opt(&subroutine.name, subroutine_id.into()); + scope.insert_value_opt(&subroutine.name, def_id(db, subroutine_id)); } - // handle other members for (decl_id, decl) in module.decls.iter() { - let Some(name) = &decl.name else { - continue; - }; - - let is_port_decl = matches!(decl.parent, DeclaratorParent::PortDeclId(_)); - - if let Some(ModuleEntry::NonAnsiPortEntry(entry)) = scope.get_mut(name) { - if is_port_decl { - entry.port_decl = Some(decl_id); - } else { - entry.data_decl = Some(decl_id); - } - continue; - } - - let entry = if is_port_decl { - match module.ports { - Ports::NonAnsi { .. } => { - NonAnsiPortEntry { port_decl: Some(decl_id), ..Default::default() }.into() - } - Ports::Ansi(_) => AnsiPortEntry(decl_id).into(), - } - } else { - decl_id.into() - }; - - scope.insert(name, entry); + scope.insert_value_opt( + &decl.name, + def_id(db, InContainer::new(module_id.into(), decl_id)), + ); } for (typedef_id, typedef) in module.typedefs.iter() { - scope.insert_opt(&typedef.name, typedef_id.into()); + scope.insert_type_opt( + &typedef.name, + def_id(db, InContainer::new(module_id.into(), typedef_id)), + ); } for (instance_id, instance) in module.instances.iter() { - scope.insert_opt(&instance.name, instance_id.into()); + scope.insert_value_opt( + &instance.name, + def_id(db, InModule::new(module_id, instance_id)), + ); } for item in &module_src_map.items { @@ -340,50 +136,35 @@ impl ModuleScope { ) = *item { let generate_block = db.generate_block(generate_block_id); - scope.insert_opt(&generate_block.name, generate_block_id.into()); + scope.insert_value_opt(&generate_block.name, def_id(db, generate_block_id)); } } } } for (stmt_id, stmt) in module.stmts.iter() { - scope.insert_opt(&stmt.label, stmt_id.into()); + scope.insert_value_opt( + &stmt.label, + def_id(db, InContainer::new(module_id.into(), stmt_id)), + ); if let StmtKind::Block(BlockInfo { name, block_id }) = &stmt.kind { - scope.insert_opt(name, (*block_id).into()); + scope.insert_value_opt(name, def_id(db, *block_id)); } } Arc::new(scope) } - pub fn non_ansi_port_decl_id_by_name( - &self, - module: &Module, - name: &SmolStr, - ) -> Option { - let ModuleEntry::NonAnsiPortEntry(NonAnsiPortEntry { port_decl, .. }) = self.get(name)? - else { - return None; - }; - let decl = module.get(port_decl?); - let DeclaratorParent::PortDeclId(port_decl_id) = decl.parent else { - return None; - }; - Some(port_decl_id) - } -} - -impl GenerateBlockScope { pub fn generate_block_scope_query( db: &dyn HirDb, generate_block_id: GenerateBlockId, - ) -> Arc { - let mut scope = Scope::default(); + ) -> Arc { + let mut scope = NameScope::default(); let (generate_block, source_map) = db.generate_block_with_source_map(generate_block_id); let file_id = HirFileId::File(generate_block_id.file_id(db)); - scope.insert_opt(&generate_block.name, generate_block_id.into()); + scope.insert_value_opt(&generate_block.name, def_id(db, generate_block_id)); for (local_subroutine_id, subroutine) in generate_block.subroutines.iter() { let Some(src) = source_map.get(local_subroutine_id) else { @@ -394,15 +175,21 @@ impl GenerateBlockScope { src: InFile::new(file_id, src), local_id: local_subroutine_id, }); - scope.insert_opt(&subroutine.name, subroutine_id.into()); + scope.insert_value_opt(&subroutine.name, def_id(db, subroutine_id)); } for (decl_id, decl) in generate_block.decls.iter() { - scope.insert_opt(&decl.name, decl_id.into()); + scope.insert_value_opt( + &decl.name, + def_id(db, InContainer::new(generate_block_id.into(), decl_id)), + ); } for (typedef_id, typedef) in generate_block.typedefs.iter() { - scope.insert_opt(&typedef.name, typedef_id.into()); + scope.insert_type_opt( + &typedef.name, + def_id(db, InContainer::new(generate_block_id.into(), typedef_id)), + ); } for item in &generate_block.items { @@ -410,73 +197,324 @@ impl GenerateBlockScope { *item { let child = db.generate_block(child_id); - scope.insert_opt(&child.name, child_id.into()); + scope.insert_value_opt(&child.name, def_id(db, child_id)); } } for (stmt_id, stmt) in generate_block.stmts.iter() { - scope.insert_opt(&stmt.label, stmt_id.into()); + scope.insert_value_opt( + &stmt.label, + def_id(db, InContainer::new(generate_block_id.into(), stmt_id)), + ); if let StmtKind::Block(BlockInfo { name, block_id }) = &stmt.kind { - scope.insert_opt(name, (*block_id).into()); + scope.insert_value_opt(name, def_id(db, *block_id)); } } Arc::new(scope) } -} -impl BlockScope { - pub fn block_scope_query(db: &dyn HirDb, block_id: BlockId) -> Arc { - let mut scope = Scope::default(); + pub fn block_scope_query( + db: &dyn HirDb, + block_id: crate::hir_def::block::BlockId, + ) -> Arc { + let mut scope = NameScope::default(); let block = db.block(block_id); for (decl_id, decl) in block.decls.iter() { - scope.insert_opt(&decl.name, decl_id.into()); + scope.insert_value_opt( + &decl.name, + def_id(db, InContainer::new(block_id.into(), decl_id)), + ); } for (typedef_id, typedef) in block.typedefs.iter() { - scope.insert_opt(&typedef.name, typedef_id.into()); + scope.insert_type_opt( + &typedef.name, + def_id(db, InContainer::new(block_id.into(), typedef_id)), + ); } for (stmt_id, stmt) in block.stmts.iter() { - scope.insert_opt(&stmt.label, stmt_id.into()); + scope.insert_value_opt( + &stmt.label, + def_id(db, InContainer::new(block_id.into(), stmt_id)), + ); if let StmtKind::Block(BlockInfo { name, block_id }) = &stmt.kind { - scope.insert_opt(name, (*block_id).into()); + scope.insert_value_opt(name, def_id(db, *block_id)); } } Arc::new(scope) } -} -impl SubroutineScope { - pub fn subroutine_scope_query(db: &dyn HirDb, subroutine_id: SubroutineId) -> Arc { - let mut scope = Scope::default(); + pub fn subroutine_scope_query( + db: &dyn HirDb, + subroutine_id: crate::hir_def::subroutine::SubroutineId, + ) -> Arc { + let mut scope = NameScope::default(); let subroutine = db.subroutine(subroutine_id); for (port_idx, port) in subroutine.ports.iter().enumerate() { let port_id = SubroutinePortId(port_idx as u32); - scope.insert_opt(&port.name, port_id.into()); + scope.insert_value_opt( + &port.name, + def_id(db, InSubroutine::new(subroutine_id, port_id)), + ); } for (decl_id, decl) in subroutine.decls.iter() { - scope.insert_opt(&decl.name, decl_id.into()); + scope.insert_value_opt( + &decl.name, + def_id(db, InContainer::new(subroutine_id.into(), decl_id)), + ); } for (typedef_id, typedef) in subroutine.typedefs.iter() { - scope.insert_opt(&typedef.name, typedef_id.into()); + scope.insert_type_opt( + &typedef.name, + def_id(db, InContainer::new(subroutine_id.into(), typedef_id)), + ); } for (stmt_id, stmt) in subroutine.stmts.iter() { - scope.insert_opt(&stmt.label, stmt_id.into()); + scope.insert_value_opt( + &stmt.label, + def_id(db, InContainer::new(subroutine_id.into(), stmt_id)), + ); if let StmtKind::Block(BlockInfo { name, block_id }) = &stmt.kind { - scope.insert_opt(name, (*block_id).into()); + scope.insert_value_opt(name, def_id(db, *block_id)); } } Arc::new(scope) } + + pub fn non_ansi_port_decl_id_by_name( + &self, + db: &dyn HirDb, + module: &Module, + name: &SmolStr, + ) -> Option { + let defs = self.values.get(name)?; + defs.iter().filter_map(|def_id| def_id.as_decl(db)).find_map(|decl_id| { + let decl = module.get(decl_id.value); + match decl.parent { + DeclaratorParent::PortDeclId(port_decl_id) => Some(port_decl_id), + _ => None, + } + }) + } + + fn extend_from(&mut self, other: &NameScope) { + for (ident, defs) in &other.types { + for def_id in defs { + self.insert_type(ident, *def_id); + } + } + for (ident, defs) in &other.values { + for def_id in defs { + self.insert_value(ident, *def_id); + } + } + for (ident, defs) in &other.assertions { + for def_id in defs { + self.insert_assertion(ident, *def_id); + } + } + self.imports.extend(other.imports.iter().copied()); + } +} + +#[cfg(test)] +mod tests { + use std::fmt; + + use rustc_hash::FxHashSet; + use smol_str::SmolStr; + use triomphe::Arc; + use utils::paths::{AbsPathBuf, Utf8PathBuf}; + use vfs::{FileId, FileSet, VfsPath, anchored_path::AnchoredPath}; + + use crate::{ + base_db::{ + diagnostics_config::DiagnosticsConfig, + project::{CompilationProfile, CompilationProfileId, PreprocessConfig, ProjectConfig}, + salsa::{self, Durability}, + source_db::{ + FileLoader, SourceDb, SourceDbStorage, SourceFileKind, SourceRootDb, + SourceRootDbStorage, + }, + source_root::{SourceRoot, SourceRootId}, + }, + db::{HirDb, HirDbStorage, InternDbStorage}, + hir_def::Ident, + symbol::DefKind, + }; + + const TOP: FileId = FileId(0); + const ROOT: SourceRootId = SourceRootId(0); + const PROFILE: CompilationProfileId = CompilationProfileId(0); + + #[salsa::database(SourceDbStorage, SourceRootDbStorage, InternDbStorage, HirDbStorage)] + #[derive(Default)] + struct TestDb { + storage: salsa::Storage, + } + + impl salsa::Database for TestDb {} + + impl fmt::Debug for TestDb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TestDb").finish() + } + } + + impl FileLoader for TestDb { + fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { + let source_root_id = SourceRootDb::source_root_id(self, path.anchor_id); + SourceRootDb::source_root(self, source_root_id).resolve_path(path) + } + } + + fn db_with_root_text(root_text: &str) -> TestDb { + let top_path = abs_path("rtl/top.sv"); + let mut file_set = FileSet::default(); + file_set.insert(TOP, VfsPath::from(top_path.clone())); + let root = SourceRoot::new_local_with_source_files(file_set, vec![TOP]); + let mut files = FxHashSet::default(); + files.insert(TOP); + + let preprocess = PreprocessConfig::default(); + let project_config = ProjectConfig::new( + vec![Some(PROFILE)], + vec![CompilationProfile { + source_roots: vec![ROOT], + top_modules: Vec::new(), + preprocess: preprocess.clone(), + }], + ); + + let mut db = TestDb::default(); + db.set_files_with_durability(Box::new(files), Durability::HIGH); + db.set_project_config_with_durability(Arc::new(project_config), Durability::HIGH); + db.set_diagnostics_config_with_durability( + Arc::new(DiagnosticsConfig::default()), + Durability::HIGH, + ); + db.set_source_root_with_durability(ROOT, Arc::new(root), Durability::LOW); + db.set_source_root_id_with_durability(TOP, ROOT, Durability::LOW); + db.set_file_path_with_durability(TOP, Some(top_path), Durability::LOW); + db.set_file_kind_with_durability(TOP, SourceFileKind::SystemVerilog, Durability::LOW); + db.set_file_text_with_durability(TOP, Arc::from(root_text), Durability::LOW); + db.set_file_preprocess_config_with_durability(TOP, Arc::new(preprocess), Durability::LOW); + db + } + + fn abs_path(path: &str) -> AbsPathBuf { + let prefix = if cfg!(windows) { "C:/repo" } else { "/repo" }; + AbsPathBuf::assert(Utf8PathBuf::from(format!("{prefix}/{path}"))) + } + + fn ident(name: &str) -> Ident { + SmolStr::new(name) + } + + #[test] + fn name_scope_merged_lookup_covers_current_scope_shapes() { + let db = db_with_root_text( + r#" +typedef logic shared; +wire shared; +wire file_sig; + +module m(a); + output a; + reg [7:0] a; + + function automatic [3:0] f(input p); + begin: b + integer x; + end + endfunction + + generate + if (1) begin: g + wire y; + end + endgenerate +endmodule +"#, + ); + + let unit_scope = db.unit_scope(); + assert!( + unit_scope + .lookup_merged(&ident("file_sig")) + .expect("file decl should be visible") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Net) + ); + let shared_defs = unit_scope + .lookup_merged(&ident("shared")) + .expect("merged lookup should preserve same-name type and value definitions"); + assert!(shared_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Typedef)); + assert!(shared_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Net)); + + let module_id = unit_scope + .module_ids(&db, &ident("m")) + .unique() + .expect("module should resolve uniquely"); + + let module_scope = db.module_scope(module_id); + let port_defs = + module_scope.lookup_merged(&ident("a")).expect("non-ANSI port name should resolve"); + assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::NonAnsiPort)); + assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Port)); + assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Variable)); + + let subroutine_id = module_scope + .lookup_merged(&ident("f")) + .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_subroutine(&db))) + .expect("subroutine should be visible from module scope"); + let subroutine_scope = db.subroutine_scope(subroutine_id); + assert!( + subroutine_scope + .lookup_merged(&ident("p")) + .expect("subroutine port should be visible") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::SubroutinePort) + ); + + let block_id = subroutine_scope + .lookup_merged(&ident("b")) + .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_block(&db))) + .expect("named block should be visible from subroutine scope"); + assert!( + db.block_scope(block_id) + .lookup_merged(&ident("x")) + .expect("block local should be visible") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Variable) + ); + + let generate_block_id = module_scope + .lookup_merged(&ident("g")) + .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_generate_block(&db))) + .expect("generate block should be visible from module scope"); + assert!( + db.generate_block_scope(generate_block_id) + .lookup_merged(&ident("y")) + .expect("generate local should be visible") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Net) + ); + + // Adding an interface lowering should create a DefKind::Interface + // producer and insert the resulting DefId into NameScope; IDE + // feature matches already have default no-op arms. + } } diff --git a/crates/hir/src/semantics/hir_to_def.rs b/crates/hir/src/semantics/hir_to_def.rs index 8afda2ab..4eb7fc9a 100644 --- a/crates/hir/src/semantics/hir_to_def.rs +++ b/crates/hir/src/semantics/hir_to_def.rs @@ -3,15 +3,15 @@ use utils::get::GetRef; use super::{Source2DefCtx, pathres::PathResolution}; use crate::{ - container::{ - InBlock, InContainer, InGenerateBlock, InModule, InSubroutine, ScopeId, ScopeParent, - }, + container::{InContainer, ScopeId}, hir_def::{ Ident, block::BlockId, expr::{Expr, ExprId}, module::{ModuleId, generate::GenerateBlockId, instantiation::InstanceId}, }, + semantics::pathres::{name_scope, resolve_name}, + symbol::DefLoc, }; #[derive(Default, Debug)] @@ -32,17 +32,17 @@ impl Source2DefCtx<'_, '_> { let field = field.as_ref()?; let receiver_res = self.expr_to_def(InContainer::new(cont_id, *receiver))?; let res = self.resolve_member_from_resolution(receiver_res, field)?; - self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res); + self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res.clone()); Some(res) } Expr::ElementSelect { receiver, .. } => { let res = self.expr_to_def(InContainer::new(cont_id, *receiver))?; - self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res); + self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res.clone()); Some(res) } Expr::Ident(ident) => { let res = self.name_to_def(InContainer::new(cont_id, ident.clone()))?; - self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res); + self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res.clone()); Some(res) } _ => None, @@ -76,35 +76,8 @@ impl Source2DefCtx<'_, '_> { &mut self, InContainer { cont_id, value: ident }: InContainer, ) -> Option { - let db = self.db; - let res = ScopeParent::start_from(db, cont_id).find_map(|id| match id { - ScopeId::File(_) => { - let scope = db.unit_scope(); - let entry = scope.get(&ident)?; - Some(entry.into()) - } - ScopeId::Module(module_id) => { - let scope = db.module_scope(module_id); - let entry = scope.get(&ident)?; - Some(InModule::new(module_id, entry).into()) - } - ScopeId::Block(block_id) => { - let scope = db.block_scope(block_id); - let entry = scope.get(&ident)?; - Some(InBlock::new(block_id, entry).into()) - } - ScopeId::GenerateBlock(generate_block_id) => { - let scope = db.generate_block_scope(generate_block_id); - let entry = scope.get(&ident)?; - Some(InGenerateBlock::new(generate_block_id, entry).into()) - } - ScopeId::Subroutine(subroutine_id) => { - let scope = db.subroutine_scope(subroutine_id); - let entry = scope.get(&ident)?; - Some(InSubroutine::new(subroutine_id, entry).into()) - } - })?; - self.hir_cache.name_map.insert(InContainer::new(cont_id, ident), res); + let res = resolve_name(self.db, cont_id, &ident)?; + self.hir_cache.name_map.insert(InContainer::new(cont_id, ident), res.clone()); Some(res) } @@ -113,19 +86,36 @@ impl Source2DefCtx<'_, '_> { res: PathResolution, field: &Ident, ) -> Option { - match res { - PathResolution::Module(module_id) => self.resolve_member_in_module(module_id, field), - PathResolution::Instance(instance) => { - let target_module = - self.instance_target_module_id(instance.module_id, instance.value)?; - self.resolve_member_in_module(target_module, field) - } - PathResolution::Block(block_id) => self.resolve_member_in_block(block_id, field), - PathResolution::GenerateBlock(generate_block_id) => { - self.resolve_member_in_generate_block(generate_block_id, field) + for def_id in res.def_ids() { + match def_id.loc(self.db) { + DefLoc::Module(module_id) => { + if let Some(res) = self.resolve_member_in_module(module_id, field) { + return Some(res); + } + } + DefLoc::Instance(instance) => { + let target_module = + self.instance_target_module_id(instance.module_id, instance.value)?; + if let Some(res) = self.resolve_member_in_module(target_module, field) { + return Some(res); + } + } + DefLoc::Block(block_id) => { + if let Some(res) = self.resolve_member_in_block(block_id, field) { + return Some(res); + } + } + DefLoc::GenerateBlock(generate_block_id) => { + if let Some(res) = + self.resolve_member_in_generate_block(generate_block_id, field) + { + return Some(res); + } + } + _ => {} } - _ => None, } + None } fn resolve_member_in_module( @@ -133,9 +123,9 @@ impl Source2DefCtx<'_, '_> { module_id: ModuleId, field: &Ident, ) -> Option { - let scope = self.db.module_scope(module_id); - let entry = scope.get(field)?; - Some(InModule::new(module_id, entry).into()) + name_scope(self.db, module_id.into()) + .lookup_merged(field) + .and_then(PathResolution::from_def_ids) } fn resolve_member_in_block( @@ -143,9 +133,9 @@ impl Source2DefCtx<'_, '_> { block_id: BlockId, field: &Ident, ) -> Option { - let scope = self.db.block_scope(block_id); - let entry = scope.get(field)?; - Some(InBlock::new(block_id, entry).into()) + name_scope(self.db, block_id.into()) + .lookup_merged(field) + .and_then(PathResolution::from_def_ids) } fn resolve_member_in_generate_block( @@ -153,9 +143,9 @@ impl Source2DefCtx<'_, '_> { generate_block_id: GenerateBlockId, field: &Ident, ) -> Option { - let scope = self.db.generate_block_scope(generate_block_id); - let entry = scope.get(field)?; - Some(InGenerateBlock::new(generate_block_id, entry).into()) + name_scope(self.db, generate_block_id.into()) + .lookup_merged(field) + .and_then(PathResolution::from_def_ids) } fn instance_target_module_id( @@ -167,6 +157,6 @@ impl Source2DefCtx<'_, '_> { let instance = module.get(instance_id); let instantiation = module.get(instance.parent); let module_name = instantiation.module_name.as_ref()?; - self.db.unit_scope().resolve_module(module_name).unique() + self.db.unit_scope().module_ids(self.db, module_name).unique() } } diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index a192e7a5..6826d59a 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -1,29 +1,15 @@ -use smallvec::{SmallVec, smallvec}; +use smallvec::SmallVec; use syntax::{SyntaxNode, SyntaxTokenWithParent}; +use triomphe::Arc; use super::SemanticsImpl; use crate::{ - container::{ - InBlock, InContainer, InFile, InGenerateBlock, InModule, InSubroutine, ScopeId, ScopeParent, - }, + container::{InContainer, InFile, ScopeId, ScopeParent}, db::HirDb, - def_id::{ModuleDef, ModuleDefId, ModuleDefOrigin}, + def_id::{ModuleDef, ModuleDefId}, file::HirFileId, - hir_def::{ - Ident, - block::BlockId, - expr::declarator::DeclId, - file::{config::ConfigDeclId, library::LibraryDeclId, udp::UdpDeclId}, - lower_ident_opt, - module::{ - ModuleId, generate::GenerateBlockId, instantiation::InstanceId, port::NonAnsiPortId, - }, - stmt::StmtId, - subroutine::{SubroutineId, SubroutinePortId}, - typedef::TypedefId, - }, - scope::{self, BlockEntry, GenerateBlockEntry, ModuleEntry, SubroutineEntry, UnitEntry}, - symbol::DefLoc, + hir_def::{Ident, lower_ident_opt}, + symbol::{DefId, NameScope}, }; impl SemanticsImpl<'_> { @@ -49,185 +35,58 @@ impl SemanticsImpl<'_> { } pub fn resolve_name(db: &dyn HirDb, cont_id: ScopeId, ident: &Ident) -> Option { - ScopeParent::start_from(db, cont_id).find_map(|id| match id { - ScopeId::File(_) => db.unit_scope().get(ident).map(PathResolution::from), - ScopeId::Module(module_id) => db - .module_scope(module_id) - .get(ident) - .map(|entry| PathResolution::from(InModule::new(module_id, entry))), - ScopeId::GenerateBlock(generate_block_id) => db - .generate_block_scope(generate_block_id) - .get(ident) - .map(|entry| PathResolution::from(InGenerateBlock::new(generate_block_id, entry))), - ScopeId::Block(block_id) => db - .block_scope(block_id) - .get(ident) - .map(|entry| PathResolution::from(InBlock::new(block_id, entry))), - ScopeId::Subroutine(subroutine_id) => db - .subroutine_scope(subroutine_id) - .get(ident) - .map(|entry| PathResolution::from(InSubroutine::new(subroutine_id, entry))), + ScopeParent::start_from(db, cont_id).find_map(|id| { + let scope = name_scope(db, id); + scope.lookup_merged(ident).and_then(PathResolution::from_def_ids) }) } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum PathResolution { - Module(ModuleId), - Config(InFile), - Library(InFile), - Udp(InFile), - Decl(InContainer), - Typedef(InContainer), - ParamDecl(InModule), - Subroutine(SubroutineId), - SubroutinePort(InSubroutine), - NonAnsiPort { - // There won't be a situation where all fields are None. - label: Option, - port_decl: Option, - data_decl: Option, - module: ModuleId, - }, - AnsiPort(InModule), - Instance(InModule), - Stmt(InContainer), - Block(BlockId), - GenerateBlock(GenerateBlockId), -} - -impl PathResolution { - pub fn to_def_id(self, db: &dyn HirDb) -> Option { - let module_def = ModuleDef::from_origins(self.origins(db))?; - Some(db.intern_module_def(module_def)) +pub(crate) fn name_scope(db: &dyn HirDb, scope_id: ScopeId) -> Arc { + match scope_id { + ScopeId::File(_) => db.unit_scope(), + ScopeId::Module(module_id) => db.module_scope(module_id), + ScopeId::GenerateBlock(generate_block_id) => db.generate_block_scope(generate_block_id), + ScopeId::Block(block_id) => db.block_scope(block_id), + ScopeId::Subroutine(subroutine_id) => db.subroutine_scope(subroutine_id), } +} - fn origins(self, db: &dyn HirDb) -> SmallVec<[ModuleDefOrigin; 3]> { - let mut res = smallvec![]; - let mut add_source = |source: DefLoc| res.push(ModuleDefOrigin::from_loc(db, source)); - - match self { - PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ScopeId = module.into(); - if let Some(label) = label { - add_source(InModule::new(module, label).into()); - } - if let Some(port_decl) = port_decl { - add_source(InContainer::new(container, port_decl).into()); - } - if let Some(decl) = data_decl { - add_source(InContainer::new(container, decl).into()); - } - } - _ => { - if let Some(origin) = self.pick() { - add_source(origin); - } - } - }; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PathResolution { + def_ids: SmallVec<[DefId; 3]>, +} - res +impl PathResolution { + pub fn from_def_id(def_id: DefId) -> Self { + Self { def_ids: SmallVec::from_slice(&[def_id]) } } - #[inline] - fn pick(self) -> Option { - match self { - PathResolution::Module(module_id) => Some(module_id.into()), - PathResolution::Config(config_id) => Some(config_id.into()), - PathResolution::Library(library_id) => Some(library_id.into()), - PathResolution::Udp(udp_id) => Some(udp_id.into()), - PathResolution::Decl(decl_id) => Some(decl_id.into()), - PathResolution::Typedef(typedef_id) => Some(typedef_id.into()), - PathResolution::Instance(instance_id) => Some(instance_id.into()), - PathResolution::Stmt(stmt_id) => Some(stmt_id.into()), - PathResolution::Block(blk_id) => Some(blk_id.into()), - PathResolution::GenerateBlock(generate_block_id) => Some(generate_block_id.into()), - PathResolution::Subroutine(subroutine_id) => Some(subroutine_id.into()), - PathResolution::SubroutinePort(port_id) => Some(port_id.into()), - PathResolution::ParamDecl(decl_id) | PathResolution::AnsiPort(decl_id) => { - Some(InContainer::new(decl_id.module_id.into(), decl_id.value).into()) - } - PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let container: ScopeId = module.into(); - if let Some(label) = label { - Some(InModule::new(module, label).into()) - } else if let Some(port_decl) = port_decl { - Some(InContainer::new(container, port_decl).into()) - } else { - data_decl.map(|decl| InContainer::new(container, decl).into()) - } + pub fn from_def_ids(def_ids: impl IntoIterator) -> Option { + let mut resolved = SmallVec::<[DefId; 3]>::new(); + for def_id in def_ids { + if !resolved.contains(&def_id) { + resolved.push(def_id); } } + (!resolved.is_empty()).then_some(Self { def_ids: resolved }) } -} - -impl From for PathResolution { - fn from(entry: UnitEntry) -> Self { - use UnitEntry::*; - match entry { - ModuleId(idx) => Self::Module(idx), - FiledConfigDeclId(idx) => Self::Config(idx), - FiledLibraryDeclId(idx) => Self::Library(idx), - FiledUdpDeclId(idx) => Self::Udp(idx), - FiledDeclId(idx) => Self::Decl(idx.into()), - FiledTypedefId(idx) => Self::Typedef(idx.into()), - } - } -} -impl From> for PathResolution { - fn from(entry: InModule) -> Self { - use ModuleEntry::*; - match entry.value { - DeclId(decl_id) => Self::Decl(entry.with_value(decl_id).into()), - TypedefId(typedef_id) => Self::Typedef(entry.with_value(typedef_id).into()), - InstanceId(idx) => Self::Instance(entry.with_value(idx)), - GenerateBlockId(generate_block_id) => Self::GenerateBlock(generate_block_id), - StmtId(idx) => Self::Stmt(entry.with_value(idx).into()), - SubroutineId(subroutine_id) => Self::Subroutine(subroutine_id), - NonAnsiPortEntry(scope::NonAnsiPortEntry { label, port_decl, data_decl }) => { - Self::NonAnsiPort { label, port_decl, data_decl, module: entry.module_id } - } - AnsiPortEntry(scope::AnsiPortEntry(idx)) => Self::AnsiPort(entry.with_value(idx)), - BlockId(block_id) => Self::Block(block_id), - } + pub fn def_ids(&self) -> &[DefId] { + &self.def_ids } -} -impl From> for PathResolution { - fn from(entry: InGenerateBlock) -> Self { - use GenerateBlockEntry::*; - match entry.value { - DeclId(idx) => Self::Decl(entry.with_value(idx).into()), - TypedefId(idx) => Self::Typedef(entry.with_value(idx).into()), - GenerateBlockId(generate_block_id) => Self::GenerateBlock(generate_block_id), - StmtId(idx) => Self::Stmt(entry.with_value(idx).into()), - BlockId(block_id) => Self::Block(block_id), - SubroutineId(subroutine_id) => Self::Subroutine(subroutine_id), - } + pub fn primary_def_id(&self) -> Option { + self.def_ids.first().copied() } -} -impl From> for PathResolution { - fn from(entry: InBlock) -> Self { - use BlockEntry::*; - match entry.value { - DeclId(idx) => Self::Decl(entry.with_value(idx).into()), - TypedefId(idx) => Self::Typedef(entry.with_value(idx).into()), - StmtId(idx) => Self::Stmt(entry.with_value(idx).into()), - BlockId(block_id) => Self::Block(block_id), - } + pub fn to_def_id(&self, db: &dyn HirDb) -> Option { + let module_def = ModuleDef::from_def_ids(self.def_ids.iter().copied())?; + Some(db.intern_module_def(module_def)) } } -impl From> for PathResolution { - fn from(entry: InSubroutine) -> Self { - use SubroutineEntry::*; - match entry.value { - DeclId(idx) => Self::Decl(entry.with_value(idx).into()), - TypedefId(idx) => Self::Typedef(entry.with_value(idx).into()), - StmtId(idx) => Self::Stmt(entry.with_value(idx).into()), - BlockId(block_id) => Self::Block(block_id), - SubroutinePortId(idx) => Self::SubroutinePort(entry.with_value(idx)), - } +impl From for PathResolution { + fn from(def_id: DefId) -> Self { + Self::from_def_id(def_id) } } diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs index 34eb74ee..75a5dfb9 100644 --- a/crates/hir/src/symbol.rs +++ b/crates/hir/src/symbol.rs @@ -171,8 +171,11 @@ pub enum DefKind { Udp, Config, Library, + Block, + GenerateBlock, Subroutine, SubroutinePort, + NonAnsiPort, Typedef, Enum, Struct, @@ -180,6 +183,8 @@ pub enum DefKind { Variable, Param, Port, + Genvar, + Specparam, Instance, ClassField, Method, @@ -187,6 +192,7 @@ pub enum DefKind { ClockingBlock, Sequence, Property, + Stmt, } impl DefKind { @@ -206,14 +212,20 @@ impl DefKind { DefKind::Udp => SymbolKind::Primitive, DefKind::Config => SymbolKind::Config, DefKind::Library => SymbolKind::Library, + DefKind::Block => SymbolKind::Block, + DefKind::GenerateBlock => SymbolKind::Generate, DefKind::Subroutine | DefKind::Method => SymbolKind::Fn, + DefKind::NonAnsiPort => SymbolKind::NonAnsiPortLabel, DefKind::SubroutinePort | DefKind::Port => SymbolKind::PortDecl, DefKind::Typedef | DefKind::Enum => SymbolKind::Typedef, DefKind::Struct => SymbolKind::Struct, DefKind::Net => SymbolKind::NetDecl, DefKind::Variable | DefKind::ClassField => SymbolKind::DataDecl, DefKind::Param => SymbolKind::ParamDecl, + DefKind::Genvar => SymbolKind::Genvar, + DefKind::Specparam => SymbolKind::Specparam, DefKind::Instance => SymbolKind::Instance, + DefKind::Stmt => SymbolKind::Stmt, } } } @@ -249,6 +261,123 @@ pub struct Import { pub wildcard_pkg: Option, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum NameResolution { + Unique(T), + Ambiguous(SmallVec<[T; 2]>), + Unresolved, +} + +impl NameResolution { + pub fn unique(self) -> Option { + match self { + NameResolution::Unique(value) => Some(value), + NameResolution::Ambiguous(_) | NameResolution::Unresolved => None, + } + } +} + +impl NameScope { + pub fn insert_type(&mut self, ident: &Ident, def_id: DefId) { + Self::insert(&mut self.types, ident, def_id); + } + + pub fn insert_type_opt(&mut self, ident: &Option, def_id: DefId) { + if let Some(ident) = ident { + self.insert_type(ident, def_id); + } + } + + pub fn insert_value(&mut self, ident: &Ident, def_id: DefId) { + Self::insert(&mut self.values, ident, def_id); + } + + pub fn insert_value_opt(&mut self, ident: &Option, def_id: DefId) { + if let Some(ident) = ident { + self.insert_value(ident, def_id); + } + } + + pub fn insert_assertion(&mut self, ident: &Ident, def_id: DefId) { + Self::insert(&mut self.assertions, ident, def_id); + } + + pub fn lookup_merged(&self, ident: &Ident) -> Option> { + let mut defs = SmallVec::new(); + if let Some(type_defs) = self.types.get(ident) { + defs.extend_from_slice(type_defs); + } + if let Some(value_defs) = self.values.get(ident) { + defs.extend_from_slice(value_defs); + } + + (!defs.is_empty()).then_some(defs) + } + + pub fn iter_merged(&self) -> impl Iterator)> + '_ { + self.types + .iter() + .map(|(ident, type_defs)| { + let mut defs = SmallVec::from_slice(type_defs); + if let Some(value_defs) = self.values.get(ident) { + defs.extend_from_slice(value_defs); + } + (ident, defs) + }) + .chain( + self.values + .iter() + .filter(|(ident, _)| !self.types.contains_key(*ident)) + .map(|(ident, defs)| (ident, SmallVec::from_slice(defs))), + ) + } + + pub fn module_ids( + &self, + db: &dyn InternDb, + ident: &Ident, + ) -> NameResolution { + let entries = self + .values + .get(ident) + .into_iter() + .flat_map(|defs| defs.iter()) + .filter_map(|def_id| def_id.as_module(db)) + .collect::>(); + + match entries.as_slice() { + [module_id] => NameResolution::Unique(*module_id), + [] => NameResolution::Unresolved, + _ => NameResolution::Ambiguous(entries), + } + } + + pub fn module_names<'a>( + &'a self, + db: &'a dyn InternDb, + ) -> impl Iterator + 'a { + self.values.iter().filter_map(move |(ident, defs)| { + defs.iter().any(|def_id| def_id.as_module(db).is_some()).then_some(ident) + }) + } + + pub fn typedef_names<'a>( + &'a self, + db: &'a dyn InternDb, + ) -> impl Iterator + 'a { + self.types.iter().filter_map(move |(ident, defs)| { + defs.iter().any(|def_id| matches!(def_id.loc(db), DefLoc::Typedef(_))).then_some(ident) + }) + } + + fn insert(map: &mut FxHashMap>, ident: &Ident, def_id: DefId) { + let defs = map.entry(ident.clone()).or_default(); + if !defs.contains(&def_id) { + defs.push(def_id); + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum SymbolKind { Module, diff --git a/crates/hir/src/type_infer.rs b/crates/hir/src/type_infer.rs index 1a777354..8cfca16a 100644 --- a/crates/hir/src/type_infer.rs +++ b/crates/hir/src/type_infer.rs @@ -3,7 +3,7 @@ use triomphe::Arc; use utils::get::GetRef; use crate::{ - container::{InContainer, InGenerateBlock, InModule, InSubroutine, ScopeId}, + container::{InContainer, InSubroutine, ScopeId}, db::HirDb, hir_def::{ Ident, @@ -21,6 +21,7 @@ use crate::{ typedef::TypedefId, }, semantics::pathres::{PathResolution, resolve_name}, + symbol::{DefId, DefKind}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -114,32 +115,75 @@ fn type_of_decl_impl(db: &dyn HirDb, decl: InContainer) -> TyResult { } fn type_of_path_resolution_impl(db: &dyn HirDb, res: PathResolution) -> TyResult { - match res { - PathResolution::Module(module_id) => TyResult::new(Ty::Module(module_id)), - PathResolution::Decl(decl) => type_of_decl_impl(db, decl), - PathResolution::Typedef(typedef) => type_of_typedef_impl(db, typedef), - PathResolution::ParamDecl(decl) | PathResolution::AnsiPort(decl) => { - type_of_decl_impl(db, decl.into()) + let mut port_ty = None; + for def_id in res.def_ids() { + let ty = type_of_def_id(db, *def_id); + match def_id.kind(db) { + DefKind::NonAnsiPort => {} + DefKind::Port | DefKind::SubroutinePort => { + port_ty.get_or_insert(ty); + } + _ if !matches!(ty.ty, Ty::Unknown) => return ty, + _ => {} } - PathResolution::NonAnsiPort { port_decl, data_decl, module, .. } => data_decl - .or(port_decl) - .map(|decl| type_of_decl_impl(db, InContainer::new(module.into(), decl))) + } + port_ty.unwrap_or_else(|| TyResult::new(Ty::Unknown)) +} + +fn type_of_def_id(db: &dyn HirDb, def_id: DefId) -> TyResult { + match def_id.kind(db) { + DefKind::Module => def_id + .as_module(db) + .map(|module_id| TyResult::new(Ty::Module(module_id))) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), - PathResolution::SubroutinePort(port) => type_of_subroutine_port_impl(db, port), - PathResolution::Instance(instance) => { - instance_target_module_id(db, instance.module_id, instance.value) - .map(|module_id| TyResult::new(Ty::Module(module_id))) - .unwrap_or_else(|| TyResult::new(Ty::Unknown)) - } - PathResolution::GenerateBlock(generate_block_id) => { - TyResult::new(Ty::GenerateBlock(generate_block_id)) - } - PathResolution::Block(block_id) => TyResult::new(Ty::Block(block_id)), - PathResolution::Config(_) - | PathResolution::Library(_) - | PathResolution::Udp(_) - | PathResolution::Subroutine(_) - | PathResolution::Stmt(_) => TyResult::new(Ty::Unknown), + DefKind::Port + | DefKind::Variable + | DefKind::Net + | DefKind::Param + | DefKind::Genvar + | DefKind::Specparam => def_id + .as_decl(db) + .map(|decl| type_of_decl_impl(db, decl)) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::Typedef | DefKind::Enum | DefKind::Struct => def_id + .as_typedef(db) + .map(|typedef| type_of_typedef_impl(db, typedef)) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::SubroutinePort => def_id + .as_subroutine_port(db) + .map(|port| type_of_subroutine_port_impl(db, port)) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::Instance => def_id + .as_instance(db) + .and_then(|instance| instance_target_module_id(db, instance.module_id, instance.value)) + .map(|module_id| TyResult::new(Ty::Module(module_id))) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::GenerateBlock => def_id + .as_generate_block(db) + .map(|generate_block_id| TyResult::new(Ty::GenerateBlock(generate_block_id))) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::Block => def_id + .as_block(db) + .map(|block_id| TyResult::new(Ty::Block(block_id))) + .unwrap_or_else(|| TyResult::new(Ty::Unknown)), + DefKind::Interface + | DefKind::Package + | DefKind::Program + | DefKind::Class + | DefKind::Covergroup + | DefKind::Checker + | DefKind::Udp + | DefKind::Config + | DefKind::Library + | DefKind::Subroutine + | DefKind::NonAnsiPort + | DefKind::ClassField + | DefKind::Method + | DefKind::Modport + | DefKind::ClockingBlock + | DefKind::Sequence + | DefKind::Property + | DefKind::Stmt => TyResult::new(Ty::Unknown), } } @@ -302,8 +346,14 @@ fn type_of_named_data_ty( }; match resolve_name(db, container, &ident) { - Some(PathResolution::Typedef(typedef)) => type_of_typedef_inner(db, typedef, seen), - Some(res) => type_of_path_resolution_impl(db, res), + Some(res) => { + for def_id in res.def_ids() { + if let Some(typedef) = def_id.as_typedef(db) { + return type_of_typedef_inner(db, typedef, seen); + } + } + type_of_path_resolution_impl(db, res) + } None => TyResult::new(Ty::Unknown), } } @@ -360,11 +410,11 @@ fn struct_members(db: &dyn HirDb, struct_id: InContainer) -> Vec Vec { let mut members: Vec<_> = db .module_scope(module_id) - .iter() - .map(|(name, entry)| { - let origin = PathResolution::from(InModule::new(module_id, entry)); - let ty = type_of_path_resolution_impl(db, origin).ty; - TyMember { name: name.clone(), ty, origin: Some(origin) } + .iter_merged() + .filter_map(|(name, defs)| { + let origin = PathResolution::from_def_ids(defs)?; + let ty = type_of_path_resolution_impl(db, origin.clone()).ty; + Some(TyMember { name: name.clone(), ty, origin: Some(origin) }) }) .collect(); sort_members(&mut members); @@ -374,11 +424,11 @@ fn module_members(db: &dyn HirDb, module_id: ModuleId) -> Vec { fn generate_block_members(db: &dyn HirDb, generate_block_id: GenerateBlockId) -> Vec { let mut members: Vec<_> = db .generate_block_scope(generate_block_id) - .iter() - .map(|(name, entry)| { - let origin = PathResolution::from(InGenerateBlock::new(generate_block_id, entry)); - let ty = type_of_path_resolution_impl(db, origin).ty; - TyMember { name: name.clone(), ty, origin: Some(origin) } + .iter_merged() + .filter_map(|(name, defs)| { + let origin = PathResolution::from_def_ids(defs)?; + let ty = type_of_path_resolution_impl(db, origin.clone()).ty; + Some(TyMember { name: name.clone(), ty, origin: Some(origin) }) }) .collect(); sort_members(&mut members); @@ -388,11 +438,11 @@ fn generate_block_members(db: &dyn HirDb, generate_block_id: GenerateBlockId) -> fn block_members(db: &dyn HirDb, block_id: crate::hir_def::block::BlockId) -> Vec { let mut members: Vec<_> = db .block_scope(block_id) - .iter() - .map(|(name, entry)| { - let origin = PathResolution::from(crate::container::InBlock::new(block_id, entry)); - let ty = type_of_path_resolution_impl(db, origin).ty; - TyMember { name: name.clone(), ty, origin: Some(origin) } + .iter_merged() + .filter_map(|(name, defs)| { + let origin = PathResolution::from_def_ids(defs)?; + let ty = type_of_path_resolution_impl(db, origin.clone()).ty; + Some(TyMember { name: name.clone(), ty, origin: Some(origin) }) }) .collect(); sort_members(&mut members); @@ -458,7 +508,7 @@ fn instance_target_module_id( let instance = module.get(instance_id); let instantiation = module.get(instance.parent); let module_name = instantiation.module_name.as_ref()?; - db.unit_scope().resolve_module(module_name).unique() + db.unit_scope().module_ids(db, module_name).unique() } fn int_kind_width(kind: IntKind) -> usize { diff --git a/crates/ide/src/code_action/handlers/convert_port_declarations.rs b/crates/ide/src/code_action/handlers/convert_port_declarations.rs index a159330d..209b29b5 100644 --- a/crates/ide/src/code_action/handlers/convert_port_declarations.rs +++ b/crates/ide/src/code_action/handlers/convert_port_declarations.rs @@ -14,8 +14,8 @@ use hir::{ port::{PortDecl, PortDeclSrc, Ports}, }, }, - scope::{ModuleEntry, ModuleScope, NonAnsiPortEntry}, source_map::IsSrc, + symbol::{DefKind, NameScope}, }; use itertools::Itertools; use syntax::{ @@ -216,18 +216,30 @@ fn non_ansi_port_replacement( ctx: &CodeActionCtx, module: &Module, module_src_map: &ModuleSourceMap, - module_scope: &ModuleScope, + module_scope: &NameScope, name: &Ident, text: &str, ) -> Option { - let ModuleEntry::NonAnsiPortEntry(NonAnsiPortEntry { - port_decl: Some(port_decl), - data_decl, - .. - }) = module_scope.get(name)? - else { + let defs = module_scope.lookup_merged(name)?; + if !defs.iter().any(|def_id| def_id.kind(ctx.sema().db) == DefKind::NonAnsiPort) { return None; - }; + } + + let port_decl = defs + .iter() + .filter_map(|def_id| def_id.as_decl(ctx.sema().db)) + .find(|decl_id| { + matches!(module.get(decl_id.value).parent, DeclaratorParent::PortDeclId(_)) + })? + .value; + let data_decl = defs + .iter() + .filter_map(|def_id| def_id.as_decl(ctx.sema().db)) + .find(|decl_id| { + matches!(module.get(decl_id.value).parent, DeclaratorParent::DeclarationId(_)) + }) + .map(|decl_id| decl_id.value); + let DeclaratorParent::PortDeclId(port_decl_id) = module.get(port_decl).parent else { return None; }; diff --git a/crates/ide/src/code_lens.rs b/crates/ide/src/code_lens.rs index 972e470c..a422c07d 100644 --- a/crates/ide/src/code_lens.rs +++ b/crates/ide/src/code_lens.rs @@ -1,6 +1,5 @@ use hir::{ db::{HirDb, InternDb}, - def_id::ModuleDefOrigin, file::HirFileId, hir_def::{ file::{FileSourceMap, HirFile}, @@ -8,6 +7,7 @@ use hir::{ }, semantics::Semantics, source_map::IsSrc, + symbol::DefId, }; use syntax::{ ast::{self, AstNode}, @@ -87,8 +87,8 @@ pub(crate) fn code_lens_resolve(db: &RootDb, mut kind: CodeLensKind) -> CodeLens }; let module_id = ModuleId::new(hir_file_id, local_module_id); - let def = ModuleDefOrigin::from_loc(sema.db, module_id); - let def = hir::def_id::ModuleDef::from_origins([def]) + let def = DefId::new(sema.db, module_id); + let def = hir::def_id::ModuleDef::from_def_ids([def]) .expect("module definition should have an origin"); let def = sema.db.intern_module_def(def); diff --git a/crates/ide/src/completion/engine/expr.rs b/crates/ide/src/completion/engine/expr.rs index 0f85f0ff..2a253ba1 100644 --- a/crates/ide/src/completion/engine/expr.rs +++ b/crates/ide/src/completion/engine/expr.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use hir::{ - container::{InContainer, InSubroutine, ScopeId, ScopeParent}, + container::{InContainer, ScopeId, ScopeParent}, db::HirDb, file::HirFileId, hir_def::{ @@ -9,11 +9,8 @@ use hir::{ module::ModuleId, subroutine::{SubroutineId, SubroutineKind}, }, - scope::{ - AnsiPortEntry, BlockEntry, GenerateBlockEntry, ModuleEntry, NonAnsiPortEntry, - SubroutineEntry, UnitEntry, - }, semantics::{Semantics, pathres::PathResolution}, + symbol::{DefId, DefKind}, type_infer::{Ty, normalize_data_ty, type_class}, }; use syntax::{ @@ -118,52 +115,20 @@ fn collect_container_names( ScopeId::Module(module_id) => collect_module_names(db, module_id, names), ScopeId::GenerateBlock(generate_block_id) => { let scope = db.generate_block_scope(generate_block_id); - for (ident, entry) in scope.iter() { - match entry { - GenerateBlockEntry::DeclId(decl_id) => { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), - }); - } - GenerateBlockEntry::SubroutineId(subroutine_id) => { - names.entry(ident.to_string()).or_insert(NameKind::SubroutineCall { - return_ty: subroutine_return_ty(db, subroutine_id), - }); - } - _ => {} - } + for (ident, defs) in scope.iter_merged() { + collect_def_names(db, ident, defs, names); } } ScopeId::Block(block_id) => { let scope = db.block_scope(block_id); - for (ident, entry) in scope.iter() { - if let BlockEntry::DeclId(decl_id) = entry { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), - }); - } + for (ident, defs) in scope.iter_merged() { + collect_def_names(db, ident, defs, names); } } ScopeId::Subroutine(subroutine_id) => { let scope = db.subroutine_scope(subroutine_id); - for (ident, entry) in scope.iter() { - match entry { - SubroutineEntry::DeclId(decl_id) => { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), - }); - } - SubroutineEntry::SubroutinePortId(port_id) => { - let ty = db - .type_of_path_resolution(PathResolution::SubroutinePort( - InSubroutine::new(subroutine_id, port_id), - )) - .ty - .clone(); - names.entry(ident.to_string()).or_insert(NameKind::Value { ty }); - } - _ => {} - } + for (ident, defs) in scope.iter_merged() { + collect_def_names(db, ident, defs, names); } } } @@ -171,48 +136,49 @@ fn collect_container_names( fn collect_file_names(db: &RootDb, file_id: HirFileId, names: &mut BTreeMap) { let scope = db.file_scope(file_id); - for (ident, entry) in scope.iter() { - if let UnitEntry::FiledDeclId(decl_id) = entry { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db - .type_of_decl(InContainer::new(ScopeId::File(file_id), decl_id.value)) - .ty - .clone(), - }); - } + for (ident, defs) in scope.iter_merged() { + collect_def_names(db, ident, defs, names); } } fn collect_module_names(db: &RootDb, module_id: ModuleId, names: &mut BTreeMap) { let scope = db.module_scope(module_id); - for (ident, entry) in scope.iter() { - match entry { - ModuleEntry::DeclId(decl_id) => { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(), - }); - } - ModuleEntry::AnsiPortEntry(AnsiPortEntry(decl_id)) => { - names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(), - }); - } - ModuleEntry::NonAnsiPortEntry(NonAnsiPortEntry { port_decl, data_decl, .. }) => { - let ty = data_decl - .or(port_decl) - .map(|decl_id| { - db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone() - }) - .unwrap_or(Ty::Unknown); - names.entry(ident.to_string()).or_insert(NameKind::Value { ty }); - } - ModuleEntry::SubroutineId(subroutine_id) => { - names.entry(ident.to_string()).or_insert(NameKind::SubroutineCall { - return_ty: subroutine_return_ty(db, subroutine_id), - }); - } - _ => {} - } + for (ident, defs) in scope.iter_merged() { + collect_def_names(db, ident, defs, names); + } +} + +fn collect_def_names( + db: &RootDb, + ident: &hir::hir_def::Ident, + defs: impl IntoIterator, + names: &mut BTreeMap, +) { + let defs = defs.into_iter().collect::>(); + + if let Some(subroutine_id) = defs.iter().find_map(|def_id| def_id.as_subroutine(db)) { + names.entry(ident.to_string()).or_insert(NameKind::SubroutineCall { + return_ty: subroutine_return_ty(db, subroutine_id), + }); + return; + } + + if defs.iter().any(|def_id| { + matches!( + def_id.kind(db), + DefKind::Variable + | DefKind::Net + | DefKind::Param + | DefKind::Port + | DefKind::Genvar + | DefKind::Specparam + | DefKind::SubroutinePort + | DefKind::NonAnsiPort + ) + }) && let Some(res) = PathResolution::from_def_ids(defs.iter().copied()) + { + let ty = db.type_of_path_resolution(res).ty.clone(); + names.entry(ident.to_string()).or_insert(NameKind::Value { ty }); } } diff --git a/crates/ide/src/completion/engine/keywords.rs b/crates/ide/src/completion/engine/keywords.rs index 2fa0f860..99b77a76 100644 --- a/crates/ide/src/completion/engine/keywords.rs +++ b/crates/ide/src/completion/engine/keywords.rs @@ -39,16 +39,13 @@ fn module_instantiation_snippets( ctx: &CompletionContext, enabled: bool, ) -> Vec { - use hir::scope::UnitEntry; - if !enabled || prefix.is_empty() { return Vec::new(); } let mut modules: Vec = db .unit_scope() - .iter() - .filter_map(|(ident, entry)| matches!(entry, UnitEntry::ModuleId(_)).then_some(ident)) + .module_names(db) .map(|ident| ident.to_string()) .filter(|name| name.starts_with(prefix)) .collect(); diff --git a/crates/ide/src/completion/engine/paren_list.rs b/crates/ide/src/completion/engine/paren_list.rs index 848d712e..e907b541 100644 --- a/crates/ide/src/completion/engine/paren_list.rs +++ b/crates/ide/src/completion/engine/paren_list.rs @@ -4,7 +4,6 @@ use hir::{ Ident, lower_ident_opt, module::{ModuleId, ModuleSrc}, }, - scope::{ModuleEntry, UnitEntry}, semantics::Semantics, }; use rustc_hash::FxHashSet; @@ -98,11 +97,8 @@ fn complete_parameter_port_list_with_typedefs( let mut items: Vec = db .unit_scope() - .iter() - .filter_map(|(ident, entry)| matches!(entry, UnitEntry::FiledTypedefId(_)).then_some(ident)) - .chain(db.module_scope(module_id).iter().filter_map(|(ident, entry)| { - matches!(entry, ModuleEntry::TypedefId(_)).then_some(ident) - })) + .typedef_names(db) + .chain(db.module_scope(module_id).typedef_names(db)) .map(|ident| ident.to_string()) .filter(|name| name.starts_with(prefix)) .map(|name| CompletionCandidate::text(name, ctx.replacement)) diff --git a/crates/ide/src/completion/engine/port_list.rs b/crates/ide/src/completion/engine/port_list.rs index 292e289e..544757c7 100644 --- a/crates/ide/src/completion/engine/port_list.rs +++ b/crates/ide/src/completion/engine/port_list.rs @@ -1,8 +1,8 @@ use hir::{ db::HirDb, hir_def::module::{ModuleId, ModuleSrc}, - scope::{ModuleEntry, UnitEntry}, semantics::Semantics, + symbol::DefKind, }; use syntax::ast; use utils::get::Get; @@ -71,21 +71,10 @@ fn visible_typedefs_in_module_header(db: &RootDb, position: FilePosition) -> Vec return Vec::new(); }; - let mut names: Vec = db - .unit_scope() - .iter() - .filter_map(|(ident, entry)| matches!(entry, UnitEntry::FiledTypedefId(_)).then_some(ident)) - .map(|ident| ident.to_string()) - .collect(); + let mut names: Vec = + db.unit_scope().typedef_names(db).map(|ident| ident.to_string()).collect(); - names.extend( - db.module_scope(module_id) - .iter() - .filter_map(|(ident, entry)| { - matches!(entry, ModuleEntry::TypedefId(_)).then_some(ident) - }) - .map(|ident| ident.to_string()), - ); + names.extend(db.module_scope(module_id).typedef_names(db).map(|ident| ident.to_string())); names.sort(); names.dedup(); @@ -116,14 +105,11 @@ fn complete_non_ansi_port_list( let scope = db.module_scope(module_id); scope - .iter() - .filter_map(|(ident, entry)| { - matches!( - entry, - hir::scope::ModuleEntry::AnsiPortEntry(_) - | hir::scope::ModuleEntry::NonAnsiPortEntry(_) - ) - .then_some(ident.to_string()) + .iter_merged() + .filter_map(|(ident, defs)| { + defs.iter() + .any(|def_id| matches!(def_id.kind(db), DefKind::Port | DefKind::NonAnsiPort)) + .then(|| ident.to_string()) }) .filter(|name| name.starts_with(prefix)) .map(|name| CompletionCandidate::text(name, ctx.replacement)) diff --git a/crates/ide/src/completion/engine/typed_filter.rs b/crates/ide/src/completion/engine/typed_filter.rs index 3fd85613..b3109d4f 100644 --- a/crates/ide/src/completion/engine/typed_filter.rs +++ b/crates/ide/src/completion/engine/typed_filter.rs @@ -1,5 +1,5 @@ use hir::{ - container::InContainer, + container::{InContainer, ScopeId}, db::HirDb, hir_def::{ Ident, @@ -7,8 +7,8 @@ use hir::{ expr::declarator::DeclaratorParent, module::{ModuleId, port::Ports}, }, - scope::ModuleEntry, semantics::pathres::PathResolution, + symbol::DefKind, type_infer::{Ty, TyClass, packed_bit_width, type_class}, }; use utils::get::GetRef; @@ -21,19 +21,15 @@ pub(super) fn expected_port_ty( port_name: &Ident, ) -> Option { let scope = db.module_scope(target_module_id); - let entry = scope.get(port_name)?; - - match entry { - ModuleEntry::AnsiPortEntry(_) | ModuleEntry::NonAnsiPortEntry(_) => Some( - db.type_of_path_resolution(PathResolution::from(hir::container::InModule::new( - target_module_id, - entry, - ))) - .ty - .clone(), - ), - _ => None, - } + let defs = scope.lookup_merged(port_name)?; + let res = if defs.iter().any(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) { + PathResolution::from_def_ids(defs)? + } else { + PathResolution::from_def_ids( + defs.into_iter().filter(|def_id| def_id.kind(db) == DefKind::Port), + )? + }; + Some(db.type_of_path_resolution(res).ty.clone()) } pub(super) fn expected_param_ty( @@ -43,21 +39,32 @@ pub(super) fn expected_param_ty( ) -> Option { let target_module = db.module(target_module_id); let scope = db.module_scope(target_module_id); - let ModuleEntry::DeclId(decl_id) = scope.get(param_name)? else { - return None; - }; + let defs = scope.lookup_merged(param_name)?; - let DeclaratorParent::DeclarationId(declaration_id) = target_module.get(decl_id).parent else { - return None; - }; - let Declaration::ParamDecl(param_decl) = target_module.get(declaration_id) else { - return None; - }; + for def_id in defs { + if def_id.kind(db) != DefKind::Param { + continue; + } + let Some(decl_id) = def_id.as_decl(db) else { + continue; + }; + if decl_id.cont_id != ScopeId::Module(target_module_id) { + continue; + } + let DeclaratorParent::DeclarationId(declaration_id) = + target_module.get(decl_id.value).parent + else { + continue; + }; + let Declaration::ParamDecl(param_decl) = target_module.get(declaration_id) else { + continue; + }; + if param_decl.kind.is_overridable() { + return Some(db.type_of_decl(decl_id).ty.clone()); + } + } - param_decl - .kind - .is_overridable() - .then(|| db.type_of_decl(InContainer::new(target_module_id.into(), decl_id)).ty.clone()) + None } pub(super) fn value_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Vec<(String, Ty)> { diff --git a/crates/ide/src/definitions.rs b/crates/ide/src/definitions.rs index 5be507ce..e93e3ccc 100644 --- a/crates/ide/src/definitions.rs +++ b/crates/ide/src/definitions.rs @@ -1,7 +1,8 @@ use hir::{ - def_id::{ModuleDefId, ModuleDefOrigin}, + def_id::ModuleDefId, file::HirFileId, semantics::{Semantics, pathres::PathResolution}, + symbol::DefId, }; use smallvec::SmallVec; use syntax::{ @@ -82,7 +83,7 @@ impl DefinitionClass { Some(res) } - pub(crate) fn origins(self, db: &RootDb) -> SmallVec<[ModuleDefOrigin; 6]> { + pub(crate) fn origins(self, db: &RootDb) -> SmallVec<[DefId; 6]> { match self { DefinitionClass::Definition(definition) => definition.origins(db).into_iter().collect(), DefinitionClass::PortConnShorthand { port, local } => { @@ -104,7 +105,9 @@ fn resolve_declaration_name( && module.name() == Some(tok) { let module_id = sema.module_to_def(file_id, module)?; - return Some(PathResolution::Module(module_id).to_def_id(sema.db)?.into()); + return Some( + PathResolution::from_def_id(DefId::new(sema.db, module_id)).to_def_id(sema.db)?.into(), + ); } None @@ -146,13 +149,18 @@ fn resolve_instantiation_type_name( { return match resolve_instantiation_target(sema.db, file_id.file_id(), instantiation) { ModuleResolution::Unique(module_id) - | ModuleResolution::BestEffortProximity { selected: module_id, .. } => { - Some(PathResolution::Module(module_id).to_def_id(sema.db)?.into()) - } + | ModuleResolution::BestEffortProximity { selected: module_id, .. } => Some( + PathResolution::from_def_id(DefId::new(sema.db, module_id)) + .to_def_id(sema.db)? + .into(), + ), ModuleResolution::Ambiguous { candidates, .. } => Some(DefinitionClass::Ambiguous( candidates .into_iter() - .map(|module_id| PathResolution::Module(module_id).to_def_id(sema.db)) + .map(|module_id| { + PathResolution::from_def_id(DefId::new(sema.db, module_id)) + .to_def_id(sema.db) + }) .collect::>>()?, )), ModuleResolution::Unresolved => None, @@ -184,7 +192,7 @@ mod tests { use hir::{ base_db::{change::Change, source_root::SourceRoot}, - def_id::ModuleDefOrigin, + symbol::DefKind, }; use syntax::SyntaxNodeExt; use triomphe::Arc; @@ -260,11 +268,11 @@ mod tests { let origins = def.origins(db); let (resolution, range) = match origins.first().copied() { - Some(origin @ ModuleDefOrigin::NonAnsiPort(_)) => ( + Some(origin) if origin.kind(db) == DefKind::NonAnsiPort => ( "NonAnsiPort", origin.name_range(db).expect("non-ANSI port label should have a name range"), ), - Some(origin @ ModuleDefOrigin::Decl(_)) => { + Some(origin) if origin.kind(db) == DefKind::Port => { ("AnsiPort", origin.name_range(db).expect("ANSI port should have a name range")) } other => panic!("unexpected definition for {name}: {other:?}"), diff --git a/crates/ide/src/inlay_hint.rs b/crates/ide/src/inlay_hint.rs index 228437e7..065337fb 100644 --- a/crates/ide/src/inlay_hint.rs +++ b/crates/ide/src/inlay_hint.rs @@ -16,8 +16,8 @@ use hir::{ }, }, preproc::{MacroCallResolution, macro_call_resolutions_in_range}, - scope::{AnsiPortEntry, ModuleEntry, ModuleScope, NonAnsiPortEntry}, source_map::{IsNamedSrc, IsSrc}, + symbol::{DefKind, NameScope}, }; use syntax::{ast, match_ast_kind}; use utils::{ @@ -383,16 +383,26 @@ fn process_instantiation( match &target_module.ports { Ports::NonAnsi { .. } => { - let (port_id, name, dir) = - non_ansi_port_id_for_conn(target_module, target_scope, conn, idx)?; + let (port_id, name, dir) = non_ansi_port_id_for_conn( + db, + target_module, + target_scope, + conn, + idx, + )?; let target_src = InFile::new(target_file, target_src_map.get(port_id)?); collect_connection_hint( module, src_map, conn_id, name, dir, target_src, collector, ); } Ports::Ansi(_) => { - let (port_decl_id, decl_id) = - ansi_port_decl_id_for_conn(target_module, target_scope, conn, idx)?; + let (port_decl_id, decl_id) = ansi_port_decl_id_for_conn( + db, + target_module, + target_scope, + conn, + idx, + )?; let port_decl = target_module.get(port_decl_id); let name = target_module.get(decl_id).name.as_ref()?; let dir = port_decl.header.dir(); @@ -463,8 +473,9 @@ fn collect_connection_hint( } fn non_ansi_port_id_for_conn<'a>( + db: &RootDb, module: &'a Module, - scope: &ModuleScope, + scope: &NameScope, conn: &'a PortConn, idx: usize, ) -> Option<(NonAnsiPortId, &'a Ident, PortDirection)> { @@ -475,17 +486,18 @@ fn non_ansi_port_id_for_conn<'a>( }; let (port_id, port) = ports.iter().nth(idx)?; let name = port.label.as_ref()?; - let dir = non_ansi_port_dir_by_port_id(module, scope, port_id)?; + let dir = non_ansi_port_dir_by_port_id(db, module, scope, port_id)?; Some((port_id, name, dir)) } PortConn::Named(Some(name), _) => { - let ModuleEntry::NonAnsiPortEntry(NonAnsiPortEntry { label, .. }) = scope.get(name)? - else { - return None; - }; - let port_id = label?; + let defs = scope.lookup_merged(name)?; + let port_id = defs + .iter() + .find(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) + .and_then(|def_id| def_id.as_non_ansi_port(db))? + .value; let port_name = module.get(port_id).label.as_ref()?; - let dir = non_ansi_port_dir_by_port_id(module, scope, port_id)?; + let dir = non_ansi_port_dir_by_port_id(db, module, scope, port_id)?; Some((port_id, port_name, dir)) } PortConn::Named(None, _) | PortConn::Wildcard => None, @@ -493,8 +505,9 @@ fn non_ansi_port_id_for_conn<'a>( } fn non_ansi_port_dir_by_port_id( + db: &RootDb, module: &Module, - scope: &ModuleScope, + scope: &NameScope, port_id: NonAnsiPortId, ) -> Option { let port = module.get(port_id); @@ -504,20 +517,21 @@ fn non_ansi_port_dir_by_port_id( let Some(name) = module.get(ref_id).ident.as_ref() else { continue; }; - if let Some(port_decl_id) = scope.non_ansi_port_decl_id_by_name(module, name) { + if let Some(port_decl_id) = scope.non_ansi_port_decl_id_by_name(db, module, name) { return Some(module.get(port_decl_id).header.dir()); } } } let name = port.label.as_ref()?; - let port_decl_id = scope.non_ansi_port_decl_id_by_name(module, name)?; + let port_decl_id = scope.non_ansi_port_decl_id_by_name(db, module, name)?; Some(module.get(port_decl_id).header.dir()) } fn ansi_port_decl_id_for_conn( + db: &RootDb, module: &Module, - scope: &ModuleScope, + scope: &NameScope, conn: &PortConn, idx: usize, ) -> Option<(PortDeclId, DeclId)> { @@ -528,9 +542,15 @@ fn ansi_port_decl_id_for_conn( Some((port_decl_id, decl_id)) } PortConn::Named(Some(name), _) => { - let ModuleEntry::AnsiPortEntry(AnsiPortEntry(decl_id)) = scope.get(name)? else { - return None; - }; + let defs = scope.lookup_merged(name)?; + let decl_id = defs + .iter() + .filter(|def_id| def_id.kind(db) == DefKind::Port) + .filter_map(|def_id| def_id.as_decl(db)) + .map(|decl_id| decl_id.value) + .find(|decl_id| { + matches!(module.get(*decl_id).parent, DeclaratorParent::PortDeclId(_)) + })?; let DeclaratorParent::PortDeclId(port_decl_id) = module.get(decl_id).parent else { return None; }; diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 5cba0852..86e0972a 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -2,12 +2,6 @@ #![feature(decl_macro)] pub use hir::base_db::Cancelled; -use hir::hir_def::{ - block::BlockId, - expr::declarator::DeclId, - module::{ModuleId, instantiation::InstanceId, port::NonAnsiPortId}, - stmt::StmtId, -}; pub use range::{ErasedFileAstId, FilePosition, FileRange, RangeInfo}; use syntax::{SyntaxKind, ast, match_ast_kind}; pub type Cancellable = Result; @@ -104,40 +98,32 @@ impl SymbolKind { } } -// TODO: const impl -impl From for SymbolKind { - fn from(_: ModuleId) -> Self { - SymbolKind::Module - } -} - -impl From for SymbolKind { - fn from(_: BlockId) -> Self { - SymbolKind::Block - } -} - -impl From for SymbolKind { - fn from(_: NonAnsiPortId) -> Self { - SymbolKind::NonAnsiPortLabel - } -} - -impl From for SymbolKind { - fn from(_: DeclId) -> Self { - SymbolKind::DataDecl - } -} - -impl From for SymbolKind { - fn from(_: InstanceId) -> Self { - SymbolKind::Instance - } -} - -impl From for SymbolKind { - fn from(_: StmtId) -> Self { - SymbolKind::Stmt +impl From for SymbolKind { + fn from(kind: hir::symbol::SymbolKind) -> Self { + match kind { + hir::symbol::SymbolKind::Module => SymbolKind::Module, + hir::symbol::SymbolKind::Config => SymbolKind::Config, + hir::symbol::SymbolKind::Primitive => SymbolKind::Primitive, + hir::symbol::SymbolKind::NonAnsiPortLabel => SymbolKind::NonAnsiPortLabel, + hir::symbol::SymbolKind::PortDecl => SymbolKind::PortDecl, + hir::symbol::SymbolKind::ParamDecl => SymbolKind::ParamDecl, + hir::symbol::SymbolKind::NetDecl => SymbolKind::NetDecl, + hir::symbol::SymbolKind::DataDecl => SymbolKind::DataDecl, + hir::symbol::SymbolKind::Genvar => SymbolKind::Genvar, + hir::symbol::SymbolKind::Specparam => SymbolKind::Specparam, + hir::symbol::SymbolKind::Typedef => SymbolKind::Typedef, + hir::symbol::SymbolKind::Struct => SymbolKind::Struct, + hir::symbol::SymbolKind::Instance => SymbolKind::Instance, + hir::symbol::SymbolKind::Block => SymbolKind::Block, + hir::symbol::SymbolKind::Stmt => SymbolKind::Stmt, + hir::symbol::SymbolKind::Fn => SymbolKind::Fn, + hir::symbol::SymbolKind::Generate => SymbolKind::Generate, + hir::symbol::SymbolKind::Specify => SymbolKind::Specify, + hir::symbol::SymbolKind::Interface => SymbolKind::Interface, + hir::symbol::SymbolKind::Library => SymbolKind::Library, + hir::symbol::SymbolKind::Region => SymbolKind::Region, + hir::symbol::SymbolKind::Unknown => SymbolKind::Unknown, + } } } diff --git a/crates/ide/src/module_resolution.rs b/crates/ide/src/module_resolution.rs index 0e0b700d..eb786085 100644 --- a/crates/ide/src/module_resolution.rs +++ b/crates/ide/src/module_resolution.rs @@ -5,7 +5,7 @@ use hir::{ source_db::{SourceDb, SourceRootDb}, source_root::SourceRootRole, }, - container::InModule, + container::ScopeId, db::HirDb, hir_def::{ Ident, @@ -14,8 +14,8 @@ use hir::{ lower_ident_opt, module::{ModuleId, instantiation::Instantiation}, }, - scope::ModuleEntry, semantics::pathres::PathResolution, + symbol::DefKind, }; use syntax::{ SyntaxAncestors, @@ -125,11 +125,13 @@ fn resolve_named_port_in_module( module_id: ModuleId, port_name: &Ident, ) -> Option { - let entry = db.module_scope(module_id).get(port_name)?; - if matches!(entry, ModuleEntry::AnsiPortEntry(_) | ModuleEntry::NonAnsiPortEntry(_)) { - Some(PathResolution::from(InModule::new(module_id, entry))) + let defs = db.module_scope(module_id).lookup_merged(port_name)?; + if defs.iter().any(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) { + PathResolution::from_def_ids(defs) } else { - None + PathResolution::from_def_ids( + defs.into_iter().filter(|def_id| def_id.kind(db) == DefKind::Port), + ) } } @@ -138,18 +140,25 @@ fn resolve_named_param_in_module( module_id: ModuleId, param_name: &Ident, ) -> Option { - let ModuleEntry::DeclId(decl_id) = db.module_scope(module_id).get(param_name)? else { - return None; - }; + let defs = db.module_scope(module_id).lookup_merged(param_name)?; let module = db.module(module_id); - if let DeclaratorParent::DeclarationId(declaration_id) = module.get(decl_id).parent - && let Declaration::ParamDecl(param_decl) = module.get(declaration_id) - && param_decl.kind.is_overridable() - { - Some(PathResolution::ParamDecl(InModule::new(module_id, decl_id))) - } else { - None + + for def_id in defs { + let Some(decl_id) = def_id.as_decl(db) else { + continue; + }; + if decl_id.cont_id != ScopeId::Module(module_id) { + continue; + } + if let DeclaratorParent::DeclarationId(declaration_id) = module.get(decl_id.value).parent + && let Declaration::ParamDecl(param_decl) = module.get(declaration_id) + && param_decl.kind.is_overridable() + { + return Some(PathResolution::from_def_id(def_id)); + } } + + None } fn resolve_module_name_with_policy( @@ -321,8 +330,8 @@ mod tests { use hir::{ base_db::{change::Change, source_db::SourceDb, source_root::SourceRoot}, - container::InModule, semantics::pathres::PathResolution, + symbol::DefLoc, }; use smol_str::SmolStr; use syntax::{SyntaxNodeExt, ast}; @@ -487,7 +496,8 @@ mod tests { .find_node_at_offset::(offset) .expect("named port connection should parse at /*caret*/"); match resolve_named_port_connection(&db, fixture.focus, port_conn) { - Some(PathResolution::AnsiPort(InModule { module_id, .. })) => { + Some(res) if resolution_module_id(&db, &res, DefKind::Port).is_some() => { + let module_id = resolution_module_id(&db, &res, DefKind::Port).unwrap(); format!( "AnsiPort module={}", file_path(&fixture.files, module_id.file_id.file_id()) @@ -504,7 +514,8 @@ mod tests { .find_node_at_offset::(offset) .expect("named parameter assignment should parse at /*caret*/"); match resolve_named_param_assignment(&db, fixture.focus, param_assign) { - Some(PathResolution::ParamDecl(InModule { module_id, .. })) => { + Some(res) if resolution_module_id(&db, &res, DefKind::Param).is_some() => { + let module_id = resolution_module_id(&db, &res, DefKind::Param).unwrap(); format!( "ParamDecl module={}", file_path(&fixture.files, module_id.file_id.file_id()) @@ -516,6 +527,22 @@ mod tests { } } + fn resolution_module_id(db: &RootDb, res: &PathResolution, kind: DefKind) -> Option { + res.def_ids().iter().find_map(|def_id| { + if def_id.kind(db) != kind { + return None; + } + match def_id.loc(db) { + DefLoc::Decl(decl_id) => match decl_id.cont_id { + ScopeId::Module(module_id) => Some(module_id), + _ => None, + }, + DefLoc::NonAnsiPort(nonansi_port_id) => Some(nonansi_port_id.module_id), + _ => None, + } + }) + } + fn format_module_resolution(files: &[(String, String)], result: ModuleResolution) -> String { match result { ModuleResolution::Unique(module_id) => { diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 09b19a57..aebd9a1a 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -2,7 +2,6 @@ use hir::{ base_db::intern::Lookup, container::{InContainer, InFile, InModule, InSubroutine, ScopeId}, db::HirDb, - def_id::ModuleDefOrigin, hir_def::{ block::{BlockId, BlockLoc}, declaration::Declaration, @@ -19,7 +18,7 @@ use hir::{ typedef::TypedefId, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, - symbol::DefLoc, + symbol::DefId, }; use smol_str::SmolStr; use syntax::{ @@ -58,23 +57,18 @@ pub(crate) trait ToNav { fn to_nav(&self, db: &RootDb) -> Option; } -impl ToNav for ModuleDefOrigin { +impl ToNav for DefId { fn to_nav(&self, db: &RootDb) -> Option { - match self.loc(db) { - DefLoc::Module(module_id) => module_id.to_nav(db), - DefLoc::Config(config_id) => config_id.to_nav(db), - DefLoc::Library(library_id) => library_id.to_nav(db), - DefLoc::Udp(udp_id) => udp_id.to_nav(db), - DefLoc::Block(block_id) => block_id.to_nav(db), - DefLoc::GenerateBlock(generate_block_id) => generate_block_id.to_nav(db), - DefLoc::Subroutine(subroutine_id) => subroutine_id.to_nav(db), - DefLoc::SubroutinePort(subroutine_port_id) => subroutine_port_id.to_nav(db), - DefLoc::NonAnsiPort(nonansi_port_id) => nonansi_port_id.to_nav(db), - DefLoc::Decl(decl_id) => decl_id.to_nav(db), - DefLoc::Typedef(typedef_id) => typedef_id.to_nav(db), - DefLoc::Instance(instance_id) => instance_id.to_nav(db), - DefLoc::Stmt(stmt_id) => stmt_id.to_nav(db), - } + let InFile { file_id, value: full_range } = self.range(db)?; + let focus_range = self.name_range(db).map(|range| range.value); + let name = self.name(db); + let kind = self.kind(db).symbol_kind().into(); + let container_name = match self.container_id(db) { + ScopeId::File(_) => None, + cont_id => cont_id.to_container(db).name().cloned(), + }; + + Some(build(file_id.file_id(), focus_range, full_range, name, kind, container_name)) } } diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 6f0af8b0..661955e3 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -1,8 +1,6 @@ use hir::{ - base_db::source_db::SourceDb, - container::InFile, - def_id::{ModuleDefId, ModuleDefOrigin}, - semantics::Semantics, + base_db::source_db::SourceDb, container::InFile, def_id::ModuleDefId, semantics::Semantics, + symbol::DefId, }; use nohash_hasher::IntMap; use rustc_hash::FxHashMap; @@ -143,7 +141,7 @@ pub(crate) fn expanded_rename( let sema = Semantics::new(db); let resolved = resolve_rename_target(&sema, position)?; let targets = recursive_rename_targets(db, &sema, position.file_id, &config, resolved.targets)?; - let mut rename_targets = UniqVec::<(), ModuleDefOrigin>::default(); + let mut rename_targets = UniqVec::<(), DefId>::default(); for target in &targets { rename_targets.push(target.def.origins(db), ()); } @@ -188,11 +186,11 @@ pub(crate) fn rename_conflict_info( }; let new_name = SmolStr::new(new_name); - let mut target_index = UniqVec::<(), ModuleDefOrigin>::default(); + let mut target_index = UniqVec::<(), DefId>::default(); for target in &targets { target_index.push(target.origins(db), ()); } - let mut conflicts = UniqVec::::default(); + let mut conflicts = UniqVec::::default(); for collision in targets.iter().flat_map(|target| target.origins(db)).filter_map(|origin| { sema.resolve_name(origin.container_id(db), &new_name).and_then(|res| res.to_def_id(db)) }) { @@ -239,7 +237,7 @@ fn resolve_rename_target( }; let (range, tokens) = target.into_parts(); let mut selected_def = None; - let mut targets = UniqVec::::default(); + let mut targets = UniqVec::::default(); for token in tokens { let token_selected = match DefinitionClass::resolve(sema, hir_file_id, token) @@ -291,7 +289,7 @@ fn rename_definition( config: &RenameConfig, def: &ModuleDefId, new_name: &str, - rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, + rename_targets: Option<&UniqVec<(), DefId>>, ) -> RenameResult { let refs = references_for_definition(db, sema, request_file_id, config, def)?; rename_definition_with_refs(db, sema, def, new_name, rename_targets, &refs, &[]) @@ -313,7 +311,7 @@ fn rename_definition_with_refs( sema: &Semantics<'_, RootDb>, def: &ModuleDefId, new_name: &str, - rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, + rename_targets: Option<&UniqVec<(), DefId>>, refs: &ReferenceSearchResult, same_name_refs: &[SameNameConnectionRef], ) -> RenameResult { @@ -365,7 +363,7 @@ fn recursive_rename_targets( config: &RenameConfig, initial_targets: Vec, ) -> RenameResult> { - let mut targets = UniqVec::::default(); + let mut targets = UniqVec::::default(); for target in initial_targets { targets.push(target.origins(db), target); } @@ -490,7 +488,7 @@ fn edits_from_refs( def: &ModuleDefId, old_name: &str, new_name: &str, - rename_targets: Option<&UniqVec<(), ModuleDefOrigin>>, + rename_targets: Option<&UniqVec<(), DefId>>, same_name_refs: &[SameNameConnectionRef], ) -> (FileId, TextEdit) { let mut text_edit = TextEdit::builder(); diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index 22249997..668f086c 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -5,7 +5,7 @@ use hir::{ }, container::{InContainer, InFile, InModule, InSubroutine, ScopeId, ScopeParent}, db::HirDb, - def_id::{ModuleDefId, ModuleDefOrigin}, + def_id::ModuleDefId, display::HirDisplay, hir_def::{ DEFAULT_NAME, @@ -24,7 +24,7 @@ use hir::{ }, region_tree::RegionParent, semantics::Semantics, - symbol::DefLoc, + symbol::{DefId, DefLoc}, }; use itertools::Itertools; use syntax::{ @@ -181,7 +181,7 @@ pub(crate) fn render_definition_location( fn render_def_origin_location( db: &RootDb, - origin: &ModuleDefOrigin, + origin: &DefId, anchor_file_id: vfs::FileId, ) -> Option { let InFile { value: range, file_id } = origin.range(db)?; @@ -259,7 +259,7 @@ fn has_normal_path_component(path: &utils::paths::AbsPath) -> bool { fn render_def_origin( sema: &Semantics, - origin: &ModuleDefOrigin, + origin: &DefId, anchor_file_id: vfs::FileId, ) -> Markup { let mut res = Markup::new(); @@ -284,7 +284,7 @@ fn render_def_origin( res } -fn render_definition_title(db: &RootDb, origin: &ModuleDefOrigin) -> Option { +fn render_definition_title(db: &RootDb, origin: &DefId) -> Option { let name = origin.name(db)?; let kind = match origin.loc(db) { DefLoc::Module(_) => "Module", @@ -327,7 +327,7 @@ fn render_decl_title_kind(db: &RootDb, decl_id: InContainer) -> Option<& }) } -fn render_signature(sema: &Semantics, origin: &ModuleDefOrigin) -> Option { +fn render_signature(sema: &Semantics, origin: &DefId) -> Option { let db = sema.db; match origin.loc(db) { DefLoc::Module(module_id) => render_module_signature(db, module_id), @@ -619,7 +619,7 @@ fn render_data_ty(db: &RootDb, container: ScopeId, ty: DataTy) -> Option InContainer::new(container, ty).display_source(db).ok() } -fn render_label_signature(db: &RootDb, origin: &ModuleDefOrigin) -> Option { +fn render_label_signature(db: &RootDb, origin: &DefId) -> Option { let name = origin.name(db)?; let kind = match origin.loc(db) { DefLoc::Config(_) => "config", @@ -639,7 +639,7 @@ fn render_label_signature(db: &RootDb, origin: &ModuleDefOrigin) -> Option, origin: &ModuleDefOrigin) -> Option { +fn render_side_comments(sema: &Semantics<'_, RootDb>, origin: &DefId) -> Option { let db = sema.db; let InFile { value: range, file_id } = origin.range(db)?; @@ -677,7 +677,7 @@ fn render_side_comments(sema: &Semantics<'_, RootDb>, origin: &ModuleDefOrigin) } } -fn render_scope_fact(sema: &Semantics, origin: &ModuleDefOrigin) -> Option { +fn render_scope_fact(sema: &Semantics, origin: &DefId) -> Option { // elaboration? let db = sema.db; let InFile { value: range, .. } = origin.range(db)?; @@ -713,7 +713,7 @@ fn render_scope_fact(sema: &Semantics, origin: &ModuleDefOrigin) -> Opti fn render_definition_metadata( sema: &Semantics, - origin: &ModuleDefOrigin, + origin: &DefId, anchor_file_id: vfs::FileId, ) -> Option { let mut parts = Vec::new(); diff --git a/crates/ide/src/semantic_index.rs b/crates/ide/src/semantic_index.rs index 4a02a39e..21f3a0a9 100644 --- a/crates/ide/src/semantic_index.rs +++ b/crates/ide/src/semantic_index.rs @@ -5,12 +5,12 @@ use hir::{ }, container::InFile, db::HirDb, - def_id::{ModuleDefId, ModuleDefOrigin}, + def_id::ModuleDefId, file::HirFileId, hir_def::{Ident, module::ModuleId}, - scope::UnitEntry, semantics::Semantics, source_map::IsSrc, + symbol::{DefId, DefKind}, }; use itertools::Itertools; use rustc_hash::FxHashMap; @@ -117,14 +117,17 @@ impl ModuleIndex { for file_id in source_root.iter() { let hir_file_id = HirFileId::from(file_id); - for (_, entry) in db.file_scope(hir_file_id).iter() { - let UnitEntry::ModuleId(module_id) = entry else { - continue; - }; - let Some(module) = SemanticModuleDefinition::new(db, module_id) else { - continue; - }; - modules_by_name.entry(module.name.clone()).or_default().push(module); + for (_, defs) in db.file_scope(hir_file_id).iter_merged() { + for module_id in defs + .iter() + .filter(|def_id| def_id.kind(db) == DefKind::Module) + .filter_map(|def_id| def_id.as_module(db)) + { + let Some(module) = SemanticModuleDefinition::new(db, module_id) else { + continue; + }; + modules_by_name.entry(module.name.clone()).or_default().push(module); + } } } @@ -163,7 +166,7 @@ impl ModuleIndex { impl SemanticModuleDefinition { fn new(db: &dyn HirDb, module_id: ModuleId) -> Option { - let origin = ModuleDefOrigin::from_loc(db, module_id); + let origin = DefId::new(db, module_id); let name = origin.name(db)?; let InFile { file_id, value: name_range } = origin.name_range(db)?; let InFile { value: full_range, .. } = origin.range(db)?; diff --git a/crates/ide/src/semantic_tokens.rs b/crates/ide/src/semantic_tokens.rs index d4a26cbe..03331b8f 100644 --- a/crates/ide/src/semantic_tokens.rs +++ b/crates/ide/src/semantic_tokens.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use collector::SemaTokenCollectorTree; use hir::{ - container::{InContainer, InModule}, + container::{InContainer, ScopeId}, db::HirDb, file::HirFileId, hir_def::{ @@ -15,9 +15,9 @@ use hir::{ stmt::StmtKind, }, preproc::macro_references_in_range, - scope::NonAnsiPortEntry, semantics::{Semantics, pathres::PathResolution}, source_map::{IsNamedSrc, IsSrc, ToAstNode}, + symbol::{DefKind, DefLoc}, }; use smol_str::SmolStr; use syntax::{ast, has_text_range::HasTextRange}; @@ -465,40 +465,58 @@ fn collect_resolved_path( ) -> Option<()> { let db = sema.db; - match res { - PathResolution::NonAnsiPort { label, port_decl, data_decl, module } => { - let module = db.module(module); - let name = module.get(port_decl?).name.as_ref()?; - let entry = NonAnsiPortEntry { label, port_decl, data_decl }; - let (dir, ty) = port::resolve_non_ansi_port(module.as_ref(), &entry.into())?; - port::add_port_token(db, name, dir, ty, range, collector); - } - PathResolution::AnsiPort(InModule { value: decl_id, module_id }) => { - let module = db.module(module_id); - let name = module.get(decl_id).name.as_ref()?; + if res.def_ids().iter().any(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) { + let module_id = res.def_ids().iter().find_map(|def_id| match def_id.loc(db) { + DefLoc::NonAnsiPort(port_id) => Some(port_id.module_id), + DefLoc::Decl(decl_id) => match decl_id.cont_id { + ScopeId::Module(module_id) => Some(module_id), + _ => None, + }, + _ => None, + })?; + let module = db.module(module_id); + let (name, dir, ty) = port::resolve_non_ansi_port(db, module.as_ref(), res.def_ids())?; + port::add_port_token(db, name, dir, ty, range, collector); + return Some(()); + } - let DeclaratorParent::PortDeclId(port_declaration_id) = module.get(decl_id).parent - else { - return None; - }; - let port_decl = module.get(port_declaration_id); - let header = &port_decl.header; - let (dir, ty) = (Some(header.dir()), header.ty()); - port::add_port_token(db, name, dir, ty, range, collector); - } - PathResolution::Instance(_) => { - let sema_token = - SemaToken { range, tag: SemaTokenTag::Instance, mods: SemaTokenModifier::empty() }; - collector.tokens.add(sema_token); - } - PathResolution::Typedef(_) => { - collector.tokens.add(SemaToken { - range, - tag: SemaTokenTag::Type, - mods: SemaTokenModifier::REF, - }); + for def_id in res.def_ids() { + match def_id.kind(db) { + DefKind::Port => { + let decl_id = def_id.as_decl(db)?; + let ScopeId::Module(module_id) = decl_id.cont_id else { + return None; + }; + let module = db.module(module_id); + let name = module.get(decl_id.value).name.as_ref()?; + + let DeclaratorParent::PortDeclId(port_declaration_id) = + module.get(decl_id.value).parent + else { + return None; + }; + let port_decl = module.get(port_declaration_id); + let header = &port_decl.header; + let (dir, ty) = (Some(header.dir()), header.ty()); + port::add_port_token(db, name, dir, ty, range, collector); + } + DefKind::Instance => { + let sema_token = SemaToken { + range, + tag: SemaTokenTag::Instance, + mods: SemaTokenModifier::empty(), + }; + collector.tokens.add(sema_token); + } + DefKind::Typedef | DefKind::Struct | DefKind::Enum => { + collector.tokens.add(SemaToken { + range, + tag: SemaTokenTag::Type, + mods: SemaTokenModifier::REF, + }); + } + _ => {} } - _ => {} } Some(()) diff --git a/crates/ide/src/semantic_tokens/port.rs b/crates/ide/src/semantic_tokens/port.rs index 5ffa32ac..f75041e1 100644 --- a/crates/ide/src/semantic_tokens/port.rs +++ b/crates/ide/src/semantic_tokens/port.rs @@ -13,9 +13,9 @@ use hir::{ port::{NonAnsiPort, PortDirection, Ports}, }, }, - scope::{ModuleEntry, NonAnsiPortEntry}, semantics::Semantics, source_map::{IsNamedSrc, IsSrc}, + symbol::DefId, }; use regex::{Regex, RegexBuilder}; use smallvec::SmallVec; @@ -61,8 +61,8 @@ pub(super) fn collect_port( check_range!(collector, name_range); let name = module.get(ref_id).ident.as_ref()?; - let entry = module_scope.get(name)?; - let (dir, ty) = resolve_non_ansi_port(module, &entry)?; + let defs = module_scope.lookup_merged(name)?; + let (_, dir, ty) = resolve_non_ansi_port(db, module, &defs)?; add_port_token(db, name, dir, ty, name_range, collector); }; } @@ -80,8 +80,8 @@ pub(super) fn collect_port( check_range!(collector, name_range); let name = decl.name.as_ref()?; - let entry = module_scope.get(name)?; - let (dir, ty) = resolve_non_ansi_port(module, &entry)?; + let defs = module_scope.lookup_merged(name)?; + let (_, dir, ty) = resolve_non_ansi_port(db, module, &defs)?; add_port_token(db, name, dir, ty, name_range, collector); }; } @@ -112,19 +112,22 @@ pub(super) fn collect_port( } } -pub(super) fn resolve_non_ansi_port( - module: &Module, - entry: &ModuleEntry, -) -> Option<(Option, DataTy)> { - let ModuleEntry::NonAnsiPortEntry(NonAnsiPortEntry { - port_decl: Some(port_decl_id), - data_decl: data_decl_id, - .. - }) = *entry - else { - return None; - }; +pub(super) fn resolve_non_ansi_port<'a>( + db: &RootDb, + module: &'a Module, + defs: &[DefId], +) -> Option<(&'a hir::hir_def::Ident, Option, DataTy)> { + let port_decl_id = + defs.iter().filter_map(|def_id| def_id.as_decl(db)).map(|decl_id| decl_id.value).find( + |decl_id| matches!(module.get(*decl_id).parent, DeclaratorParent::PortDeclId(_)), + )?; + let data_decl_id = + defs.iter().filter_map(|def_id| def_id.as_decl(db)).map(|decl_id| decl_id.value).find( + |decl_id| matches!(module.get(*decl_id).parent, DeclaratorParent::DeclarationId(_)), + ); + let port_decl = module.get(port_decl_id); + let name = port_decl.name.as_ref()?; let port_declaration = match port_decl.parent { DeclaratorParent::PortDeclId(port_declaration_id) => module.get(port_declaration_id), _ => return None, @@ -144,7 +147,7 @@ pub(super) fn resolve_non_ansi_port( header.ty() }; - Some((dir, ty)) + Some((name, dir, ty)) } pub(super) fn add_port_token( From 01263264fa0347b17c6f2a4032de1b0a8d0b2336 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 04:29:04 +0800 Subject: [PATCH 5/7] feat(hir): activate PerNs import resolution (cherry picked from commit 1cc16668ac5ca49aca604a06de918c7702cc7765) --- crates/hir/src/db.rs | 8 +- crates/hir/src/def_id.rs | 31 +- crates/hir/src/hir_def.rs | 25 +- crates/hir/src/hir_def/file.rs | 14 +- crates/hir/src/hir_def/module.rs | 45 +- crates/hir/src/scope.rs | 419 +++++++++++++++++- crates/hir/src/semantics.rs | 3 +- crates/hir/src/semantics/hir_to_def.rs | 14 +- crates/hir/src/semantics/pathres.rs | 105 ++++- crates/hir/src/symbol.rs | 82 +++- crates/hir/src/type_infer.rs | 27 +- .../handlers/convert_port_declarations.rs | 4 +- crates/ide/src/completion/engine/expr.rs | 10 +- crates/ide/src/completion/engine/member.rs | 25 +- crates/ide/src/completion/engine/port_list.rs | 2 +- .../ide/src/completion/engine/typed_filter.rs | 6 +- crates/ide/src/definitions.rs | 26 +- crates/ide/src/inlay_hint.rs | 6 +- crates/ide/src/module_resolution.rs | 6 +- crates/ide/src/rename.rs | 12 +- crates/ide/src/render.rs | 57 ++- crates/ide/src/semantic_index.rs | 2 +- crates/ide/src/semantic_tokens.rs | 116 ++++- crates/ide/src/semantic_tokens/port.rs | 6 +- 24 files changed, 939 insertions(+), 112 deletions(-) diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index b1b3cae5..5babbe7e 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -16,7 +16,7 @@ use crate::{ file::{self, FileSourceMap, HirFile}, macro_file::{self, ExpansionInfo, MacroCallId, MacroCallLoc, MacroFileId, MacroFileLoc}, module::{ - self, Module, ModuleId, ModuleSourceMap, + self, Module, ModuleId, ModuleSourceMap, PackageId, generate::{ self, GenerateBlock, GenerateBlockId, GenerateBlockLoc, GenerateBlockSourceMap, }, @@ -135,6 +135,12 @@ pub trait HirDb: InternDb { #[salsa::invoke(NameScope::subroutine_scope_query)] fn subroutine_scope(&self, subroutine_id: SubroutineId) -> Arc; + #[salsa::invoke(NameScope::package_export_signature_query)] + fn package_export_signature(&self, package_id: PackageId) -> Arc; + + #[salsa::invoke(NameScope::package_export_scope_query)] + fn package_export_scope(&self, package_id: PackageId) -> Arc; + #[salsa::invoke(crate::type_infer::type_of_decl_query)] fn type_of_decl(&self, decl: InContainer) -> Arc; diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index be2d1890..e0701cb1 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -14,8 +14,10 @@ use crate::{ container::{InContainer, InFile, InModule, InSubroutine, ScopeId}, db::HirDb, hir_def::{ - block::BlockLoc, declaration::Declaration, expr::declarator::DeclaratorParent, - module::generate::GenerateBlockLoc, + block::BlockLoc, + declaration::Declaration, + expr::declarator::DeclaratorParent, + module::{ModuleKind, generate::GenerateBlockLoc}, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, symbol::{DefId, DefKind, DefLoc}, @@ -32,6 +34,7 @@ impl DefId { DefLoc::Block(block_id) => block_id.lookup(db).cont_id, DefLoc::GenerateBlock(generate_block_id) => generate_block_id.lookup(db).cont_id, DefLoc::Subroutine(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), + DefLoc::PackageSubroutine(InModule { module_id, .. }) => module_id.into(), DefLoc::SubroutinePort(InSubroutine { subroutine, .. }) => { ScopeId::Subroutine(subroutine) } @@ -45,13 +48,22 @@ impl DefId { pub fn kind(self, db: &dyn HirDb) -> DefKind { match self.loc(db) { - DefLoc::Module(_) => DefKind::Module, + DefLoc::Module(module_id) => { + let file = db.hir_file(module_id.file_id); + match file.get(module_id.value).kind { + ModuleKind::Module => DefKind::Module, + ModuleKind::Interface => DefKind::Interface, + ModuleKind::Program => DefKind::Program, + ModuleKind::Package => DefKind::Package, + } + } DefLoc::Config(_) => DefKind::Config, DefLoc::Library(_) => DefKind::Library, DefLoc::Udp(_) => DefKind::Udp, DefLoc::Block(_) => DefKind::Block, DefLoc::GenerateBlock(_) => DefKind::GenerateBlock, DefLoc::Subroutine(_) => DefKind::Subroutine, + DefLoc::PackageSubroutine(_) => DefKind::Subroutine, DefLoc::SubroutinePort(_) => DefKind::SubroutinePort, DefLoc::NonAnsiPort(_) => DefKind::NonAnsiPort, DefLoc::Decl(InContainer { value, cont_id }) => { @@ -100,6 +112,9 @@ impl DefId { db.generate_block(generate_block_id).name.clone() } DefLoc::Subroutine(subroutine_id) => db.subroutine(subroutine_id).name.clone(), + DefLoc::PackageSubroutine(InModule { module_id, value }) => { + db.module(module_id).get(value).name.clone() + } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { db.subroutine(subroutine).ports.get(value.0 as usize)?.name.clone() } @@ -154,6 +169,11 @@ impl DefId { let src = subroutine_id.lookup(db).src; Some(InFile::new(src.file_id, src.value.name_or_full_range())) } + DefLoc::PackageSubroutine(InModule { module_id, value }) => { + let (_, src_map) = db.module_with_source_map(module_id); + let range = src_map.get(value)?.name_range()?; + Some(InFile::new(module_id.file_id, range)) + } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { let src = subroutine.lookup(db).src; let tree = db.parse(src.file_id); @@ -228,6 +248,11 @@ impl DefId { let range = src.value.range(); InFile::new(src.file_id, range) } + DefLoc::PackageSubroutine(InModule { module_id, value }) => { + let (_, src_map) = db.module_with_source_map(module_id); + let range = src_map.get(value)?.range(); + InFile::new(module_id.file_id, range) + } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { let src = subroutine.lookup(db).src; let tree = db.parse(src.file_id); diff --git a/crates/hir/src/hir_def.rs b/crates/hir/src/hir_def.rs index 4e2d50bb..9b14d009 100644 --- a/crates/hir/src/hir_def.rs +++ b/crates/hir/src/hir_def.rs @@ -14,12 +14,19 @@ pub mod typedef; use la_arena::{Arena, Idx, RawIdx}; use smol_str::{SmolStr, ToSmolStr}; -use syntax::{SyntaxToken, ast}; +use syntax::{SyntaxToken, TokenKind, ast}; pub type Ident = SmolStr; pub const DEFAULT_NAME: SmolStr = SmolStr::new_static("unnamed"); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PackageImport { + pub package: Ident, + /// `None` represents `pkg::*`. + pub item: Option, +} + #[inline] pub fn lower_ident(ident: Option) -> Option { Some(ident?.value_text().to_smolstr()) @@ -38,6 +45,22 @@ pub(crate) fn lower_named_label_opt(label: Option) -> Option Vec { + import_decl + .items() + .children() + .filter_map(|item| { + let package = lower_ident_opt(item.package())?; + let item = item.item()?; + let item = + (item.kind() != TokenKind::STAR).then(|| lower_ident_opt(Some(item))).flatten(); + Some(PackageImport { package, item }) + }) + .collect() +} + macro alloc_idx_and_src($file_id:expr; $hir:expr => $arena:expr, $ast:expr => $src_map:expr $(,)?) {{ let idx = $arena.alloc($hir.into()); // HIR lowering can consume include-expanded AST nodes, but source maps only diff --git a/crates/hir/src/hir_def/file.rs b/crates/hir/src/hir_def/file.rs index a8957618..b136cff2 100644 --- a/crates/hir/src/hir_def/file.rs +++ b/crates/hir/src/hir_def/file.rs @@ -14,6 +14,7 @@ use udp::{UdpDecl, UdpDeclId, UdpDeclSrc}; use utils::{define_enum_deriving_from, get::Get}; use super::{ + PackageImport, aggregate::{StructDef, StructId, StructSrc, lower_struct_def}, alloc_idx_and_src, block::{BlockInfo, BlockSrc, LocalBlockId}, @@ -26,7 +27,8 @@ use super::{ impl_lower_expr, timing_control::{EventExpr, EventExprSrc, impl_lower_event_expr}, }, - module::{LocalModuleId, ModuleInfo, ModuleSrc}, + lower_package_imports, + module::{LocalModuleId, ModuleInfo, ModuleKind, ModuleSrc}, proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ @@ -61,6 +63,7 @@ define_container! { library_decls: [LibraryDecl], library_includes: [LibraryInclude], subroutines: [Subroutine], + package_imports: [PackageImport], declarations: [Declaration], exprs: [Expr], @@ -295,10 +298,11 @@ impl LowerFileCtx<'_> { let idx = match member { ModuleDeclaration(decl) => { let name = lower_ident_opt(decl.header().name()); + let kind = ModuleKind::from_ast(decl); alloc_idx_and_src! { self.file_id; - ModuleInfo { name } => self.file.modules, + ModuleInfo { name, kind } => self.file.modules, decl => self.file_source_map.module_srcs, } .into() @@ -314,6 +318,12 @@ impl LowerFileCtx<'_> { Some(id) => id.into(), None => continue, }, + PackageImportDeclaration(import_decl) => { + for import in lower_package_imports(import_decl) { + self.file.package_imports.alloc(import); + } + continue; + } UdpDeclaration(udp_decl) => self.lower_udp_decl(udp_decl).into(), ConfigDeclaration(config_decl) => self.lower_config_decl(config_decl).into(), _ => continue, diff --git a/crates/hir/src/hir_def/module.rs b/crates/hir/src/hir_def/module.rs index ef8796b7..8f63fae8 100644 --- a/crates/hir/src/hir_def/module.rs +++ b/crates/hir/src/hir_def/module.rs @@ -28,7 +28,7 @@ use utils::{ }; use super::{ - HirData, Ident, + HirData, Ident, PackageImport, aggregate::{StructDef, StructId, StructSrc, lower_struct_def}, alloc_idx_and_src, block::{BlockInfo, BlockSrc, LocalBlockId}, @@ -42,7 +42,7 @@ use super::{ impl_lower_expr, timing_control::{EventExpr, EventExprSrc, impl_lower_event_expr}, }, - lower_ident_opt, + lower_ident_opt, lower_package_imports, proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ @@ -91,6 +91,7 @@ define_container! { typedefs: [Typedef], structs: [StructDef], subroutines: [Subroutine], + package_imports: [PackageImport], instantiations: [Instantiation], inst_param_assigns: [ParamAssign], @@ -300,13 +301,43 @@ define_enum_deriving_from! { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum ModuleKind { + Module, + Interface, + Program, + Package, +} + +impl ModuleKind { + pub fn from_ast(decl: ast::ModuleDeclaration) -> Self { + if decl.as_package_declaration().is_some() { + ModuleKind::Package + } else if decl.as_interface_declaration().is_some() { + ModuleKind::Interface + } else if decl.as_program_declaration().is_some() { + ModuleKind::Program + } else { + ModuleKind::Module + } + } +} + +impl Default for ModuleKind { + fn default() -> Self { + ModuleKind::Module + } +} + #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct ModuleInfo { pub name: Option, + pub kind: ModuleKind, } pub type LocalModuleId = Idx; pub type ModuleId = InFile; +pub type PackageId = ModuleId; pub(crate) struct LowerModuleCtx<'a> { pub(crate) db: &'a dyn InternDb, @@ -519,7 +550,12 @@ impl LowerModuleCtx<'_> { ExplicitAnsiPort(_) | ImplicitAnsiPort(_) => continue, // Imports - PackageImportDeclaration(_) => continue, + PackageImportDeclaration(import_decl) => { + for import in lower_package_imports(import_decl) { + self.module.package_imports.alloc(import); + } + continue; + } // Aggregates ClassDeclaration(_) => continue, @@ -643,7 +679,8 @@ pub(crate) fn module_with_source_map_query( let (file, file_source_map) = db.hir_file_with_source_map(file_id); let tree = db.parse(file_id); - let mut module = Module { name: file.get(local_module_id).name.clone(), ..Default::default() }; + let module_info = file.get(local_module_id); + let mut module = Module { name: module_info.name.clone(), ..Default::default() }; let mut module_source_map = ModuleSourceMap::default(); let Some(ast_module) = file_source_map.get(local_module_id).and_then(|src| src.to_node(&tree)) diff --git a/crates/hir/src/scope.rs b/crates/hir/src/scope.rs index befae1cb..18d7d6b8 100644 --- a/crates/hir/src/scope.rs +++ b/crates/hir/src/scope.rs @@ -1,4 +1,6 @@ +use la_arena::{Idx, RawIdx}; use smol_str::SmolStr; +use syntax::ast; use triomphe::Arc; use utils::get::{Get, GetRef}; @@ -7,19 +9,31 @@ use crate::{ db::HirDb, file::HirFileId, hir_def::{ + PackageImport, block::BlockInfo, - expr::declarator::DeclaratorParent, + declaration::DeclarationId, + expr::declarator::{DeclId, DeclaratorParent}, + lower_ident_opt, module::{ - Module, + Module, ModuleKind, PackageId, generate::GenerateBlockId, port::{PortDeclId, Ports}, }, stmt::StmtKind, - subroutine::{SubroutineLoc, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutineLoc, SubroutinePortId}, + typedef::TypedefId, }, - symbol::{DefId, DefLoc, NameScope}, + source_map::ToAstNode, + symbol::{DefId, DefLoc, Import, NameScope}, }; +// SystemVerilog has separate namespaces. This scope stores current supported +// declarations as: +// - types: modules, interfaces, packages, programs, typedefs +// - values: nets, variables, params, ports, subroutines, instances, blocks +// - assertions: reserved for sequence/property/checker work +// Hierarchical lookup remains a separate resolver path. + fn def_id(db: &dyn HirDb, loc: impl Into) -> DefId { DefId::new(db, loc) } @@ -31,18 +45,55 @@ impl NameScope { for file_id in db.files().iter() { let file_id = HirFileId::File(*file_id); let file_scope = db.file_scope(file_id); - scope.extend_from(&file_scope); + scope.extend_defs_from(&file_scope); } Arc::new(scope) } + pub fn package_export_scope_query(db: &dyn HirDb, package_id: PackageId) -> Arc { + db.package_export_signature(package_id) + } + + pub fn package_export_signature_query(db: &dyn HirDb, package_id: PackageId) -> Arc { + let mut scope = NameScope::default(); + let file_id = HirFileId::File(package_id.file_id()); + let (file, file_source_map) = db.hir_file_with_source_map(file_id); + if file.get(package_id.value).kind != ModuleKind::Package { + return Arc::new(scope); + } + + let tree = db.parse(file_id); + let Some(package) = + file_source_map.get(package_id.value).and_then(|src| src.to_node(&tree)) + else { + return Arc::new(scope); + }; + + let mut builder = PackageExportSignatureBuilder { + db, + package_id, + scope: &mut scope, + next_declaration: 0, + next_decl: 0, + next_typedef: 0, + next_subroutine: 0, + }; + builder.collect(package); + + Arc::new(scope) + } + pub(super) fn file_scope_query(db: &dyn HirDb, file_id: HirFileId) -> Arc { let mut scope = NameScope::default(); let hir_file = db.hir_file(file_id); for (module_id, module_info) in hir_file.modules.iter() { - scope.insert_value_opt(&module_info.name, def_id(db, InFile::new(file_id, module_id))); + scope.insert_type_opt(&module_info.name, def_id(db, InFile::new(file_id, module_id))); + } + + for (_, import) in hir_file.package_imports.iter() { + scope.insert_package_import(import); } for (decl_id, decl) in hir_file.decls.iter() { @@ -94,6 +145,10 @@ impl NameScope { } } + for (_, import) in module.package_imports.iter() { + scope.insert_package_import(import); + } + for (local_subroutine_id, subroutine) in module.subroutines.iter() { let Some(src) = module_src_map.get(local_subroutine_id) else { continue; @@ -309,7 +364,11 @@ impl NameScope { }) } - fn extend_from(&mut self, other: &NameScope) { + fn insert_package_import(&mut self, import: &PackageImport) { + self.imports.push(Import { package: import.package.clone(), name: import.item.clone() }); + } + + fn extend_defs_from(&mut self, other: &NameScope) { for (ident, defs) in &other.types { for def_id in defs { self.insert_type(ident, *def_id); @@ -325,10 +384,136 @@ impl NameScope { self.insert_assertion(ident, *def_id); } } - self.imports.extend(other.imports.iter().copied()); } } +struct PackageExportSignatureBuilder<'a> { + db: &'a dyn HirDb, + package_id: PackageId, + scope: &'a mut NameScope, + next_declaration: u32, + next_decl: u32, + next_typedef: u32, + next_subroutine: u32, +} + +impl PackageExportSignatureBuilder<'_> { + fn collect(&mut self, package: ast::ModuleDeclaration<'_>) { + for member in package.members().children() { + use ast::Member::*; + match member { + DataDeclaration(decl) => self.record_declarators(decl.declarators()), + NetDeclaration(decl) => self.record_declarators(decl.declarators()), + ParameterDeclarationStatement(decl) => self.record_param_decl(decl.parameter()), + TypedefDeclaration(decl) => self.record_typedef(decl), + GenvarDeclaration(decl) => self.record_identifier_names(decl.identifiers()), + SpecparamDeclaration(decl) => self.record_specparam_declarators(decl.declarators()), + FunctionDeclaration(decl) => self.record_subroutine(decl), + _ => {} + } + } + } + + fn record_declarators<'a>(&mut self, declarators: ast::SeparatedList<'a, ast::Declarator<'a>>) { + let _declaration_id = self.next_declaration_id(); + for declarator in declarators.children() { + self.record_decl_name(lower_ident_opt(declarator.name())); + } + } + + fn record_specparam_declarators<'a>( + &mut self, + declarators: ast::SeparatedList<'a, ast::SpecparamDeclarator<'a>>, + ) { + let _declaration_id = self.next_declaration_id(); + for declarator in declarators.children() { + self.record_decl_name(lower_ident_opt(declarator.name())); + } + } + + fn record_identifier_names<'a>( + &mut self, + identifiers: ast::SeparatedList<'a, ast::IdentifierName<'a>>, + ) { + let _declaration_id = self.next_declaration_id(); + for ident in identifiers.children() { + self.record_decl_name(lower_ident_opt(ident.identifier())); + } + } + + fn record_param_decl(&mut self, param_decl: ast::ParameterDeclarationBase<'_>) { + match param_decl { + ast::ParameterDeclarationBase::ParameterDeclaration(decl) => { + self.record_declarators(decl.declarators()); + } + ast::ParameterDeclarationBase::TypeParameterDeclaration(_) => { + let _declaration_id = self.next_declaration_id(); + } + } + } + + fn record_decl_name(&mut self, name: Option) { + let decl_id = self.next_decl_id(); + self.scope.insert_value_opt( + &name, + def_id(self.db, InContainer::new(self.package_id.into(), decl_id)), + ); + } + + fn record_typedef(&mut self, typedef: ast::TypedefDeclaration<'_>) { + let typedef_id = self.next_typedef_id(); + let name = lower_ident_opt(typedef.name()); + self.scope.insert_type_opt( + &name, + def_id(self.db, InContainer::new(self.package_id.into(), typedef_id)), + ); + } + + fn record_subroutine(&mut self, subroutine: ast::FunctionDeclaration<'_>) { + let local_id = self.next_subroutine_id(); + let name = lower_name(subroutine.prototype().name()); + self.scope + .insert_value_opt(&name, def_id(self.db, InModule::new(self.package_id, local_id))); + } + + fn next_declaration_id(&mut self) -> DeclarationId { + let id = Idx::from_raw(RawIdx::from(self.next_declaration)); + self.next_declaration += 1; + id + } + + fn next_decl_id(&mut self) -> DeclId { + let id = Idx::from_raw(RawIdx::from(self.next_decl)); + self.next_decl += 1; + id + } + + fn next_typedef_id(&mut self) -> TypedefId { + let id = Idx::from_raw(RawIdx::from(self.next_typedef)); + self.next_typedef += 1; + id + } + + fn next_subroutine_id(&mut self) -> LocalSubroutineId { + let id = Idx::from_raw(RawIdx::from(self.next_subroutine)); + self.next_subroutine += 1; + id + } +} + +fn lower_name(name: ast::Name<'_>) -> Option { + if let Some(id) = name.as_identifier_name().and_then(|name| name.identifier()) { + return lower_ident_opt(Some(id)); + } + if let Some(select) = name.as_identifier_select_name() { + return select.identifier().and_then(|tok| lower_ident_opt(Some(tok))); + } + if let Some(scoped) = name.as_scoped_name() { + return lower_name(scoped.right()); + } + None +} + #[cfg(test)] mod tests { use std::fmt; @@ -350,9 +535,11 @@ mod tests { }, source_root::{SourceRoot, SourceRootId}, }, + container::ScopeId, db::{HirDb, HirDbStorage, InternDbStorage}, hir_def::Ident, - symbol::DefKind, + semantics::pathres::resolve_name, + symbol::{DefKind, NameContext}, }; const TOP: FileId = FileId(0); @@ -424,7 +611,7 @@ mod tests { } #[test] - fn name_scope_merged_lookup_covers_current_scope_shapes() { + fn name_scope_context_lookup_covers_current_scope_shapes() { let db = db_with_root_text( r#" typedef logic shared; @@ -453,16 +640,26 @@ endmodule let unit_scope = db.unit_scope(); assert!( unit_scope - .lookup_merged(&ident("file_sig")) + .lookup(NameContext::Value, &ident("file_sig")) .expect("file decl should be visible") .iter() .any(|def_id| def_id.kind(&db) == DefKind::Net) ); let shared_defs = unit_scope - .lookup_merged(&ident("shared")) - .expect("merged lookup should preserve same-name type and value definitions"); + .lookup(NameContext::Listing, &ident("shared")) + .expect("listing lookup should preserve same-name type and value definitions"); assert!(shared_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Typedef)); assert!(shared_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Net)); + let shared_type_defs = unit_scope + .lookup(NameContext::Type, &ident("shared")) + .expect("type lookup should see the typedef side of a collision"); + assert!(shared_type_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Typedef)); + assert!(!shared_type_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Net)); + let shared_value_defs = unit_scope + .lookup(NameContext::Value, &ident("shared")) + .expect("value lookup should see the net side of a collision"); + assert!(shared_value_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Net)); + assert!(!shared_value_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Typedef)); let module_id = unit_scope .module_ids(&db, &ident("m")) @@ -470,44 +667,45 @@ endmodule .expect("module should resolve uniquely"); let module_scope = db.module_scope(module_id); - let port_defs = - module_scope.lookup_merged(&ident("a")).expect("non-ANSI port name should resolve"); + let port_defs = module_scope + .lookup(NameContext::Value, &ident("a")) + .expect("non-ANSI port name should resolve"); assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::NonAnsiPort)); assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Port)); assert!(port_defs.iter().any(|def_id| def_id.kind(&db) == DefKind::Variable)); let subroutine_id = module_scope - .lookup_merged(&ident("f")) + .lookup(NameContext::Value, &ident("f")) .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_subroutine(&db))) .expect("subroutine should be visible from module scope"); let subroutine_scope = db.subroutine_scope(subroutine_id); assert!( subroutine_scope - .lookup_merged(&ident("p")) + .lookup(NameContext::Value, &ident("p")) .expect("subroutine port should be visible") .iter() .any(|def_id| def_id.kind(&db) == DefKind::SubroutinePort) ); let block_id = subroutine_scope - .lookup_merged(&ident("b")) + .lookup(NameContext::Value, &ident("b")) .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_block(&db))) .expect("named block should be visible from subroutine scope"); assert!( db.block_scope(block_id) - .lookup_merged(&ident("x")) + .lookup(NameContext::Value, &ident("x")) .expect("block local should be visible") .iter() .any(|def_id| def_id.kind(&db) == DefKind::Variable) ); let generate_block_id = module_scope - .lookup_merged(&ident("g")) + .lookup(NameContext::Value, &ident("g")) .and_then(|defs| defs.iter().find_map(|def_id| def_id.as_generate_block(&db))) .expect("generate block should be visible from module scope"); assert!( db.generate_block_scope(generate_block_id) - .lookup_merged(&ident("y")) + .lookup(NameContext::Value, &ident("y")) .expect("generate local should be visible") .iter() .any(|def_id| def_id.kind(&db) == DefKind::Net) @@ -517,4 +715,183 @@ endmodule // producer and insert the resulting DefId into NameScope; IDE // feature matches already have default no-op arms. } + + #[test] + fn package_imports_resolve_through_export_scope() { + let db = db_with_root_text( + r#" +package pkg; + typedef logic imported_t; + int imported_v; + int shadowed_v; + function int imported_f(); + return 1; + endfunction +endpackage + +module wildcard_importer; + import pkg::*; + wire shadowed_v; +endmodule + +module named_importer; + import pkg::imported_v; +endmodule +"#, + ); + + let unit_scope = db.unit_scope(); + let package_id = unit_scope + .package_ids(&db, &ident("pkg")) + .unique() + .expect("package should resolve uniquely"); + let package_exports = db.package_export_scope(package_id); + assert!( + package_exports + .lookup(NameContext::Type, &ident("imported_t")) + .expect("package export scope should expose package typedef") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Typedef) + ); + assert!( + package_exports + .lookup(NameContext::Value, &ident("imported_v")) + .expect("package export scope should expose package value") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Variable) + ); + assert!( + package_exports + .lookup(NameContext::Value, &ident("imported_f")) + .expect("package export scope should expose package subroutines") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Subroutine) + ); + + let wildcard_importer = db + .unit_scope() + .module_ids(&db, &ident("wildcard_importer")) + .unique() + .expect("wildcard importer should resolve uniquely"); + let wildcard_scope = db.module_scope(wildcard_importer); + assert!( + wildcard_scope + .imports + .iter() + .any(|import| import.package == ident("pkg") && import.name.is_none()) + ); + + let imported_t = resolve_name( + &db, + ScopeId::Module(wildcard_importer), + &ident("imported_t"), + NameContext::Type, + ) + .expect("wildcard import should expose package typedef"); + assert!(imported_t.def_ids().iter().any(|def_id| def_id.kind(&db) == DefKind::Typedef)); + assert!( + resolve_name( + &db, + ScopeId::Module(wildcard_importer), + &ident("imported_t"), + NameContext::Value, + ) + .is_none(), + "value lookup should not fall back to the type bucket" + ); + + let shadowed_v = resolve_name( + &db, + ScopeId::Module(wildcard_importer), + &ident("shadowed_v"), + NameContext::Value, + ) + .expect("local declaration should win before wildcard imports"); + assert!(shadowed_v.def_ids().iter().any(|def_id| def_id.kind(&db) == DefKind::Net)); + assert!(!shadowed_v.def_ids().iter().any(|def_id| def_id.kind(&db) == DefKind::Variable)); + + let named_importer = db + .unit_scope() + .module_ids(&db, &ident("named_importer")) + .unique() + .expect("named importer should resolve uniquely"); + let named_scope = db.module_scope(named_importer); + assert!(named_scope.imports.iter().any(|import| { + import.package == ident("pkg") + && import.name.as_ref().is_some_and(|name| name == "imported_v") + })); + + let imported_v = resolve_name( + &db, + ScopeId::Module(named_importer), + &ident("imported_v"), + NameContext::Value, + ) + .expect("named import should expose the selected package value"); + assert!(imported_v.def_ids().iter().any(|def_id| def_id.kind(&db) == DefKind::Variable)); + assert!( + resolve_name( + &db, + ScopeId::Module(named_importer), + &ident("imported_t"), + NameContext::Type, + ) + .is_none(), + "named import should not expose unrelated package symbols" + ); + } + + #[test] + fn package_export_signature_is_stable_across_function_body_edits() { + let mut db = db_with_root_text( + r#" +package pkg; + typedef logic exported_t; + int exported_v; + function int exported_f(); + int body_local; + return body_local; + endfunction +endpackage +"#, + ); + + let package_id = db + .unit_scope() + .package_ids(&db, &ident("pkg")) + .unique() + .expect("package should resolve uniquely"); + + let exports = db.package_export_scope(package_id); + assert!( + exports + .lookup(NameContext::Value, &ident("exported_f")) + .expect("signature should include package subroutine declarations") + .iter() + .any(|def_id| def_id.kind(&db) == DefKind::Subroutine) + ); + + let before_body_edit = db.package_export_signature(package_id); + db.set_file_text_with_durability( + TOP, + Arc::from( + r#" +package pkg; + typedef logic exported_t; + int exported_v; + function int exported_f(); + int changed_body_local; + return changed_body_local; + endfunction +endpackage +"#, + ), + Durability::LOW, + ); + let after_body_edit = db.package_export_signature(package_id); + assert_eq!( + before_body_edit, after_body_edit, + "function body edits should not change the package export signature" + ); + } } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 930e9722..1b5077d4 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -22,6 +22,7 @@ use crate::{ module::{ModuleId, ModuleSrc}, subroutine::{SubroutineId, SubroutineSrc}, }, + symbol::NameContext, }; mod hir_to_def; @@ -157,6 +158,6 @@ impl SemanticsImpl<'_> { } pub fn name_to_def(&self, in_cont: InContainer) -> Option { - self.with_ctx(|ctx| ctx.name_to_def(in_cont)) + self.with_ctx(|ctx| ctx.name_to_def(in_cont, NameContext::Value)) } } diff --git a/crates/hir/src/semantics/hir_to_def.rs b/crates/hir/src/semantics/hir_to_def.rs index 4eb7fc9a..6329ba3d 100644 --- a/crates/hir/src/semantics/hir_to_def.rs +++ b/crates/hir/src/semantics/hir_to_def.rs @@ -11,7 +11,7 @@ use crate::{ module::{ModuleId, generate::GenerateBlockId, instantiation::InstanceId}, }, semantics::pathres::{name_scope, resolve_name}, - symbol::DefLoc, + symbol::{DefLoc, NameContext}, }; #[derive(Default, Debug)] @@ -41,7 +41,8 @@ impl Source2DefCtx<'_, '_> { Some(res) } Expr::Ident(ident) => { - let res = self.name_to_def(InContainer::new(cont_id, ident.clone()))?; + let res = + self.name_to_def(InContainer::new(cont_id, ident.clone()), NameContext::Value)?; self.hir_cache.expr_map.insert(InContainer::new(cont_id, expr_id), res.clone()); Some(res) } @@ -75,8 +76,9 @@ impl Source2DefCtx<'_, '_> { pub(super) fn name_to_def( &mut self, InContainer { cont_id, value: ident }: InContainer, + name_ctx: NameContext, ) -> Option { - let res = resolve_name(self.db, cont_id, &ident)?; + let res = resolve_name(self.db, cont_id, &ident, name_ctx)?; self.hir_cache.name_map.insert(InContainer::new(cont_id, ident), res.clone()); Some(res) } @@ -124,7 +126,7 @@ impl Source2DefCtx<'_, '_> { field: &Ident, ) -> Option { name_scope(self.db, module_id.into()) - .lookup_merged(field) + .lookup(NameContext::Value, field) .and_then(PathResolution::from_def_ids) } @@ -134,7 +136,7 @@ impl Source2DefCtx<'_, '_> { field: &Ident, ) -> Option { name_scope(self.db, block_id.into()) - .lookup_merged(field) + .lookup(NameContext::Value, field) .and_then(PathResolution::from_def_ids) } @@ -144,7 +146,7 @@ impl Source2DefCtx<'_, '_> { field: &Ident, ) -> Option { name_scope(self.db, generate_block_id.into()) - .lookup_merged(field) + .lookup(NameContext::Value, field) .and_then(PathResolution::from_def_ids) } diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index 6826d59a..1bbde270 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -9,7 +9,7 @@ use crate::{ def_id::{ModuleDef, ModuleDefId}, file::HirFileId, hir_def::{Ident, lower_ident_opt}, - symbol::{DefId, NameScope}, + symbol::{DefId, NameContext, NameScope}, }; impl SemanticsImpl<'_> { @@ -17,11 +17,12 @@ impl SemanticsImpl<'_> { &self, file_id: HirFileId, SyntaxTokenWithParent { parent, tok }: SyntaxTokenWithParent, + name_ctx: NameContext, ) -> Option { let ident = lower_ident_opt(Some(tok))?; - self.with_ctx(|ctx| { - let container = ctx.find_container(InFile::new(file_id, parent)); - ctx.name_to_def(InContainer::new(container, ident)) + self.with_ctx(|source_ctx| { + let container = source_ctx.find_container(InFile::new(file_id, parent)); + source_ctx.name_to_def(InContainer::new(container, ident), name_ctx) }) } @@ -29,21 +30,45 @@ impl SemanticsImpl<'_> { self.with_ctx(|ctx| ctx.find_container(node)) } - pub fn resolve_name(&self, cont_id: ScopeId, ident: &Ident) -> Option { - resolve_name(self.db, cont_id, ident) + pub fn resolve_name( + &self, + cont_id: ScopeId, + ident: &Ident, + ctx: NameContext, + ) -> Option { + resolve_name(self.db, cont_id, ident, ctx) } } -pub fn resolve_name(db: &dyn HirDb, cont_id: ScopeId, ident: &Ident) -> Option { - ScopeParent::start_from(db, cont_id).find_map(|id| { - let scope = name_scope(db, id); - scope.lookup_merged(ident).and_then(PathResolution::from_def_ids) - }) +pub fn resolve_name( + db: &dyn HirDb, + cont_id: ScopeId, + ident: &Ident, + ctx: NameContext, +) -> Option { + let scopes = ScopeParent::start_from(db, cont_id).collect::>(); + + for id in &scopes { + let scope = name_scope(db, *id); + if let Some(res) = scope.lookup(ctx, ident).and_then(PathResolution::from_def_ids) { + return Some(res); + } + } + + // IEEE 1800-2017 keeps package imports distinct from ordinary lexical + // declarations: visible declarations in the lexical chain win, then + // package imports are considered, and `$unit` remains an explicit outer + // scope. `NameContext` chooses the namespace bucket at every phase. + if let Some(res) = resolve_imported_name(db, &scopes, ident, ctx) { + return Some(res); + } + + db.unit_scope().lookup(ctx, ident).and_then(PathResolution::from_def_ids) } pub(crate) fn name_scope(db: &dyn HirDb, scope_id: ScopeId) -> Arc { match scope_id { - ScopeId::File(_) => db.unit_scope(), + ScopeId::File(file_id) => db.file_scope(file_id), ScopeId::Module(module_id) => db.module_scope(module_id), ScopeId::GenerateBlock(generate_block_id) => db.generate_block_scope(generate_block_id), ScopeId::Block(block_id) => db.block_scope(block_id), @@ -51,6 +76,62 @@ pub(crate) fn name_scope(db: &dyn HirDb, scope_id: ScopeId) -> Arc { } } +fn resolve_imported_name( + db: &dyn HirDb, + scopes: &[ScopeId], + ident: &Ident, + ctx: NameContext, +) -> Option { + let mut defs = SmallVec::<[DefId; 3]>::new(); + + for scope_id in scopes { + let scope = name_scope(db, *scope_id); + collect_imports(db, &scope, ident, ctx, true, &mut defs); + if !defs.is_empty() { + return PathResolution::from_def_ids(defs); + } + } + + for scope_id in scopes { + let scope = name_scope(db, *scope_id); + collect_imports(db, &scope, ident, ctx, false, &mut defs); + if !defs.is_empty() { + return PathResolution::from_def_ids(defs); + } + } + + None +} + +fn collect_imports( + db: &dyn HirDb, + scope: &NameScope, + ident: &Ident, + ctx: NameContext, + named_only: bool, + defs: &mut SmallVec<[DefId; 3]>, +) { + for import in &scope.imports { + match (&import.name, named_only) { + (Some(name), true) if name == ident => {} + (None, false) => {} + _ => continue, + } + + let Some(package_id) = db.unit_scope().package_ids(db, &import.package).unique() else { + continue; + }; + let package_scope = db.package_export_scope(package_id); + if let Some(imported) = package_scope.lookup(ctx, ident) { + for def_id in imported { + if !defs.contains(&def_id) { + defs.push(def_id); + } + } + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PathResolution { def_ids: SmallVec<[DefId; 3]>, diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs index 75a5dfb9..d8a6e24d 100644 --- a/crates/hir/src/symbol.rs +++ b/crates/hir/src/symbol.rs @@ -5,7 +5,7 @@ use utils::impl_from; use crate::{ base_db::salsa, container::{InContainer, InFile, InModule, InSubroutine}, - db::InternDb, + db::{HirDb, InternDb}, hir_def::{ Ident, block::BlockId, @@ -15,7 +15,7 @@ use crate::{ ModuleId, generate::GenerateBlockId, instantiation::InstanceId, port::NonAnsiPortId, }, stmt::StmtId, - subroutine::{SubroutineId, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutineId, SubroutinePortId}, typedef::TypedefId, }, }; @@ -33,6 +33,7 @@ pub enum DefLoc { Block(BlockId), GenerateBlock(GenerateBlockId), Subroutine(SubroutineId), + PackageSubroutine(InModule), SubroutinePort(InSubroutine), NonAnsiPort(InModule), Decl(InContainer), @@ -49,6 +50,7 @@ impl_from! { DefLoc => Block(BlockId), GenerateBlock(GenerateBlockId), Subroutine(SubroutineId), + PackageSubroutine(InModule), SubroutinePort(InSubroutine), NonAnsiPort(InModule), Decl(InContainer), @@ -228,6 +230,20 @@ impl DefKind { DefKind::Stmt => SymbolKind::Stmt, } } + + pub fn name_context(self) -> NameContext { + match self { + DefKind::Module + | DefKind::Interface + | DefKind::Package + | DefKind::Program + | DefKind::Class + | DefKind::Typedef + | DefKind::Enum + | DefKind::Struct => NameContext::Type, + _ => NameContext::Value, + } + } } #[non_exhaustive] @@ -255,10 +271,17 @@ pub struct NameScope { pub imports: SmallVec<[Import; 2]>, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Import { - pub named: Option, - pub wildcard_pkg: Option, + pub package: Ident, + pub name: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum NameContext { + Type, + Value, + Listing, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -302,7 +325,15 @@ impl NameScope { Self::insert(&mut self.assertions, ident, def_id); } - pub fn lookup_merged(&self, ident: &Ident) -> Option> { + pub fn lookup(&self, ctx: NameContext, ident: &Ident) -> Option> { + match ctx { + NameContext::Type => self.types.get(ident).map(|defs| SmallVec::from_slice(defs)), + NameContext::Value => self.values.get(ident).map(|defs| SmallVec::from_slice(defs)), + NameContext::Listing => self.lookup_listing(ident), + } + } + + pub fn lookup_listing(&self, ident: &Ident) -> Option> { let mut defs = SmallVec::new(); if let Some(type_defs) = self.types.get(ident) { defs.extend_from_slice(type_defs); @@ -314,7 +345,7 @@ impl NameScope { (!defs.is_empty()).then_some(defs) } - pub fn iter_merged(&self) -> impl Iterator)> + '_ { + pub fn iter_listing(&self) -> impl Iterator)> + '_ { self.types .iter() .map(|(ident, type_defs)| { @@ -334,14 +365,15 @@ impl NameScope { pub fn module_ids( &self, - db: &dyn InternDb, + db: &dyn HirDb, ident: &Ident, ) -> NameResolution { let entries = self - .values + .types .get(ident) .into_iter() .flat_map(|defs| defs.iter()) + .filter(|def_id| def_id.kind(db) == DefKind::Module) .filter_map(|def_id| def_id.as_module(db)) .collect::>(); @@ -352,12 +384,32 @@ impl NameScope { } } - pub fn module_names<'a>( - &'a self, - db: &'a dyn InternDb, - ) -> impl Iterator + 'a { - self.values.iter().filter_map(move |(ident, defs)| { - defs.iter().any(|def_id| def_id.as_module(db).is_some()).then_some(ident) + pub fn package_ids( + &self, + db: &dyn HirDb, + ident: &Ident, + ) -> NameResolution { + let entries = self + .types + .get(ident) + .into_iter() + .flat_map(|defs| defs.iter()) + .filter(|def_id| def_id.kind(db) == DefKind::Package) + .filter_map(|def_id| def_id.as_module(db)) + .collect::>(); + + match entries.as_slice() { + [package_id] => NameResolution::Unique(*package_id), + [] => NameResolution::Unresolved, + _ => NameResolution::Ambiguous(entries), + } + } + + pub fn module_names<'a>(&'a self, db: &'a dyn HirDb) -> impl Iterator + 'a { + self.types.iter().filter_map(move |(ident, defs)| { + defs.iter() + .any(|def_id| def_id.kind(db) == DefKind::Module && def_id.as_module(db).is_some()) + .then_some(ident) }) } diff --git a/crates/hir/src/type_infer.rs b/crates/hir/src/type_infer.rs index 8cfca16a..cc95fad7 100644 --- a/crates/hir/src/type_infer.rs +++ b/crates/hir/src/type_infer.rs @@ -15,13 +15,13 @@ use crate::{ declarator::{DeclId, DeclaratorParent}, }, literal::Literal, - module::{ModuleId, generate::GenerateBlockId, port::PortDeclId}, + module::{ModuleId, ModuleKind, generate::GenerateBlockId, port::PortDeclId}, stmt::{ForInit, StmtKind}, subroutine::SubroutinePortId, typedef::TypedefId, }, semantics::pathres::{PathResolution, resolve_name}, - symbol::{DefId, DefKind}, + symbol::{DefId, DefKind, NameContext}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -132,7 +132,7 @@ fn type_of_path_resolution_impl(db: &dyn HirDb, res: PathResolution) -> TyResult fn type_of_def_id(db: &dyn HirDb, def_id: DefId) -> TyResult { match def_id.kind(db) { - DefKind::Module => def_id + DefKind::Module | DefKind::Package => def_id .as_module(db) .map(|module_id| TyResult::new(Ty::Module(module_id))) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), @@ -167,7 +167,6 @@ fn type_of_def_id(db: &dyn HirDb, def_id: DefId) -> TyResult { .map(|block_id| TyResult::new(Ty::Block(block_id))) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), DefKind::Interface - | DefKind::Package | DefKind::Program | DefKind::Class | DefKind::Covergroup @@ -193,7 +192,7 @@ fn type_of_expr_impl(db: &dyn HirDb, expr: InContainer) -> TyResult { }; match hir_expr { - Expr::Ident(ident) => resolve_name(db, expr.cont_id, &ident) + Expr::Ident(ident) => resolve_name(db, expr.cont_id, &ident, NameContext::Value) .map(|res| type_of_path_resolution_impl(db, res)) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), Expr::Field { receiver, field } => { @@ -345,7 +344,7 @@ fn type_of_named_data_ty( return TyResult::new(Ty::Unknown); }; - match resolve_name(db, container, &ident) { + match resolve_name(db, container, &ident, NameContext::Type) { Some(res) => { for def_id in res.def_ids() { if let Some(typedef) = def_id.as_typedef(db) { @@ -408,9 +407,15 @@ fn struct_members(db: &dyn HirDb, struct_id: InContainer) -> Vec Vec { - let mut members: Vec<_> = db - .module_scope(module_id) - .iter_merged() + let file = db.hir_file(crate::file::HirFileId::File(module_id.file_id())); + let scope = if file.get(module_id.value).kind == ModuleKind::Package { + db.package_export_scope(module_id) + } else { + db.module_scope(module_id) + }; + + let mut members: Vec<_> = scope + .iter_listing() .filter_map(|(name, defs)| { let origin = PathResolution::from_def_ids(defs)?; let ty = type_of_path_resolution_impl(db, origin.clone()).ty; @@ -424,7 +429,7 @@ fn module_members(db: &dyn HirDb, module_id: ModuleId) -> Vec { fn generate_block_members(db: &dyn HirDb, generate_block_id: GenerateBlockId) -> Vec { let mut members: Vec<_> = db .generate_block_scope(generate_block_id) - .iter_merged() + .iter_listing() .filter_map(|(name, defs)| { let origin = PathResolution::from_def_ids(defs)?; let ty = type_of_path_resolution_impl(db, origin.clone()).ty; @@ -438,7 +443,7 @@ fn generate_block_members(db: &dyn HirDb, generate_block_id: GenerateBlockId) -> fn block_members(db: &dyn HirDb, block_id: crate::hir_def::block::BlockId) -> Vec { let mut members: Vec<_> = db .block_scope(block_id) - .iter_merged() + .iter_listing() .filter_map(|(name, defs)| { let origin = PathResolution::from_def_ids(defs)?; let ty = type_of_path_resolution_impl(db, origin.clone()).ty; diff --git a/crates/ide/src/code_action/handlers/convert_port_declarations.rs b/crates/ide/src/code_action/handlers/convert_port_declarations.rs index 209b29b5..76a50125 100644 --- a/crates/ide/src/code_action/handlers/convert_port_declarations.rs +++ b/crates/ide/src/code_action/handlers/convert_port_declarations.rs @@ -15,7 +15,7 @@ use hir::{ }, }, source_map::IsSrc, - symbol::{DefKind, NameScope}, + symbol::{DefKind, NameContext, NameScope}, }; use itertools::Itertools; use syntax::{ @@ -220,7 +220,7 @@ fn non_ansi_port_replacement( name: &Ident, text: &str, ) -> Option { - let defs = module_scope.lookup_merged(name)?; + let defs = module_scope.lookup(NameContext::Value, name)?; if !defs.iter().any(|def_id| def_id.kind(ctx.sema().db) == DefKind::NonAnsiPort) { return None; } diff --git a/crates/ide/src/completion/engine/expr.rs b/crates/ide/src/completion/engine/expr.rs index 2a253ba1..470e7b72 100644 --- a/crates/ide/src/completion/engine/expr.rs +++ b/crates/ide/src/completion/engine/expr.rs @@ -115,19 +115,19 @@ fn collect_container_names( ScopeId::Module(module_id) => collect_module_names(db, module_id, names), ScopeId::GenerateBlock(generate_block_id) => { let scope = db.generate_block_scope(generate_block_id); - for (ident, defs) in scope.iter_merged() { + for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } } ScopeId::Block(block_id) => { let scope = db.block_scope(block_id); - for (ident, defs) in scope.iter_merged() { + for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } } ScopeId::Subroutine(subroutine_id) => { let scope = db.subroutine_scope(subroutine_id); - for (ident, defs) in scope.iter_merged() { + for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } } @@ -136,14 +136,14 @@ fn collect_container_names( fn collect_file_names(db: &RootDb, file_id: HirFileId, names: &mut BTreeMap) { let scope = db.file_scope(file_id); - for (ident, defs) in scope.iter_merged() { + for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } } fn collect_module_names(db: &RootDb, module_id: ModuleId, names: &mut BTreeMap) { let scope = db.module_scope(module_id); - for (ident, defs) in scope.iter_merged() { + for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } } diff --git a/crates/ide/src/completion/engine/member.rs b/crates/ide/src/completion/engine/member.rs index ecc34164..6f356c6e 100644 --- a/crates/ide/src/completion/engine/member.rs +++ b/crates/ide/src/completion/engine/member.rs @@ -2,10 +2,11 @@ use hir::{ db::HirDb, file::HirFileId, semantics::Semantics, + symbol::NameContext, type_infer::{TyMember, members_of_ty}, }; use syntax::{ - SyntaxAncestors, SyntaxNode, SyntaxNodeExt, + SyntaxAncestors, SyntaxNode, SyntaxNodeExt, SyntaxTokenWithParent, ast::{self, AstNode}, has_text_range::HasTextRange, }; @@ -84,7 +85,7 @@ fn members_for_incomplete_scoped_access( return None; } let left = root.token_before_offset(separator.text_range()?.start())?; - let res = sema.nameres_ident(file_id, left)?; + let res = sema.nameres_ident(file_id, left, NameContext::Type)?; let ty = db.type_of_path_resolution(res); let members = members_of_ty(db, &ty.ty); (!members.is_empty()).then_some(members) @@ -136,6 +137,26 @@ fn members_for_scoped_name( file_id: HirFileId, scoped: ast::ScopedName<'_>, ) -> Option> { + if let Some(left) = scoped_left_token(scoped) { + let res = sema.nameres_ident(file_id, left, NameContext::Type)?; + let ty = db.type_of_path_resolution(res); + let members = members_of_ty(db, &ty.ty); + return (!members.is_empty()).then_some(members); + } + let left = ast::Expression::cast(scoped.left().syntax())?; members_for_expr(db, sema, file_id, left) } + +fn scoped_left_token(scoped: ast::ScopedName<'_>) -> Option> { + use ast::Name::*; + match scoped.left() { + IdentifierName(ident) => { + Some(SyntaxTokenWithParent { parent: ident.syntax(), tok: ident.identifier()? }) + } + IdentifierSelectName(ident) => { + Some(SyntaxTokenWithParent { parent: ident.syntax(), tok: ident.identifier()? }) + } + _ => None, + } +} diff --git a/crates/ide/src/completion/engine/port_list.rs b/crates/ide/src/completion/engine/port_list.rs index 544757c7..42d09bfb 100644 --- a/crates/ide/src/completion/engine/port_list.rs +++ b/crates/ide/src/completion/engine/port_list.rs @@ -105,7 +105,7 @@ fn complete_non_ansi_port_list( let scope = db.module_scope(module_id); scope - .iter_merged() + .iter_listing() .filter_map(|(ident, defs)| { defs.iter() .any(|def_id| matches!(def_id.kind(db), DefKind::Port | DefKind::NonAnsiPort)) diff --git a/crates/ide/src/completion/engine/typed_filter.rs b/crates/ide/src/completion/engine/typed_filter.rs index b3109d4f..e9bb8e69 100644 --- a/crates/ide/src/completion/engine/typed_filter.rs +++ b/crates/ide/src/completion/engine/typed_filter.rs @@ -8,7 +8,7 @@ use hir::{ module::{ModuleId, port::Ports}, }, semantics::pathres::PathResolution, - symbol::DefKind, + symbol::{DefKind, NameContext}, type_infer::{Ty, TyClass, packed_bit_width, type_class}, }; use utils::get::GetRef; @@ -21,7 +21,7 @@ pub(super) fn expected_port_ty( port_name: &Ident, ) -> Option { let scope = db.module_scope(target_module_id); - let defs = scope.lookup_merged(port_name)?; + let defs = scope.lookup(NameContext::Value, port_name)?; let res = if defs.iter().any(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) { PathResolution::from_def_ids(defs)? } else { @@ -39,7 +39,7 @@ pub(super) fn expected_param_ty( ) -> Option { let target_module = db.module(target_module_id); let scope = db.module_scope(target_module_id); - let defs = scope.lookup_merged(param_name)?; + let defs = scope.lookup(NameContext::Value, param_name)?; for def_id in defs { if def_id.kind(db) != DefKind::Param { diff --git a/crates/ide/src/definitions.rs b/crates/ide/src/definitions.rs index e93e3ccc..b1989ffe 100644 --- a/crates/ide/src/definitions.rs +++ b/crates/ide/src/definitions.rs @@ -2,7 +2,7 @@ use hir::{ def_id::ModuleDefId, file::HirFileId, semantics::{Semantics, pathres::PathResolution}, - symbol::DefId, + symbol::{DefId, NameContext}, }; use smallvec::SmallVec; use syntax::{ @@ -66,7 +66,9 @@ impl DefinitionClass { .and_then(|res| res.to_def_id(sema.db)); if it.open_paren().is_none() && it.close_paren().is_none() { - let local = sema.nameres_ident(file_id, tp).and_then(|res| res.to_def_id(sema.db)); + let local = sema + .nameres_ident(file_id, tp, NameContext::Value) + .and_then(|res| res.to_def_id(sema.db)); match (port, local) { (Some(port), Some(local)) => Self::PortConnShorthand { port, local }, @@ -77,7 +79,10 @@ impl DefinitionClass { port?.into() } }, - _ => sema.nameres_ident(file_id, tp)?.to_def_id(sema.db)?.into(), + _ => sema + .nameres_ident(file_id, tp, name_context_for_token(parent)) + ?.to_def_id(sema.db)? + .into(), }; Some(res) @@ -171,12 +176,25 @@ fn resolve_instantiation_type_name( SyntaxAncestors::start_from(parent).find_map(ast::PrimitiveInstantiation::cast) && instantiation.type_() == Some(tok) { - return Some(sema.nameres_ident(file_id, tp)?.to_def_id(sema.db)?.into()); + return Some( + sema.nameres_ident(file_id, tp, NameContext::Value)?.to_def_id(sema.db)?.into(), + ); } None } +fn name_context_for_token(parent: syntax::SyntaxNode<'_>) -> NameContext { + if SyntaxAncestors::start_from(parent).any(|node| ast::NamedType::cast(node).is_some()) { + NameContext::Type + } else { + // Value is the conservative default for identifier references in IDE + // features; type positions are selected by the syntactic NamedType arm + // above. + NameContext::Value + } +} + fn scoped_right_token(scoped: ast::ScopedName<'_>) -> Option> { use ast::Name::*; match scoped.right() { diff --git a/crates/ide/src/inlay_hint.rs b/crates/ide/src/inlay_hint.rs index 065337fb..79ad0d4e 100644 --- a/crates/ide/src/inlay_hint.rs +++ b/crates/ide/src/inlay_hint.rs @@ -17,7 +17,7 @@ use hir::{ }, preproc::{MacroCallResolution, macro_call_resolutions_in_range}, source_map::{IsNamedSrc, IsSrc}, - symbol::{DefKind, NameScope}, + symbol::{DefKind, NameContext, NameScope}, }; use syntax::{ast, match_ast_kind}; use utils::{ @@ -490,7 +490,7 @@ fn non_ansi_port_id_for_conn<'a>( Some((port_id, name, dir)) } PortConn::Named(Some(name), _) => { - let defs = scope.lookup_merged(name)?; + let defs = scope.lookup(NameContext::Value, name)?; let port_id = defs .iter() .find(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) @@ -542,7 +542,7 @@ fn ansi_port_decl_id_for_conn( Some((port_decl_id, decl_id)) } PortConn::Named(Some(name), _) => { - let defs = scope.lookup_merged(name)?; + let defs = scope.lookup(NameContext::Value, name)?; let decl_id = defs .iter() .filter(|def_id| def_id.kind(db) == DefKind::Port) diff --git a/crates/ide/src/module_resolution.rs b/crates/ide/src/module_resolution.rs index eb786085..86dc8b27 100644 --- a/crates/ide/src/module_resolution.rs +++ b/crates/ide/src/module_resolution.rs @@ -15,7 +15,7 @@ use hir::{ module::{ModuleId, instantiation::Instantiation}, }, semantics::pathres::PathResolution, - symbol::DefKind, + symbol::{DefKind, NameContext}, }; use syntax::{ SyntaxAncestors, @@ -125,7 +125,7 @@ fn resolve_named_port_in_module( module_id: ModuleId, port_name: &Ident, ) -> Option { - let defs = db.module_scope(module_id).lookup_merged(port_name)?; + let defs = db.module_scope(module_id).lookup(NameContext::Value, port_name)?; if defs.iter().any(|def_id| def_id.kind(db) == DefKind::NonAnsiPort) { PathResolution::from_def_ids(defs) } else { @@ -140,7 +140,7 @@ fn resolve_named_param_in_module( module_id: ModuleId, param_name: &Ident, ) -> Option { - let defs = db.module_scope(module_id).lookup_merged(param_name)?; + let defs = db.module_scope(module_id).lookup(NameContext::Value, param_name)?; let module = db.module(module_id); for def_id in defs { diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 661955e3..2210ee0b 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -1,6 +1,9 @@ use hir::{ - base_db::source_db::SourceDb, container::InFile, def_id::ModuleDefId, semantics::Semantics, - symbol::DefId, + base_db::source_db::SourceDb, + container::InFile, + def_id::ModuleDefId, + semantics::Semantics, + symbol::{DefId, NameContext}, }; use nohash_hasher::IntMap; use rustc_hash::FxHashMap; @@ -192,7 +195,8 @@ pub(crate) fn rename_conflict_info( } let mut conflicts = UniqVec::::default(); for collision in targets.iter().flat_map(|target| target.origins(db)).filter_map(|origin| { - sema.resolve_name(origin.container_id(db), &new_name).and_then(|res| res.to_def_id(db)) + sema.resolve_name(origin.container_id(db), &new_name, origin.kind(db).name_context()) + .and_then(|res| res.to_def_id(db)) }) { if collision.origins(db).iter().any(|origin| target_index.contains(origin)) { continue; @@ -466,7 +470,7 @@ fn check_same_name_conn( let collapse_end = close_paren.text_range_in(conn.syntax())?.end(); Some(SameNameConnection { port, - local: sema.nameres_ident(file_id, actual_token)?.to_def_id(sema.db)?, + local: sema.nameres_ident(file_id, actual_token, NameContext::Value)?.to_def_id(sema.db)?, collapse_range: TextRange::new(name_range.start(), collapse_end), }) } diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index 668f086c..23d583e7 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -20,7 +20,7 @@ use hir::{ instantiation::InstanceId, port::{NonAnsiPortId, Ports}, }, - subroutine::{SubroutineId, SubroutineKind, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutineId, SubroutineKind, SubroutinePortId}, }, region_tree::RegionParent, semantics::Semantics, @@ -297,6 +297,12 @@ fn render_definition_title(db: &RootDb, origin: &DefId) -> Option { SubroutineKind::Task => "Task", SubroutineKind::Function { .. } => "Function", }, + DefLoc::PackageSubroutine(subroutine_id) => { + match db.module(subroutine_id.module_id).get(subroutine_id.value).kind { + SubroutineKind::Task => "Task", + SubroutineKind::Function { .. } => "Function", + } + } DefLoc::SubroutinePort(_) | DefLoc::NonAnsiPort(_) => "Port", DefLoc::Decl(decl_id) => render_decl_title_kind(db, decl_id)?, DefLoc::Typedef(_) => "Typedef", @@ -332,6 +338,9 @@ fn render_signature(sema: &Semantics, origin: &DefId) -> Option match origin.loc(db) { DefLoc::Module(module_id) => render_module_signature(db, module_id), DefLoc::Subroutine(subroutine_id) => render_subroutine_signature(db, subroutine_id), + DefLoc::PackageSubroutine(subroutine_id) => { + render_package_subroutine_signature(db, subroutine_id) + } DefLoc::SubroutinePort(port_id) => render_subroutine_port_signature(db, port_id), DefLoc::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, port_id), DefLoc::Decl(decl_id) => render_decl_signature(db, decl_id), @@ -447,6 +456,51 @@ fn render_subroutine_signature(db: &RootDb, subroutine_id: SubroutineId) -> Opti Some(signature) } +fn render_package_subroutine_signature( + db: &RootDb, + subroutine_id: InModule, +) -> Option { + let subroutine = db.module(subroutine_id.module_id); + let subroutine = subroutine.get(subroutine_id.value); + let name = subroutine.name.as_ref()?; + let container = subroutine_id.module_id.into(); + let mut signature = match subroutine.kind { + SubroutineKind::Task => format!("task {name}"), + SubroutineKind::Function { return_ty } => { + if let Some(return_ty) = return_ty.and_then(|ty| render_data_ty(db, container, ty)) { + format!("function {return_ty} {name}") + } else { + format!("function {name}") + } + } + }; + + let ports = subroutine + .ports + .iter() + .filter_map(|port| { + let name = port.name.as_ref()?; + let ty = port.ty.and_then(|ty| render_data_ty(db, container, ty)); + let dir = port.direction.display_source(db).ok()?; + + match (dir.is_empty(), ty) { + (false, Some(ty)) => Some(format!("{dir} {ty} {name}")), + (false, None) => Some(format!("{dir} {name}")), + (true, Some(ty)) => Some(format!("{ty} {name}")), + (true, None) => Some(name.to_string()), + } + }) + .collect_vec(); + if ports.is_empty() { + signature.push_str("()"); + } else { + signature.push('('); + signature.push_str(&ports.join(", ")); + signature.push(')'); + } + Some(signature) +} + fn render_module_port_list(db: &RootDb, module_id: ModuleId) -> Vec { let module = db.module(module_id); match &module.ports { @@ -632,6 +686,7 @@ fn render_label_signature(db: &RootDb, origin: &DefId) -> Option { DefLoc::Typedef(_) => "typedef", DefLoc::Module(_) | DefLoc::Subroutine(_) + | DefLoc::PackageSubroutine(_) | DefLoc::SubroutinePort(_) | DefLoc::NonAnsiPort(_) | DefLoc::Decl(_) => return None, diff --git a/crates/ide/src/semantic_index.rs b/crates/ide/src/semantic_index.rs index 21f3a0a9..c7322f54 100644 --- a/crates/ide/src/semantic_index.rs +++ b/crates/ide/src/semantic_index.rs @@ -117,7 +117,7 @@ impl ModuleIndex { for file_id in source_root.iter() { let hir_file_id = HirFileId::from(file_id); - for (_, defs) in db.file_scope(hir_file_id).iter_merged() { + for (_, defs) in db.file_scope(hir_file_id).iter_listing() { for module_id in defs .iter() .filter(|def_id| def_id.kind(db) == DefKind::Module) diff --git a/crates/ide/src/semantic_tokens.rs b/crates/ide/src/semantic_tokens.rs index 03331b8f..8374d5ea 100644 --- a/crates/ide/src/semantic_tokens.rs +++ b/crates/ide/src/semantic_tokens.rs @@ -7,7 +7,11 @@ use hir::{ hir_def::{ Ident, block::{BlockId, BlockInfo}, - expr::{Expr, declarator::DeclaratorParent}, + expr::{ + Expr, ExprId, + data_ty::{DataTy, NamedDataTy}, + declarator::DeclaratorParent, + }, module::{ ModuleId, instantiation::{ParamAssign, PortConn}, @@ -17,8 +21,9 @@ use hir::{ preproc::macro_references_in_range, semantics::{Semantics, pathres::PathResolution}, source_map::{IsNamedSrc, IsSrc, ToAstNode}, - symbol::{DefKind, DefLoc}, + symbol::{DefKind, DefLoc, NameContext}, }; +use rustc_hash::FxHashSet; use smol_str::SmolStr; use syntax::{ast, has_text_range::HasTextRange}; use utils::{ @@ -197,7 +202,35 @@ fn collect_file( collect_ident_like(sema, name_in_cont, range, collector); }; + let mut type_expr_ids = FxHashSet::default(); + for (_, declaration) in hir_file.declarations.iter() { + if let Some(expr_id) = named_data_ty_expr_id(declaration.ty()) { + type_expr_ids.insert(expr_id); + let Some(range) = file_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, file_id.into(), hir_file.get(expr_id), range, collector); + } + } + for (_, typedef) in hir_file.typedefs.iter() { + let Some(ty) = typedef.ty else { + continue; + }; + if let Some(expr_id) = named_data_ty_expr_id(ty) { + type_expr_ids.insert(expr_id); + let Some(range) = file_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, file_id.into(), hir_file.get(expr_id), range, collector); + } + } + for (expr_id, expr) in hir_file.exprs.iter() { + if type_expr_ids.contains(&expr_id) { + continue; + } match expr { Expr::Field { .. } => {} Expr::Ident(name) => { @@ -260,6 +293,31 @@ fn collect_module( collect_ident_like(sema, name_in_cont, range, collector); }; + let mut type_expr_ids = FxHashSet::default(); + for (_, declaration) in module.declarations.iter() { + if let Some(expr_id) = named_data_ty_expr_id(declaration.ty()) { + type_expr_ids.insert(expr_id); + let Some(range) = module_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, module_id.into(), module.get(expr_id), range, collector); + } + } + for (_, typedef) in module.typedefs.iter() { + let Some(ty) = typedef.ty else { + continue; + }; + if let Some(expr_id) = named_data_ty_expr_id(ty) { + type_expr_ids.insert(expr_id); + let Some(range) = module_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, module_id.into(), module.get(expr_id), range, collector); + } + } + for (instance_id, _) in module.instances.iter() { if let Some(range) = module_src_map.get(instance_id).and_then(|src| src.name_range()) { check_range!(collector, range); @@ -273,6 +331,9 @@ fn collect_module( collect_named_port_connections(sema, module_id, collector); for (expr_id, expr) in module.exprs.iter() { + if type_expr_ids.contains(&expr_id) { + continue; + } match expr { Expr::Field { .. } => {} Expr::Ident(name) => { @@ -334,7 +395,35 @@ fn collect_block( collect_ident_like(sema, name_in_cont, range, collector); }; + let mut type_expr_ids = FxHashSet::default(); + for (_, declaration) in block.declarations.iter() { + if let Some(expr_id) = named_data_ty_expr_id(declaration.ty()) { + type_expr_ids.insert(expr_id); + let Some(range) = block_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, block_id.into(), block.get(expr_id), range, collector); + } + } + for (_, typedef) in block.typedefs.iter() { + let Some(ty) = typedef.ty else { + continue; + }; + if let Some(expr_id) = named_data_ty_expr_id(ty) { + type_expr_ids.insert(expr_id); + let Some(range) = block_src_map.get(expr_id).map(|src| src.range()) else { + continue; + }; + check_range!(collector, range); + collect_type_ident_like(sema, block_id.into(), block.get(expr_id), range, collector); + } + } + for (expr_id, expr) in block.exprs.iter() { + if type_expr_ids.contains(&expr_id) { + continue; + } match expr { Expr::Field { .. } => {} Expr::Ident(name) => { @@ -453,10 +542,31 @@ fn collect_ident_like( range: TextRange, collector: &mut SemaTokenCollector, ) -> Option<()> { - let res = sema.name_to_def(in_cont)?; + let res = sema.resolve_name(in_cont.cont_id, &in_cont.value, NameContext::Value)?; + collect_resolved_path(sema, res, range, collector) +} + +fn collect_type_ident_like( + sema: &Semantics<'_, RootDb>, + cont_id: ScopeId, + expr: &Expr, + range: TextRange, + collector: &mut SemaTokenCollector, +) -> Option<()> { + let Expr::Ident(name) = expr else { + return None; + }; + let res = sema.resolve_name(cont_id, name, NameContext::Type)?; collect_resolved_path(sema, res, range, collector) } +fn named_data_ty_expr_id(ty: DataTy) -> Option { + match ty { + DataTy::Named(NamedDataTy::Ident(expr_id) | NamedDataTy::Field(expr_id)) => Some(expr_id), + DataTy::Builtin(_) | DataTy::Struct(_) => None, + } +} + fn collect_resolved_path( sema: &Semantics<'_, RootDb>, res: PathResolution, diff --git a/crates/ide/src/semantic_tokens/port.rs b/crates/ide/src/semantic_tokens/port.rs index f75041e1..9ae87d11 100644 --- a/crates/ide/src/semantic_tokens/port.rs +++ b/crates/ide/src/semantic_tokens/port.rs @@ -15,7 +15,7 @@ use hir::{ }, semantics::Semantics, source_map::{IsNamedSrc, IsSrc}, - symbol::DefId, + symbol::{DefId, NameContext}, }; use regex::{Regex, RegexBuilder}; use smallvec::SmallVec; @@ -61,7 +61,7 @@ pub(super) fn collect_port( check_range!(collector, name_range); let name = module.get(ref_id).ident.as_ref()?; - let defs = module_scope.lookup_merged(name)?; + let defs = module_scope.lookup(NameContext::Value, name)?; let (_, dir, ty) = resolve_non_ansi_port(db, module, &defs)?; add_port_token(db, name, dir, ty, name_range, collector); }; @@ -80,7 +80,7 @@ pub(super) fn collect_port( check_range!(collector, name_range); let name = decl.name.as_ref()?; - let defs = module_scope.lookup_merged(name)?; + let defs = module_scope.lookup(NameContext::Value, name)?; let (_, dir, ty) = resolve_non_ansi_port(db, module, &defs)?; add_port_token(db, name, dir, ty, name_range, collector); }; From e9c4179a678737189a39d67f99cf219794dc8c3c Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 04:58:07 +0800 Subject: [PATCH 6/7] refactor(hir): use container handles for subroutines (cherry picked from commit ef79372af8be9a6818796fc0ab57ce1e1fa4df98) --- crates/hir/src/container.rs | 94 ++++++++++++++++--- crates/hir/src/db.rs | 14 +-- crates/hir/src/def_id.rs | 50 +++++----- crates/hir/src/hir_def/file.rs | 15 +-- crates/hir/src/hir_def/module.rs | 13 +-- crates/hir/src/hir_def/module/generate.rs | 11 +-- crates/hir/src/hir_def/subroutine.rs | 87 +++--------------- crates/hir/src/scope.rs | 107 +++++++++++++++++----- crates/hir/src/semantics.rs | 4 +- crates/hir/src/semantics/hir_to_def.rs | 2 +- crates/hir/src/semantics/pathres.rs | 2 +- crates/hir/src/semantics/source_to_def.rs | 30 +++--- crates/hir/src/symbol.rs | 10 +- crates/hir/src/type_infer.rs | 14 +-- crates/ide/src/completion/engine/expr.rs | 8 +- crates/ide/src/navigation_target.rs | 49 ++-------- crates/ide/src/references/search.rs | 9 +- crates/ide/src/render.rs | 71 ++------------ 18 files changed, 277 insertions(+), 313 deletions(-) diff --git a/crates/hir/src/container.rs b/crates/hir/src/container.rs index 875ad21b..c5d4c825 100644 --- a/crates/hir/src/container.rs +++ b/crates/hir/src/container.rs @@ -23,7 +23,7 @@ use crate::{ generate::{GenerateBlock, GenerateBlockId, GenerateBlockSourceMap}, }, stmt::{Stmt, StmtId, StmtSrc}, - subroutine::{Subroutine, SubroutineId, SubroutineSourceMap}, + subroutine::{LocalSubroutineId, Subroutine, SubroutineSourceMap}, typedef::{Typedef, TypedefId, TypedefSrc}, }, region_tree::RegionTree, @@ -37,7 +37,79 @@ define_enum_deriving_from! { Module(ModuleId), GenerateBlock(GenerateBlockId), Block(BlockId), - Subroutine(SubroutineId), + Subroutine(SubroutineScope), + } +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub struct SubroutineScope { + pub cont_id: SubroutineParent, + pub value: LocalSubroutineId, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub enum SubroutineParent { + File(HirFileId), + Module(ModuleId), + GenerateBlock(GenerateBlockId), +} + +impl SubroutineScope { + pub fn new(cont_id: SubroutineParent, value: LocalSubroutineId) -> Self { + Self { cont_id, value } + } + + pub fn parent_scope(self) -> ScopeId { + self.cont_id.into() + } + + pub fn as_in_container(self) -> InContainer { + InContainer::new(self.parent_scope(), self.value) + } + + pub fn file_id(self, db: &dyn InternDb) -> FileId { + match self.cont_id { + SubroutineParent::File(file_id) => file_id.file_id(), + SubroutineParent::Module(module_id) => module_id.file_id(), + SubroutineParent::GenerateBlock(generate_block_id) => generate_block_id.file_id(db), + } + } +} + +impl From for ScopeId { + fn from(cont_id: SubroutineParent) -> Self { + match cont_id { + SubroutineParent::File(file_id) => file_id.into(), + SubroutineParent::Module(module_id) => module_id.into(), + SubroutineParent::GenerateBlock(generate_block_id) => generate_block_id.into(), + } + } +} + +impl TryFrom for SubroutineParent { + type Error = (); + + fn try_from(cont_id: ScopeId) -> Result { + match cont_id { + ScopeId::File(file_id) => Ok(Self::File(file_id)), + ScopeId::Module(module_id) => Ok(Self::Module(module_id)), + ScopeId::GenerateBlock(generate_block_id) => Ok(Self::GenerateBlock(generate_block_id)), + ScopeId::Block(_) | ScopeId::Subroutine(_) => Err(()), + } + } +} + +impl From> for SubroutineScope { + fn from(subroutine: InContainer) -> Self { + let parent = SubroutineParent::try_from(subroutine.cont_id) + .expect("subroutines are lowered only in file, module, or generate-block scopes"); + Self::new(parent, subroutine.value) + } +} + +impl From> for ScopeId { + fn from(subroutine: InContainer) -> Self { + ScopeId::Subroutine(subroutine.into()) } } @@ -64,11 +136,11 @@ impl InContainer { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub struct InSubroutine { pub value: T, - pub subroutine: SubroutineId, + pub subroutine: InContainer, } impl InSubroutine { - pub fn new(subroutine: SubroutineId, value: T) -> Self { + pub fn new(subroutine: InContainer, value: T) -> Self { Self { value, subroutine } } @@ -79,7 +151,7 @@ impl InSubroutine { impl From> for InContainer { fn from(item: InSubroutine) -> InContainer { - InContainer::new(ScopeId::Subroutine(item.subroutine), item.value) + InContainer::new(item.subroutine.into(), item.value) } } @@ -139,7 +211,7 @@ impl ScopeId { ScopeId::Module(module_id) => module_id.file_id(), ScopeId::GenerateBlock(generate_block_id) => generate_block_id.file_id(db), ScopeId::Block(block_id) => block_id.file_id(db), - ScopeId::Subroutine(subroutine_id) => subroutine_id.lookup(db).src.file_id.file_id(), + ScopeId::Subroutine(subroutine) => subroutine.file_id(db), } } @@ -149,7 +221,7 @@ impl ScopeId { ScopeId::Module(module_id) => module_id.to_container(db).into(), ScopeId::GenerateBlock(generate_block_id) => generate_block_id.to_container(db).into(), ScopeId::Block(block_id) => block_id.to_container(db).into(), - ScopeId::Subroutine(subroutine_id) => db.subroutine(subroutine_id).into(), + ScopeId::Subroutine(subroutine) => db.subroutine(subroutine.as_in_container()).into(), } } @@ -161,8 +233,8 @@ impl ScopeId { generate_block_id.to_container_src_map(db).into() } ScopeId::Block(block_id) => block_id.to_container_src_map(db).into(), - ScopeId::Subroutine(subroutine_id) => { - db.subroutine_with_source_map(subroutine_id).1.into() + ScopeId::Subroutine(subroutine) => { + db.subroutine_with_source_map(subroutine.as_in_container()).1.into() } } } @@ -312,9 +384,7 @@ impl Iterator for ScopeParent<'_> { Some(generate_block_id.lookup(self.db).cont_id) } ScopeId::Block(block_id) => Some(block_id.lookup(self.db).cont_id), - ScopeId::Subroutine(subroutine_id) => { - Some(subroutine_id.lookup(self.db).cont_id.into()) - } + ScopeId::Subroutine(subroutine) => Some(subroutine.parent_scope()), }; next } diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 5babbe7e..df785bf9 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -22,7 +22,7 @@ use crate::{ }, }, subroutine::{ - self, Subroutine, SubroutineId, SubroutineLoc, SubroutinePortId, SubroutineSourceMap, + self, LocalSubroutineId, Subroutine, SubroutinePortId, SubroutineSourceMap, }, typedef::TypedefId, }, @@ -45,9 +45,6 @@ pub trait InternDb: SourceRootDb { #[salsa::interned] fn intern_block(&self, block: BlockLoc) -> BlockId; - #[salsa::interned] - fn intern_subroutine(&self, subroutine: SubroutineLoc) -> SubroutineId; - #[salsa::interned] fn intern_generate_block(&self, generate_block: GenerateBlockLoc) -> GenerateBlockId; @@ -66,7 +63,6 @@ pub trait InternDb: SourceRootDb { impl_intern!(BuiltinDataTyId, BuiltinDataTy, intern_ty, lookup_intern_ty); impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); -impl_intern!(SubroutineId, SubroutineLoc, intern_subroutine, lookup_intern_subroutine); impl_intern!( GenerateBlockId, GenerateBlockLoc, @@ -104,10 +100,10 @@ pub trait HirDb: InternDb { #[salsa::invoke(subroutine::subroutine_with_source_map_query)] fn subroutine_with_source_map( &self, - subroutine: SubroutineId, + subroutine: InContainer, ) -> (Arc, Arc); - fn subroutine(&self, subroutine_id: SubroutineId) -> Arc; + fn subroutine(&self, subroutine_id: InContainer) -> Arc; #[salsa::invoke(generate::generate_block_with_source_map_query)] fn generate_block_with_source_map( @@ -133,7 +129,7 @@ pub trait HirDb: InternDb { fn block_scope(&self, block_id: BlockId) -> Arc; #[salsa::invoke(NameScope::subroutine_scope_query)] - fn subroutine_scope(&self, subroutine_id: SubroutineId) -> Arc; + fn subroutine_scope(&self, subroutine_id: InContainer) -> Arc; #[salsa::invoke(NameScope::package_export_signature_query)] fn package_export_signature(&self, package_id: PackageId) -> Arc; @@ -176,7 +172,7 @@ fn block(db: &dyn HirDb, block_id: BlockId) -> Arc { db.block_with_source_map(block_id).0 } -fn subroutine(db: &dyn HirDb, subroutine_id: SubroutineId) -> Arc { +fn subroutine(db: &dyn HirDb, subroutine_id: InContainer) -> Arc { db.subroutine_with_source_map(subroutine_id).0 } diff --git a/crates/hir/src/def_id.rs b/crates/hir/src/def_id.rs index e0701cb1..d4aaaf85 100644 --- a/crates/hir/src/def_id.rs +++ b/crates/hir/src/def_id.rs @@ -18,11 +18,34 @@ use crate::{ declaration::Declaration, expr::declarator::DeclaratorParent, module::{ModuleKind, generate::GenerateBlockLoc}, + subroutine::{LocalSubroutineId, SubroutineSrc}, }, source_map::{IsNamedSrc, IsSrc, ToAstNode}, symbol::{DefId, DefKind, DefLoc}, }; +fn subroutine_src( + db: &dyn HirDb, + subroutine: InContainer, +) -> Option> { + match subroutine.cont_id { + ScopeId::File(file_id) => { + let (_, source_map) = db.hir_file_with_source_map(file_id); + Some(InFile::new(file_id, source_map.get(subroutine.value)?)) + } + ScopeId::Module(module_id) => { + let (_, source_map) = db.module_with_source_map(module_id); + Some(InFile::new(module_id.file_id, source_map.get(subroutine.value)?)) + } + ScopeId::GenerateBlock(generate_block_id) => { + let (_, source_map) = db.generate_block_with_source_map(generate_block_id); + let file_id = generate_block_id.lookup(db).src.file_id; + Some(InFile::new(file_id, source_map.get(subroutine.value)?)) + } + ScopeId::Block(_) | ScopeId::Subroutine(_) => None, + } +} + impl DefId { #[inline] pub fn container_id(self, db: &dyn HirDb) -> ScopeId { @@ -33,10 +56,9 @@ impl DefId { DefLoc::Udp(InFile { file_id, .. }) => file_id.into(), DefLoc::Block(block_id) => block_id.lookup(db).cont_id, DefLoc::GenerateBlock(generate_block_id) => generate_block_id.lookup(db).cont_id, - DefLoc::Subroutine(subroutine_id) => subroutine_id.lookup(db).cont_id.into(), - DefLoc::PackageSubroutine(InModule { module_id, .. }) => module_id.into(), + DefLoc::Subroutine(subroutine_id) => subroutine_id.cont_id, DefLoc::SubroutinePort(InSubroutine { subroutine, .. }) => { - ScopeId::Subroutine(subroutine) + ScopeId::Subroutine(subroutine.into()) } DefLoc::NonAnsiPort(InModule { module_id, .. }) => module_id.into(), DefLoc::Decl(InContainer { cont_id, .. }) => cont_id, @@ -63,7 +85,6 @@ impl DefId { DefLoc::Block(_) => DefKind::Block, DefLoc::GenerateBlock(_) => DefKind::GenerateBlock, DefLoc::Subroutine(_) => DefKind::Subroutine, - DefLoc::PackageSubroutine(_) => DefKind::Subroutine, DefLoc::SubroutinePort(_) => DefKind::SubroutinePort, DefLoc::NonAnsiPort(_) => DefKind::NonAnsiPort, DefLoc::Decl(InContainer { value, cont_id }) => { @@ -112,9 +133,6 @@ impl DefId { db.generate_block(generate_block_id).name.clone() } DefLoc::Subroutine(subroutine_id) => db.subroutine(subroutine_id).name.clone(), - DefLoc::PackageSubroutine(InModule { module_id, value }) => { - db.module(module_id).get(value).name.clone() - } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { db.subroutine(subroutine).ports.get(value.0 as usize)?.name.clone() } @@ -166,16 +184,11 @@ impl DefId { Some(InFile::new(file_id, range)) } DefLoc::Subroutine(subroutine_id) => { - let src = subroutine_id.lookup(db).src; + let src = subroutine_src(db, subroutine_id)?; Some(InFile::new(src.file_id, src.value.name_or_full_range())) } - DefLoc::PackageSubroutine(InModule { module_id, value }) => { - let (_, src_map) = db.module_with_source_map(module_id); - let range = src_map.get(value)?.name_range()?; - Some(InFile::new(module_id.file_id, range)) - } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { - let src = subroutine.lookup(db).src; + let src = subroutine_src(db, subroutine)?; let tree = db.parse(src.file_id); let func = src.value.to_node(&tree)?; let ports = func @@ -244,17 +257,12 @@ impl DefId { InFile::new(file_id, range) } DefLoc::Subroutine(subroutine_id) => { - let src = subroutine_id.lookup(db).src; + let src = subroutine_src(db, subroutine_id)?; let range = src.value.range(); InFile::new(src.file_id, range) } - DefLoc::PackageSubroutine(InModule { module_id, value }) => { - let (_, src_map) = db.module_with_source_map(module_id); - let range = src_map.get(value)?.range(); - InFile::new(module_id.file_id, range) - } DefLoc::SubroutinePort(InSubroutine { subroutine, value }) => { - let src = subroutine.lookup(db).src; + let src = subroutine_src(db, subroutine)?; let tree = db.parse(src.file_id); let func = src.value.to_node(&tree)?; let ports = func.prototype().port_list()?; diff --git a/crates/hir/src/hir_def/file.rs b/crates/hir/src/hir_def/file.rs index b136cff2..3edd559e 100644 --- a/crates/hir/src/hir_def/file.rs +++ b/crates/hir/src/hir_def/file.rs @@ -32,13 +32,13 @@ use super::{ proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ - LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineLoc, SubroutineSrc, - lower_subroutine, lower_subroutine_body, + LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineSrc, lower_subroutine, + lower_subroutine_body, }, typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }; use crate::{ - container::{InFile, ScopeId}, + container::{InContainer, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::lower_ident_opt, @@ -223,12 +223,7 @@ impl LowerFileCtx<'_> { func => self.file_source_map.subroutine_srcs, }; - let src = SubroutineSrc::from_ast(self.file_id, func); - let subroutine_def_id = self.db.intern_subroutine(SubroutineLoc { - cont_id: self.file_id.into(), - src: InFile::new(self.file_id, src), - local_id: local_subroutine_id, - }); + let subroutine_id = InContainer::new(self.file_id.into(), local_subroutine_id); if func.end().is_some() { let subroutine = &mut self.file.subroutines[local_subroutine_id]; @@ -236,7 +231,7 @@ impl LowerFileCtx<'_> { let mut ctx = LowerSubroutineBodyCtx { db: self.db, file_id: self.file_id, - subroutine_id: subroutine_def_id, + subroutine_id, subroutine, subroutine_source_map: &mut subroutine_source_map, region_tree: RegionTreeBuilder::new(), diff --git a/crates/hir/src/hir_def/module.rs b/crates/hir/src/hir_def/module.rs index 8f63fae8..df55fc7f 100644 --- a/crates/hir/src/hir_def/module.rs +++ b/crates/hir/src/hir_def/module.rs @@ -46,14 +46,14 @@ use super::{ proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ - LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineLoc, SubroutineSrc, - lower_subroutine, lower_subroutine_body, + LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineSrc, lower_subroutine, + lower_subroutine_body, }, ty::NetKind, typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }; use crate::{ - container::{InFile, ScopeId}, + container::{InContainer, InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, region_tree::{RegionTree, RegionTreeBuilder}, @@ -432,12 +432,7 @@ impl LowerModuleCtx<'_> { func => self.module_source_map.subroutine_srcs, }; - let src = SubroutineSrc::from_ast(self.file_id, func); - let subroutine_def_id = self.db.intern_subroutine(SubroutineLoc { - cont_id: self.module_id.into(), - src: InFile::new(self.file_id, src), - local_id: subroutine_id, - }); + let subroutine_def_id = InContainer::new(self.module_id.into(), subroutine_id); if func.end().is_some() { let subroutine = &mut self.module.subroutines[subroutine_id]; diff --git a/crates/hir/src/hir_def/module/generate.rs b/crates/hir/src/hir_def/module/generate.rs index 0cfbc778..b6aab156 100644 --- a/crates/hir/src/hir_def/module/generate.rs +++ b/crates/hir/src/hir_def/module/generate.rs @@ -24,7 +24,7 @@ use super::{ }; use crate::{ base_db::intern::Lookup, - container::{InFile, ScopeId}, + container::{InContainer, InFile, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::{ @@ -44,7 +44,7 @@ use crate::{ proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ - LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineLoc, SubroutineSrc, + LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineSrc, lower_subroutine, lower_subroutine_body, }, typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, @@ -499,12 +499,7 @@ impl LowerGenerateBlockCtx<'_> { func => self.generate_block_source_map.subroutine_srcs, }; - let src = SubroutineSrc::from_ast(self.file_id, func); - let subroutine_def_id = self.db.intern_subroutine(SubroutineLoc { - cont_id: self.generate_block_id.into(), - src: InFile::new(self.file_id, src), - local_id: subroutine_id, - }); + let subroutine_def_id = InContainer::new(self.generate_block_id.into(), subroutine_id); if func.end().is_some() { let subroutine = &mut self.generate_block.subroutines[subroutine_id]; diff --git a/crates/hir/src/hir_def/subroutine.rs b/crates/hir/src/hir_def/subroutine.rs index 4dbf2102..859fb70e 100644 --- a/crates/hir/src/hir_def/subroutine.rs +++ b/crates/hir/src/hir_def/subroutine.rs @@ -25,13 +25,11 @@ use super::{ timing_control::{EventExpr, EventExprSrc}, }, lower_ident_opt, - module::{ModuleId, generate::GenerateBlockId}, stmt::{LowerStmt, Stmt, StmtId, StmtSrc, impl_lower_stmt}, typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }; use crate::{ - base_db::intern::Lookup, - container::{InFile, ScopeId}, + container::{InContainer, ScopeId}, db::{HirDb, InternDb}, file::HirFileId, hir_def::{ @@ -141,64 +139,6 @@ pub type SubroutineSrc = NamedAstId; pub type LocalSubroutineId = Idx; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct SubroutineId(pub salsa::InternId); - -#[derive(Debug, Hash, PartialEq, Eq, Clone)] -pub struct SubroutineLoc { - pub cont_id: SubroutineContainerId, - pub src: InFile, - pub local_id: LocalSubroutineId, -} - -#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] -pub enum SubroutineContainerId { - HirFileId(HirFileId), - ModuleId(ModuleId), - GenerateBlockId(GenerateBlockId), -} - -impl From for SubroutineContainerId { - fn from(file_id: HirFileId) -> Self { - Self::HirFileId(file_id) - } -} - -impl From for SubroutineContainerId { - fn from(module_id: ModuleId) -> Self { - Self::ModuleId(module_id) - } -} - -impl From for SubroutineContainerId { - fn from(generate_block_id: GenerateBlockId) -> Self { - Self::GenerateBlockId(generate_block_id) - } -} - -impl From for ScopeId { - fn from(cont_id: SubroutineContainerId) -> Self { - match cont_id { - SubroutineContainerId::HirFileId(file_id) => file_id.into(), - SubroutineContainerId::ModuleId(module_id) => module_id.into(), - SubroutineContainerId::GenerateBlockId(generate_block_id) => generate_block_id.into(), - } - } -} - -impl TryFrom for SubroutineContainerId { - type Error = (); - - fn try_from(cont_id: ScopeId) -> Result { - match cont_id { - ScopeId::File(file_id) => Ok(file_id.into()), - ScopeId::Module(module_id) => Ok(module_id.into()), - ScopeId::GenerateBlock(generate_block_id) => Ok(generate_block_id.into()), - ScopeId::Block(_) | ScopeId::Subroutine(_) => Err(()), - } - } -} - pub fn lower_subroutine(func: &ast::FunctionDeclaration, mut lower_ty: F) -> Option where F: FnMut(ast::DataType) -> DataTy, @@ -266,7 +206,7 @@ fn map_direction(kind: Option) -> SubroutinePortDir { pub struct LowerSubroutineBodyCtx<'a> { pub(crate) db: &'a dyn InternDb, pub(crate) file_id: HirFileId, - pub(crate) subroutine_id: SubroutineId, + pub(crate) subroutine_id: InContainer, pub(crate) subroutine: &'a mut Subroutine, pub(crate) subroutine_source_map: &'a mut SubroutineSourceMap, pub(crate) region_tree: RegionTreeBuilder, @@ -280,7 +220,7 @@ impl_lower_declaration!(LowerSubroutineBodyCtx<'_>, subroutine, subroutine_sourc impl LowerSubroutineBodyCtx<'_> { fn container_id(&self) -> ScopeId { - ScopeId::Subroutine(self.subroutine_id) + self.subroutine_id.into() } fn lower_struct_type(&mut self, struct_ty: ast::StructUnionType) -> StructId { @@ -391,28 +331,29 @@ pub fn lower_subroutine_body(ctx: &mut LowerSubroutineBodyCtx<'_>, func: ast::Fu pub(crate) fn subroutine_with_source_map_query( db: &dyn HirDb, - subroutine_id: SubroutineId, + subroutine_id: InContainer, ) -> (Arc, Arc) { - let SubroutineLoc { cont_id, local_id, .. } = subroutine_id.lookup(db); - - match cont_id { - SubroutineContainerId::HirFileId(file_id) => { + match subroutine_id.cont_id { + ScopeId::File(file_id) => { let file = db.hir_file(file_id); - let subroutine = file.subroutines[local_id].clone(); + let subroutine = file.subroutines[subroutine_id.value].clone(); let source_map = subroutine.source_map.clone(); (Arc::new(subroutine), Arc::new(source_map)) } - SubroutineContainerId::ModuleId(module_id) => { + ScopeId::Module(module_id) => { let module = db.module(module_id); - let subroutine = module.subroutines[local_id].clone(); + let subroutine = module.subroutines[subroutine_id.value].clone(); let source_map = subroutine.source_map.clone(); (Arc::new(subroutine), Arc::new(source_map)) } - SubroutineContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let generate_block = db.generate_block(generate_block_id); - let subroutine = generate_block.subroutines[local_id].clone(); + let subroutine = generate_block.subroutines[subroutine_id.value].clone(); let source_map = subroutine.source_map.clone(); (Arc::new(subroutine), Arc::new(source_map)) } + ScopeId::Block(_) | ScopeId::Subroutine(_) => { + unreachable!("subroutines are lowered only in file, module, or generate-block scopes") + } } } diff --git a/crates/hir/src/scope.rs b/crates/hir/src/scope.rs index 18d7d6b8..978d0816 100644 --- a/crates/hir/src/scope.rs +++ b/crates/hir/src/scope.rs @@ -20,7 +20,7 @@ use crate::{ port::{PortDeclId, Ports}, }, stmt::StmtKind, - subroutine::{LocalSubroutineId, SubroutineLoc, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutinePortId}, typedef::TypedefId, }, source_map::ToAstNode, @@ -137,7 +137,6 @@ impl NameScope { ) -> Arc { let mut scope = NameScope::default(); let (module, module_src_map) = db.module_with_source_map(module_id); - let file_id = HirFileId::File(module_id.file_id()); if let Ports::NonAnsi { ports, .. } = &module.ports { for (port_id, port) in ports.iter() { @@ -150,14 +149,7 @@ impl NameScope { } for (local_subroutine_id, subroutine) in module.subroutines.iter() { - let Some(src) = module_src_map.get(local_subroutine_id) else { - continue; - }; - let subroutine_id = db.intern_subroutine(SubroutineLoc { - cont_id: module_id.into(), - src: InFile::new(file_id, src), - local_id: local_subroutine_id, - }); + let subroutine_id = InContainer::new(module_id.into(), local_subroutine_id); scope.insert_value_opt(&subroutine.name, def_id(db, subroutine_id)); } @@ -216,20 +208,12 @@ impl NameScope { generate_block_id: GenerateBlockId, ) -> Arc { let mut scope = NameScope::default(); - let (generate_block, source_map) = db.generate_block_with_source_map(generate_block_id); - let file_id = HirFileId::File(generate_block_id.file_id(db)); + let (generate_block, _) = db.generate_block_with_source_map(generate_block_id); scope.insert_value_opt(&generate_block.name, def_id(db, generate_block_id)); for (local_subroutine_id, subroutine) in generate_block.subroutines.iter() { - let Some(src) = source_map.get(local_subroutine_id) else { - continue; - }; - let subroutine_id = db.intern_subroutine(SubroutineLoc { - cont_id: generate_block_id.into(), - src: InFile::new(file_id, src), - local_id: local_subroutine_id, - }); + let subroutine_id = InContainer::new(generate_block_id.into(), local_subroutine_id); scope.insert_value_opt(&subroutine.name, def_id(db, subroutine_id)); } @@ -307,7 +291,7 @@ impl NameScope { pub fn subroutine_scope_query( db: &dyn HirDb, - subroutine_id: crate::hir_def::subroutine::SubroutineId, + subroutine_id: InContainer, ) -> Arc { let mut scope = NameScope::default(); let subroutine = db.subroutine(subroutine_id); @@ -472,8 +456,10 @@ impl PackageExportSignatureBuilder<'_> { fn record_subroutine(&mut self, subroutine: ast::FunctionDeclaration<'_>) { let local_id = self.next_subroutine_id(); let name = lower_name(subroutine.prototype().name()); - self.scope - .insert_value_opt(&name, def_id(self.db, InModule::new(self.package_id, local_id))); + self.scope.insert_value_opt( + &name, + def_id(self.db, InContainer::new(self.package_id.into(), local_id)), + ); } fn next_declaration_id(&mut self) -> DeclarationId { @@ -539,7 +525,7 @@ mod tests { db::{HirDb, HirDbStorage, InternDbStorage}, hir_def::Ident, semantics::pathres::resolve_name, - symbol::{DefKind, NameContext}, + symbol::{DefKind, DefLoc, NameContext}, }; const TOP: FileId = FileId(0); @@ -841,6 +827,79 @@ endmodule ); } + #[test] + fn package_subroutine_def_id_is_canonical_across_imports() { + let db = db_with_root_text( + r#" +package pkg; + function automatic int f(); + return 1; + endfunction +endpackage + +module named_importer; + import pkg::f; +endmodule + +module wildcard_importer; + import pkg::*; +endmodule +"#, + ); + + let package_id = db + .unit_scope() + .package_ids(&db, &ident("pkg")) + .unique() + .expect("package should resolve uniquely"); + let package_f = resolve_name( + &db, + ScopeId::Module(package_id), + &ident("f"), + NameContext::Value, + ) + .and_then(|res| res.primary_def_id()) + .expect("package scope should resolve package subroutine"); + + let DefLoc::Subroutine(package_subroutine) = package_f.loc(&db) else { + panic!("package f should resolve to a subroutine"); + }; + assert_eq!(package_subroutine.cont_id, ScopeId::Module(package_id)); + + let named_importer = db + .unit_scope() + .module_ids(&db, &ident("named_importer")) + .unique() + .expect("named importer should resolve uniquely"); + let named_import_f = resolve_name( + &db, + ScopeId::Module(named_importer), + &ident("f"), + NameContext::Value, + ) + .and_then(|res| res.primary_def_id()) + .expect("named import should resolve package subroutine"); + + let wildcard_importer = db + .unit_scope() + .module_ids(&db, &ident("wildcard_importer")) + .unique() + .expect("wildcard importer should resolve uniquely"); + let wildcard_import_f = resolve_name( + &db, + ScopeId::Module(wildcard_importer), + &ident("f"), + NameContext::Value, + ) + .and_then(|res| res.primary_def_id()) + .expect("wildcard import should resolve package subroutine"); + + assert_eq!(package_f, named_import_f); + assert_eq!(package_f.loc(&db), named_import_f.loc(&db)); + assert_eq!(package_f, wildcard_import_f); + assert_eq!(package_f.loc(&db), wildcard_import_f.loc(&db)); + } + #[test] fn package_export_signature_is_stable_across_function_body_edits() { let mut db = db_with_root_text( diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1b5077d4..c201db79 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -20,7 +20,7 @@ use crate::{ block::{BlockId, BlockSrc}, expr::ExprId, module::{ModuleId, ModuleSrc}, - subroutine::{SubroutineId, SubroutineSrc}, + subroutine::{LocalSubroutineId, SubroutineSrc}, }, symbol::NameContext, }; @@ -148,7 +148,7 @@ impl SemanticsImpl<'_> { &self, file_id: HirFileId, subroutine: ast::FunctionDeclaration, - ) -> Option { + ) -> Option> { let subroutine_src = SubroutineSrc::from_ast(file_id, subroutine); self.with_ctx(|ctx| ctx.subroutine_to_def(InFile::new(file_id, subroutine_src))) } diff --git a/crates/hir/src/semantics/hir_to_def.rs b/crates/hir/src/semantics/hir_to_def.rs index 6329ba3d..76f88e27 100644 --- a/crates/hir/src/semantics/hir_to_def.rs +++ b/crates/hir/src/semantics/hir_to_def.rs @@ -67,7 +67,7 @@ impl Source2DefCtx<'_, '_> { resolve(generate_block.get(expr_id)) } ScopeId::Subroutine(subroutine_id) => { - let subroutine = db.subroutine(subroutine_id); + let subroutine = db.subroutine(subroutine_id.as_in_container()); resolve(subroutine.get(expr_id)) } } diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index 1bbde270..a733f91a 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -72,7 +72,7 @@ pub(crate) fn name_scope(db: &dyn HirDb, scope_id: ScopeId) -> Arc { ScopeId::Module(module_id) => db.module_scope(module_id), ScopeId::GenerateBlock(generate_block_id) => db.generate_block_scope(generate_block_id), ScopeId::Block(block_id) => db.block_scope(block_id), - ScopeId::Subroutine(subroutine_id) => db.subroutine_scope(subroutine_id), + ScopeId::Subroutine(subroutine_id) => db.subroutine_scope(subroutine_id.as_in_container()), } } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index b08e52b5..d8993212 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -9,7 +9,7 @@ use utils::get::{Get, GetRef}; use super::hir_to_def::Hir2DefCache; use crate::{ - container::{InFile, ScopeId}, + container::{InContainer, InFile, ScopeId}, db::HirDb, file::HirFileId, hir_def::{ @@ -18,9 +18,7 @@ use crate::{ ModuleId, ModuleSrc, generate::{GenerateBlockLoc, GenerateBlockSrc}, }, - subroutine::{ - LocalSubroutineId, SubroutineContainerId, SubroutineId, SubroutineLoc, SubroutineSrc, - }, + subroutine::{LocalSubroutineId, SubroutineSrc}, }, source_map::ToAstNode, }; @@ -57,7 +55,7 @@ impl Source2DefCtx<'_, '_> { pub(super) fn subroutine_to_def( &mut self, InFile { file_id, value: subroutine_src }: InFile, - ) -> Option { + ) -> Option> { let tree = self.db.parse(file_id); let node = subroutine_src.to_node(&tree)?; self.subroutine_to_def_inner(file_id, node, subroutine_src) @@ -97,7 +95,7 @@ impl Source2DefCtx<'_, '_> { } ScopeId::Subroutine(subroutine_id) => { let (subroutine, subroutine_src_map) = - self.db.subroutine_with_source_map(subroutine_id); + self.db.subroutine_with_source_map(subroutine_id.as_in_container()); let local_block_id = *subroutine_src_map.block_srcs.get(&block_src)?; subroutine.stmts.get(local_block_id).block_id } @@ -151,7 +149,7 @@ impl Source2DefCtx<'_, '_> { file_id: HirFileId, node: ast::FunctionDeclaration, src: SubroutineSrc, - ) -> Option { + ) -> Option> { let parent = ast::Member::cast(node.syntax()) .and_then(|member| self.single_member_generate_block_to_def(file_id, member)) .or_else(|| { @@ -160,33 +158,29 @@ impl Source2DefCtx<'_, '_> { .find_map(|node| self.container_to_def(file_id, node)) }) .unwrap_or(file_id.into()); - let cont_id = SubroutineContainerId::try_from(parent).ok()?; - let local_id = self.local_subroutine_id(cont_id, src)?; - Some(self.db.intern_subroutine(SubroutineLoc { - cont_id, - src: InFile::new(file_id, src), - local_id, - })) + let local_id = self.local_subroutine_id(parent, src)?; + Some(InContainer::new(parent, local_id)) } fn local_subroutine_id( &self, - cont_id: SubroutineContainerId, + cont_id: ScopeId, src: SubroutineSrc, ) -> Option { match cont_id { - SubroutineContainerId::HirFileId(file_id) => { + ScopeId::File(file_id) => { let (_, source_map) = self.db.hir_file_with_source_map(file_id); source_map.get(src) } - SubroutineContainerId::ModuleId(module_id) => { + ScopeId::Module(module_id) => { let (_, source_map) = self.db.module_with_source_map(module_id); source_map.get(src) } - SubroutineContainerId::GenerateBlockId(generate_block_id) => { + ScopeId::GenerateBlock(generate_block_id) => { let (_, source_map) = self.db.generate_block_with_source_map(generate_block_id); source_map.get(src) } + ScopeId::Block(_) | ScopeId::Subroutine(_) => None, } } diff --git a/crates/hir/src/symbol.rs b/crates/hir/src/symbol.rs index d8a6e24d..c553a666 100644 --- a/crates/hir/src/symbol.rs +++ b/crates/hir/src/symbol.rs @@ -15,7 +15,7 @@ use crate::{ ModuleId, generate::GenerateBlockId, instantiation::InstanceId, port::NonAnsiPortId, }, stmt::StmtId, - subroutine::{LocalSubroutineId, SubroutineId, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutinePortId}, typedef::TypedefId, }, }; @@ -32,8 +32,7 @@ pub enum DefLoc { Udp(InFile), Block(BlockId), GenerateBlock(GenerateBlockId), - Subroutine(SubroutineId), - PackageSubroutine(InModule), + Subroutine(InContainer), SubroutinePort(InSubroutine), NonAnsiPort(InModule), Decl(InContainer), @@ -49,8 +48,7 @@ impl_from! { DefLoc => Udp(InFile), Block(BlockId), GenerateBlock(GenerateBlockId), - Subroutine(SubroutineId), - PackageSubroutine(InModule), + Subroutine(InContainer), SubroutinePort(InSubroutine), NonAnsiPort(InModule), Decl(InContainer), @@ -110,7 +108,7 @@ impl DefId { } } - pub fn as_subroutine(self, db: &dyn InternDb) -> Option { + pub fn as_subroutine(self, db: &dyn InternDb) -> Option> { match self.loc(db) { DefLoc::Subroutine(id) => Some(id), _ => None, diff --git a/crates/hir/src/type_infer.rs b/crates/hir/src/type_infer.rs index cc95fad7..abeeb05a 100644 --- a/crates/hir/src/type_infer.rs +++ b/crates/hir/src/type_infer.rs @@ -500,7 +500,7 @@ fn type_of_subroutine_port_impl(db: &dyn HirDb, port: InSubroutine) -> Option { } ScopeId::Block(block_id) => Some(db.block(block_id).get(expr.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(expr.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(expr.value).clone()) } } } @@ -589,7 +589,7 @@ fn decl_of( } ScopeId::Block(block_id) => Some(db.block(block_id).get(decl.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(decl.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(decl.value).clone()) } } } @@ -606,7 +606,7 @@ fn declaration_of( } ScopeId::Block(block_id) => Some(db.block(block_id).get(decl.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(decl.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(decl.value).clone()) } } } @@ -623,7 +623,7 @@ fn typedef_of( } ScopeId::Block(block_id) => Some(db.block(block_id).get(typedef.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(typedef.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(typedef.value).clone()) } } } @@ -640,7 +640,7 @@ fn struct_of( } ScopeId::Block(block_id) => Some(db.block(block_id).get(struct_id.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(struct_id.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(struct_id.value).clone()) } } } @@ -657,7 +657,7 @@ fn stmt_of( } ScopeId::Block(block_id) => Some(db.block(block_id).get(stmt.value).clone()), ScopeId::Subroutine(subroutine_id) => { - Some(db.subroutine(subroutine_id).get(stmt.value).clone()) + Some(db.subroutine(subroutine_id.as_in_container()).get(stmt.value).clone()) } } } diff --git a/crates/ide/src/completion/engine/expr.rs b/crates/ide/src/completion/engine/expr.rs index 470e7b72..72cc5f47 100644 --- a/crates/ide/src/completion/engine/expr.rs +++ b/crates/ide/src/completion/engine/expr.rs @@ -7,7 +7,7 @@ use hir::{ hir_def::{ lower_ident_opt, module::ModuleId, - subroutine::{SubroutineId, SubroutineKind}, + subroutine::{LocalSubroutineId, SubroutineKind}, }, semantics::{Semantics, pathres::PathResolution}, symbol::{DefId, DefKind}, @@ -126,7 +126,7 @@ fn collect_container_names( } } ScopeId::Subroutine(subroutine_id) => { - let scope = db.subroutine_scope(subroutine_id); + let scope = db.subroutine_scope(subroutine_id.as_in_container()); for (ident, defs) in scope.iter_listing() { collect_def_names(db, ident, defs, names); } @@ -182,10 +182,10 @@ fn collect_def_names( } } -fn subroutine_return_ty(db: &RootDb, subroutine_id: SubroutineId) -> Ty { +fn subroutine_return_ty(db: &RootDb, subroutine_id: InContainer) -> Ty { match db.subroutine(subroutine_id).kind { SubroutineKind::Function { return_ty: Some(return_ty) } => { - normalize_data_ty(db, ScopeId::Subroutine(subroutine_id), return_ty).ty + normalize_data_ty(db, subroutine_id.into(), return_ty).ty } SubroutineKind::Function { return_ty: None } | SubroutineKind::Task => Ty::Unknown, } diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index aebd9a1a..1ed30938 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -14,17 +14,16 @@ use hir::{ port::NonAnsiPortId, }, stmt::StmtId, - subroutine::{SubroutineId, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutinePortId}, typedef::TypedefId, }, - source_map::{IsNamedSrc, IsSrc, ToAstNode}, + source_map::{IsNamedSrc, IsSrc}, symbol::DefId, }; use smol_str::SmolStr; use syntax::{ SyntaxTokenWithParent, - ast::AstNode, - has_text_range::{HasTextRange, HasTextRangeIn}, + has_text_range::HasTextRange, }; use utils::{ get::{Get, GetRef}, @@ -162,51 +161,15 @@ impl ToNav for GenerateBlockId { } } -impl ToNav for SubroutineId { +impl ToNav for InContainer { fn to_nav(&self, db: &RootDb) -> Option { - let loc = self.lookup(db); - let cont_id: ScopeId = loc.cont_id.into(); - let cont_name = cont_id.to_container(db).name().cloned(); - let name = db.subroutine(*self).name.clone(); - let focus_range = loc.src.value.name_range(); - - let file_id = loc.src.file_id.file_id(); - Some(build(file_id, focus_range, loc.src.value.range(), name, SymbolKind::Fn, cont_name)) + DefId::new(db, *self).to_nav(db) } } impl ToNav for InSubroutine { fn to_nav(&self, db: &RootDb) -> Option { - let InSubroutine { subroutine, value } = *self; - let loc = subroutine.lookup(db); - let cont_name = db.subroutine(subroutine).name.clone(); - let subroutine_src = loc.src; - let tree = db.parse(subroutine_src.file_id); - let func = subroutine_src.value.to_node(&tree)?; - let ports = func.prototype().port_list()?; - let port = ports - .ports() - .children() - .nth(value.0 as usize) - .and_then(|port| port.as_function_port())?; - let name = db - .subroutine(subroutine) - .ports - .get(value.0 as usize) - .and_then(|port| port.name.clone()); - let declarator = port.declarator(); - let focus_range = - declarator.name().and_then(|name| name.text_range_in(declarator.syntax())); - let full_range = port.syntax().text_range()?; - - Some(build( - subroutine_src.file_id.file_id(), - focus_range, - full_range, - name, - SymbolKind::PortDecl, - cont_name, - )) + DefId::new(db, *self).to_nav(db) } } diff --git a/crates/ide/src/references/search.rs b/crates/ide/src/references/search.rs index 62d727c9..e5e90790 100644 --- a/crates/ide/src/references/search.rs +++ b/crates/ide/src/references/search.rs @@ -9,6 +9,7 @@ use hir::{ def_id::ModuleDefId, semantics::Semantics, source_map::IsSrc, + symbol::DefId, }; use nohash_hasher::IntMap; use rustc_hash::FxHashMap; @@ -92,8 +93,12 @@ impl SearchScope { Self::single_range(src.file_id.file_id(), src.value.range()) } ScopeId::Subroutine(subroutine_id) => { - let src = subroutine_id.lookup(db).src; - Self::single_range(src.file_id.file_id(), src.value.range()) + let def_id = DefId::new(db, subroutine_id.as_in_container()); + if let Some(InFile { file_id, value: range }) = def_id.range(db) { + Self::single_range(file_id.file_id(), range) + } else { + Self::all(db) + } } } } diff --git a/crates/ide/src/render.rs b/crates/ide/src/render.rs index 23d583e7..cd574bd0 100644 --- a/crates/ide/src/render.rs +++ b/crates/ide/src/render.rs @@ -1,8 +1,5 @@ use hir::{ - base_db::{ - intern::Lookup, - source_db::{SourceDb, SourceRootDb}, - }, + base_db::source_db::{SourceDb, SourceRootDb}, container::{InContainer, InFile, InModule, InSubroutine, ScopeId, ScopeParent}, db::HirDb, def_id::ModuleDefId, @@ -20,7 +17,7 @@ use hir::{ instantiation::InstanceId, port::{NonAnsiPortId, Ports}, }, - subroutine::{LocalSubroutineId, SubroutineId, SubroutineKind, SubroutinePortId}, + subroutine::{LocalSubroutineId, SubroutineKind, SubroutinePortId}, }, region_tree::RegionParent, semantics::Semantics, @@ -297,12 +294,6 @@ fn render_definition_title(db: &RootDb, origin: &DefId) -> Option { SubroutineKind::Task => "Task", SubroutineKind::Function { .. } => "Function", }, - DefLoc::PackageSubroutine(subroutine_id) => { - match db.module(subroutine_id.module_id).get(subroutine_id.value).kind { - SubroutineKind::Task => "Task", - SubroutineKind::Function { .. } => "Function", - } - } DefLoc::SubroutinePort(_) | DefLoc::NonAnsiPort(_) => "Port", DefLoc::Decl(decl_id) => render_decl_title_kind(db, decl_id)?, DefLoc::Typedef(_) => "Typedef", @@ -338,9 +329,6 @@ fn render_signature(sema: &Semantics, origin: &DefId) -> Option match origin.loc(db) { DefLoc::Module(module_id) => render_module_signature(db, module_id), DefLoc::Subroutine(subroutine_id) => render_subroutine_signature(db, subroutine_id), - DefLoc::PackageSubroutine(subroutine_id) => { - render_package_subroutine_signature(db, subroutine_id) - } DefLoc::SubroutinePort(port_id) => render_subroutine_port_signature(db, port_id), DefLoc::NonAnsiPort(port_id) => render_non_ansi_port_signature(db, port_id), DefLoc::Decl(decl_id) => render_decl_signature(db, decl_id), @@ -408,7 +396,7 @@ fn render_subroutine_port_signature( let subroutine = db.subroutine(port_id.subroutine); let port = subroutine.ports.get(port_id.value.0 as usize)?; let name = port.name.as_ref()?; - let container = port_id.subroutine.lookup(db).cont_id.into(); + let container = port_id.subroutine.cont_id; let ty = port.ty.and_then(|ty| render_data_ty(db, container, ty)); let dir = port.direction.display_source(db).ok()?; @@ -420,10 +408,13 @@ fn render_subroutine_port_signature( } } -fn render_subroutine_signature(db: &RootDb, subroutine_id: SubroutineId) -> Option { +fn render_subroutine_signature( + db: &RootDb, + subroutine_id: InContainer, +) -> Option { let subroutine = db.subroutine(subroutine_id); let name = subroutine.name.as_ref()?; - let container = subroutine_id.lookup(db).cont_id.into(); + let container = subroutine_id.cont_id; let mut signature = match subroutine.kind { SubroutineKind::Task => format!("task {name}"), SubroutineKind::Function { return_ty } => { @@ -456,51 +447,6 @@ fn render_subroutine_signature(db: &RootDb, subroutine_id: SubroutineId) -> Opti Some(signature) } -fn render_package_subroutine_signature( - db: &RootDb, - subroutine_id: InModule, -) -> Option { - let subroutine = db.module(subroutine_id.module_id); - let subroutine = subroutine.get(subroutine_id.value); - let name = subroutine.name.as_ref()?; - let container = subroutine_id.module_id.into(); - let mut signature = match subroutine.kind { - SubroutineKind::Task => format!("task {name}"), - SubroutineKind::Function { return_ty } => { - if let Some(return_ty) = return_ty.and_then(|ty| render_data_ty(db, container, ty)) { - format!("function {return_ty} {name}") - } else { - format!("function {name}") - } - } - }; - - let ports = subroutine - .ports - .iter() - .filter_map(|port| { - let name = port.name.as_ref()?; - let ty = port.ty.and_then(|ty| render_data_ty(db, container, ty)); - let dir = port.direction.display_source(db).ok()?; - - match (dir.is_empty(), ty) { - (false, Some(ty)) => Some(format!("{dir} {ty} {name}")), - (false, None) => Some(format!("{dir} {name}")), - (true, Some(ty)) => Some(format!("{ty} {name}")), - (true, None) => Some(name.to_string()), - } - }) - .collect_vec(); - if ports.is_empty() { - signature.push_str("()"); - } else { - signature.push('('); - signature.push_str(&ports.join(", ")); - signature.push(')'); - } - Some(signature) -} - fn render_module_port_list(db: &RootDb, module_id: ModuleId) -> Vec { let module = db.module(module_id); match &module.ports { @@ -686,7 +632,6 @@ fn render_label_signature(db: &RootDb, origin: &DefId) -> Option { DefLoc::Typedef(_) => "typedef", DefLoc::Module(_) | DefLoc::Subroutine(_) - | DefLoc::PackageSubroutine(_) | DefLoc::SubroutinePort(_) | DefLoc::NonAnsiPort(_) | DefLoc::Decl(_) => return None, From cf056bbe64b8494c1bea8a40135112dace91dc52 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 27 Jun 2026 13:32:43 +0800 Subject: [PATCH 7/7] chore: satisfy workspace lint gates Apply rustfmt and clippy fixes for the symbol-core cut-over, PerNs import resolution, and subroutine container-handle refactor. --- crates/hir/src/db.rs | 4 +-- crates/hir/src/hir_def/module.rs | 9 ++---- crates/hir/src/hir_def/module/generate.rs | 4 +-- crates/hir/src/scope.rs | 36 ++++++++--------------- crates/ide/src/navigation_target.rs | 5 +--- 5 files changed, 18 insertions(+), 40 deletions(-) diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index df785bf9..1f53314e 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -21,9 +21,7 @@ use crate::{ self, GenerateBlock, GenerateBlockId, GenerateBlockLoc, GenerateBlockSourceMap, }, }, - subroutine::{ - self, LocalSubroutineId, Subroutine, SubroutinePortId, SubroutineSourceMap, - }, + subroutine::{self, LocalSubroutineId, Subroutine, SubroutinePortId, SubroutineSourceMap}, typedef::TypedefId, }, impl_intern_key, impl_intern_lookup, diff --git a/crates/hir/src/hir_def/module.rs b/crates/hir/src/hir_def/module.rs index df55fc7f..40f1ba91 100644 --- a/crates/hir/src/hir_def/module.rs +++ b/crates/hir/src/hir_def/module.rs @@ -301,8 +301,9 @@ define_enum_deriving_from! { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)] pub enum ModuleKind { + #[default] Module, Interface, Program, @@ -323,12 +324,6 @@ impl ModuleKind { } } -impl Default for ModuleKind { - fn default() -> Self { - ModuleKind::Module - } -} - #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct ModuleInfo { pub name: Option, diff --git a/crates/hir/src/hir_def/module/generate.rs b/crates/hir/src/hir_def/module/generate.rs index b6aab156..7f6af352 100644 --- a/crates/hir/src/hir_def/module/generate.rs +++ b/crates/hir/src/hir_def/module/generate.rs @@ -44,8 +44,8 @@ use crate::{ proc::{LowerProc, LowerProcCtx, Proc, ProcId, ProcSrc}, stmt::{Stmt, StmtId, StmtSrc, impl_lower_stmt}, subroutine::{ - LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineSrc, - lower_subroutine, lower_subroutine_body, + LocalSubroutineId, LowerSubroutineBodyCtx, Subroutine, SubroutineSrc, lower_subroutine, + lower_subroutine_body, }, typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty}, }, diff --git a/crates/hir/src/scope.rs b/crates/hir/src/scope.rs index 978d0816..d7d5453a 100644 --- a/crates/hir/src/scope.rs +++ b/crates/hir/src/scope.rs @@ -852,14 +852,10 @@ endmodule .package_ids(&db, &ident("pkg")) .unique() .expect("package should resolve uniquely"); - let package_f = resolve_name( - &db, - ScopeId::Module(package_id), - &ident("f"), - NameContext::Value, - ) - .and_then(|res| res.primary_def_id()) - .expect("package scope should resolve package subroutine"); + let package_f = + resolve_name(&db, ScopeId::Module(package_id), &ident("f"), NameContext::Value) + .and_then(|res| res.primary_def_id()) + .expect("package scope should resolve package subroutine"); let DefLoc::Subroutine(package_subroutine) = package_f.loc(&db) else { panic!("package f should resolve to a subroutine"); @@ -871,28 +867,20 @@ endmodule .module_ids(&db, &ident("named_importer")) .unique() .expect("named importer should resolve uniquely"); - let named_import_f = resolve_name( - &db, - ScopeId::Module(named_importer), - &ident("f"), - NameContext::Value, - ) - .and_then(|res| res.primary_def_id()) - .expect("named import should resolve package subroutine"); + let named_import_f = + resolve_name(&db, ScopeId::Module(named_importer), &ident("f"), NameContext::Value) + .and_then(|res| res.primary_def_id()) + .expect("named import should resolve package subroutine"); let wildcard_importer = db .unit_scope() .module_ids(&db, &ident("wildcard_importer")) .unique() .expect("wildcard importer should resolve uniquely"); - let wildcard_import_f = resolve_name( - &db, - ScopeId::Module(wildcard_importer), - &ident("f"), - NameContext::Value, - ) - .and_then(|res| res.primary_def_id()) - .expect("wildcard import should resolve package subroutine"); + let wildcard_import_f = + resolve_name(&db, ScopeId::Module(wildcard_importer), &ident("f"), NameContext::Value) + .and_then(|res| res.primary_def_id()) + .expect("wildcard import should resolve package subroutine"); assert_eq!(package_f, named_import_f); assert_eq!(package_f.loc(&db), named_import_f.loc(&db)); diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 1ed30938..de9db63b 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -21,10 +21,7 @@ use hir::{ symbol::DefId, }; use smol_str::SmolStr; -use syntax::{ - SyntaxTokenWithParent, - has_text_range::HasTextRange, -}; +use syntax::{SyntaxTokenWithParent, has_text_range::HasTextRange}; use utils::{ get::{Get, GetRef}, line_index::TextRange,