diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index fa2e6dc5..61cb9cd0 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -3,11 +3,16 @@ use triomphe::Arc; use crate::{ base_db::{salsa, source_db::SourceRootDb}, + container::{InContainer, InSubroutine}, def_id::{ModuleDef, ModuleDefId}, file::HirFileId, hir_def::{ block::{self, Block, BlockId, BlockLoc, BlockSourceMap}, - expr::data_ty::{BuiltinDataTy, BuiltinDataTyId}, + expr::{ + ExprId, + data_ty::{BuiltinDataTy, BuiltinDataTyId}, + declarator::DeclId, + }, file::{self, FileSourceMap, HirFile}, macro_file::{self, ExpansionInfo, MacroCallId, MacroCallLoc, MacroFileId, MacroFileLoc}, module::{ @@ -16,10 +21,15 @@ use crate::{ self, GenerateBlock, GenerateBlockId, GenerateBlockLoc, GenerateBlockSourceMap, }, }, - subroutine::{self, Subroutine, SubroutineId, SubroutineLoc, SubroutineSourceMap}, + subroutine::{ + self, Subroutine, SubroutineId, SubroutineLoc, SubroutinePortId, SubroutineSourceMap, + }, + typedef::TypedefId, }, impl_intern_key, impl_intern_lookup, scope::{BlockScope, GenerateBlockScope, ModuleScope, SubroutineScope, UnitScope}, + semantics::pathres::PathResolution, + type_infer::TyResult, }; pub(crate) macro impl_intern($id:ident, $loc:ident, $intern:ident, $lookup:ident) { @@ -120,6 +130,21 @@ pub trait HirDb: InternDb { #[salsa::invoke(SubroutineScope::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; + + #[salsa::invoke(crate::type_infer::type_of_typedef_query)] + fn type_of_typedef(&self, typedef: InContainer) -> Arc; + + #[salsa::invoke(crate::type_infer::type_of_expr_query)] + fn type_of_expr(&self, expr: InContainer) -> Arc; + + #[salsa::invoke(crate::type_infer::type_of_path_resolution_query)] + fn type_of_path_resolution(&self, res: PathResolution) -> Arc; + + #[salsa::invoke(crate::type_infer::type_of_subroutine_port_query)] + fn type_of_subroutine_port(&self, port: InSubroutine) -> Arc; } fn parse(db: &dyn HirDb, file_id: HirFileId) -> SyntaxTree { diff --git a/crates/hir/src/semantics/pathres.rs b/crates/hir/src/semantics/pathres.rs index b3dd8c9c..6c6372ae 100644 --- a/crates/hir/src/semantics/pathres.rs +++ b/crates/hir/src/semantics/pathres.rs @@ -70,7 +70,7 @@ pub fn resolve_name(db: &dyn HirDb, cont_id: ContainerId, ident: &Ident) -> Opti }) } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum PathResolution { Module(ModuleId), Config(InFile), diff --git a/crates/hir/src/type_infer.rs b/crates/hir/src/type_infer.rs index 2fbb0337..4bf8ba00 100644 --- a/crates/hir/src/type_infer.rs +++ b/crates/hir/src/type_infer.rs @@ -1,4 +1,5 @@ use rustc_hash::FxHashSet; +use triomphe::Arc; use utils::get::GetRef; use crate::{ @@ -40,7 +41,7 @@ pub enum Ty { Block(crate::hir_def::block::BlockId), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TyResult { pub ty: Ty, pub diagnostics: Vec, @@ -75,30 +76,56 @@ pub fn normalize_data_ty(db: &dyn HirDb, container: ContainerId, data_ty: DataTy normalize_data_ty_inner(db, container, data_ty, &mut FxHashSet::default()) } -pub fn type_of_typedef(db: &dyn HirDb, typedef: InContainer) -> TyResult { +pub(crate) fn type_of_typedef_query( + db: &dyn HirDb, + typedef: InContainer, +) -> Arc { + Arc::new(type_of_typedef_impl(db, typedef)) +} + +pub(crate) fn type_of_decl_query(db: &dyn HirDb, decl: InContainer) -> Arc { + Arc::new(type_of_decl_impl(db, decl)) +} + +pub(crate) fn type_of_path_resolution_query(db: &dyn HirDb, res: PathResolution) -> Arc { + Arc::new(type_of_path_resolution_impl(db, res)) +} + +pub(crate) fn type_of_expr_query(db: &dyn HirDb, expr: InContainer) -> Arc { + Arc::new(type_of_expr_impl(db, expr)) +} + +pub(crate) fn type_of_subroutine_port_query( + db: &dyn HirDb, + port: InSubroutine, +) -> Arc { + Arc::new(type_of_subroutine_port_impl(db, port)) +} + +fn type_of_typedef_impl(db: &dyn HirDb, typedef: InContainer) -> TyResult { type_of_typedef_inner(db, typedef, &mut FxHashSet::default()) } -pub fn type_of_decl(db: &dyn HirDb, decl: InContainer) -> TyResult { +fn type_of_decl_impl(db: &dyn HirDb, decl: InContainer) -> TyResult { let Some(data_ty) = data_ty_of_decl(db, decl) else { return TyResult::new(Ty::Unknown); }; normalize_data_ty(db, decl.cont_id, data_ty) } -pub fn type_of_path_resolution(db: &dyn HirDb, res: PathResolution) -> 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(db, decl), - PathResolution::Typedef(typedef) => type_of_typedef(db, typedef), + 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(db, decl.into()) + type_of_decl_impl(db, decl.into()) } PathResolution::NonAnsiPort { port_decl, data_decl, module, .. } => data_decl .or(port_decl) - .map(|decl| type_of_decl(db, InContainer::new(module.into(), decl))) + .map(|decl| type_of_decl_impl(db, InContainer::new(module.into(), decl))) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), - PathResolution::SubroutinePort(port) => type_of_subroutine_port(db, port), + 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))) @@ -116,20 +143,20 @@ pub fn type_of_path_resolution(db: &dyn HirDb, res: PathResolution) -> TyResult } } -pub fn type_of_expr(db: &dyn HirDb, expr: InContainer) -> TyResult { +fn type_of_expr_impl(db: &dyn HirDb, expr: InContainer) -> TyResult { let Some(hir_expr) = expr_of(db, expr) else { return TyResult::new(Ty::Unknown); }; match hir_expr { Expr::Ident(ident) => resolve_name(db, expr.cont_id, &ident) - .map(|res| type_of_path_resolution(db, res)) + .map(|res| type_of_path_resolution_impl(db, res)) .unwrap_or_else(|| TyResult::new(Ty::Unknown)), Expr::Field { receiver, field } => { let Some(field) = field else { return TyResult::new(Ty::Unknown); }; - let base = type_of_expr(db, expr.with_value(receiver)); + let base = type_of_expr_impl(db, expr.with_value(receiver)); if matches!(base.ty, Ty::Unknown | Ty::Error) { return base; } @@ -137,7 +164,7 @@ pub fn type_of_expr(db: &dyn HirDb, expr: InContainer) -> TyResult { selected.diagnostics.extend(base.diagnostics); selected } - Expr::ElementSelect { receiver, .. } => type_of_expr(db, expr.with_value(receiver)), + Expr::ElementSelect { receiver, .. } => type_of_expr_impl(db, expr.with_value(receiver)), Expr::Cast { ty, .. } => normalize_data_ty(db, expr.cont_id, ty), _ => TyResult::new(Ty::Unknown), } @@ -276,7 +303,7 @@ 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(db, res), + Some(res) => type_of_path_resolution_impl(db, res), None => TyResult::new(Ty::Unknown), } } @@ -336,7 +363,7 @@ fn module_members(db: &dyn HirDb, module_id: ModuleId) -> Vec { .iter() .map(|(name, entry)| { let origin = PathResolution::from(InModule::new(module_id, entry)); - let ty = type_of_path_resolution(db, origin).ty; + let ty = type_of_path_resolution_impl(db, origin).ty; TyMember { name: name.clone(), ty, origin: Some(origin) } }) .collect(); @@ -350,7 +377,7 @@ fn generate_block_members(db: &dyn HirDb, generate_block_id: GenerateBlockId) -> .iter() .map(|(name, entry)| { let origin = PathResolution::from(InGenerateBlock::new(generate_block_id, entry)); - let ty = type_of_path_resolution(db, origin).ty; + let ty = type_of_path_resolution_impl(db, origin).ty; TyMember { name: name.clone(), ty, origin: Some(origin) } }) .collect(); @@ -364,7 +391,7 @@ fn block_members(db: &dyn HirDb, block_id: crate::hir_def::block::BlockId) -> Ve .iter() .map(|(name, entry)| { let origin = PathResolution::from(crate::container::InBlock::new(block_id, entry)); - let ty = type_of_path_resolution(db, origin).ty; + let ty = type_of_path_resolution_impl(db, origin).ty; TyMember { name: name.clone(), ty, origin: Some(origin) } }) .collect(); @@ -411,7 +438,7 @@ fn for_init_decl_ty( inits.iter().find_map(|(ty, decl)| (*decl == decl_id).then_some(*ty).flatten()) } -fn type_of_subroutine_port(db: &dyn HirDb, port: InSubroutine) -> TyResult { +fn type_of_subroutine_port_impl(db: &dyn HirDb, port: InSubroutine) -> TyResult { let subroutine = db.subroutine(port.subroutine); let port_id = port; let Some(port) = subroutine.ports.get(port_id.value.0 as usize) else { diff --git a/crates/ide/src/code_action/handlers/extract_variable.rs b/crates/ide/src/code_action/handlers/extract_variable.rs index 1b260627..0ac1507b 100644 --- a/crates/ide/src/code_action/handlers/extract_variable.rs +++ b/crates/ide/src/code_action/handlers/extract_variable.rs @@ -3,8 +3,9 @@ use std::ops::Range; use hir::{ base_db::source_db::SourceDb, container::InContainer, + db::HirDb, display::HirDisplay, - type_infer::{BuiltinTy, Ty, type_of_expr, type_of_path_resolution}, + type_infer::{BuiltinTy, Ty}, }; use syntax::{ SyntaxAncestors, SyntaxKind, TokenKind, WalkEvent, @@ -176,7 +177,8 @@ fn trim_range(text: &str, range: TextRange) -> Option { } fn extracted_variable_type(ctx: &CodeActionCtx<'_>, expr: ast::Expression<'_>) -> Option { - let ty = type_of_expr(ctx.sema().db, ctx.sema().resolve_expr(ctx.file_id().into(), expr)?).ty; + let ty = + ctx.sema().db.type_of_expr(ctx.sema().resolve_expr(ctx.file_id().into(), expr)?).ty.clone(); render_ty(ctx, &ty) .or_else(|| expected_type_for_assignment_rhs(ctx, expr).and_then(|ty| render_ty(ctx, &ty))) } @@ -189,7 +191,7 @@ fn expected_type_for_assignment_rhs( let res = ctx .sema() .expr_to_def(ctx.sema().resolve_expr(ctx.file_id().into(), assignment.left())?)?; - Some(type_of_path_resolution(ctx.sema().db, res).ty) + Some(ctx.sema().db.type_of_path_resolution(res).ty.clone()) } fn render_ty(ctx: &CodeActionCtx<'_>, ty: &Ty) -> Option { diff --git a/crates/ide/src/completion/engine/expr.rs b/crates/ide/src/completion/engine/expr.rs index 4eedd681..c38add31 100644 --- a/crates/ide/src/completion/engine/expr.rs +++ b/crates/ide/src/completion/engine/expr.rs @@ -14,7 +14,7 @@ use hir::{ SubroutineEntry, UnitEntry, }, semantics::{Semantics, pathres::PathResolution}, - type_infer::{Ty, normalize_data_ty, type_class, type_of_decl, type_of_path_resolution}, + type_infer::{Ty, normalize_data_ty, type_class}, }; use syntax::{ SyntaxKind, SyntaxNode, SyntaxNodeExt, @@ -122,7 +122,7 @@ fn collect_container_names( match entry { GenerateBlockEntry::DeclId(decl_id) => { names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: type_of_decl(db, InContainer::new(container_id, decl_id)).ty, + ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), }); } GenerateBlockEntry::SubroutineId(subroutine_id) => { @@ -139,7 +139,7 @@ fn collect_container_names( for (ident, entry) in scope.iter() { if let BlockEntry::DeclId(decl_id) = entry { names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: type_of_decl(db, InContainer::new(container_id, decl_id)).ty, + ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), }); } } @@ -150,18 +150,16 @@ fn collect_container_names( match entry { SubroutineEntry::DeclId(decl_id) => { names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: type_of_decl(db, InContainer::new(container_id, decl_id)).ty, + ty: db.type_of_decl(InContainer::new(container_id, decl_id)).ty.clone(), }); } SubroutineEntry::SubroutinePortId(port_id) => { - let ty = type_of_path_resolution( - db, - PathResolution::SubroutinePort(InSubroutine::new( - subroutine_id, - port_id, - )), - ) - .ty; + 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 }); } _ => {} @@ -176,11 +174,10 @@ fn collect_file_names(db: &RootDb, file_id: HirFileId, names: &mut BTreeMap { names.entry(ident.to_string()).or_insert(NameKind::Value { - ty: type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty, + 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: type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty, + 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| type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty) + .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 }); } @@ -280,7 +279,7 @@ fn expected_type_for_assignment_rhs( } let res = sema.expr_to_def(sema.resolve_expr(file_id, assignment.left())?)?; - Some(type_of_path_resolution(db, res).ty) + Some(db.type_of_path_resolution(res).ty.clone()) } fn expected_type_for_declarator_initializer( @@ -301,7 +300,7 @@ fn expected_type_for_declarator_initializer( let ident = lower_ident_opt(declarator.name())?; let container_id = sema.container_for_node(file_id, declarator.syntax())?; let res = sema.name_to_def(InContainer::new(container_id, ident))?; - Some(type_of_path_resolution(db, res).ty) + Some(db.type_of_path_resolution(res).ty.clone()) } fn is_assignment_expression(kind: SyntaxKind) -> bool { diff --git a/crates/ide/src/completion/engine/member.rs b/crates/ide/src/completion/engine/member.rs index 376d1d4a..ecc34164 100644 --- a/crates/ide/src/completion/engine/member.rs +++ b/crates/ide/src/completion/engine/member.rs @@ -1,7 +1,8 @@ use hir::{ + db::HirDb, file::HirFileId, semantics::Semantics, - type_infer::{TyMember, members_of_ty, type_of_expr, type_of_path_resolution}, + type_infer::{TyMember, members_of_ty}, }; use syntax::{ SyntaxAncestors, SyntaxNode, SyntaxNodeExt, @@ -84,7 +85,8 @@ fn members_for_incomplete_scoped_access( } let left = root.token_before_offset(separator.text_range()?.start())?; let res = sema.nameres_ident(file_id, left)?; - let members = members_of_ty(db, &type_of_path_resolution(db, res).ty); + let ty = db.type_of_path_resolution(res); + let members = members_of_ty(db, &ty.ty); (!members.is_empty()).then_some(members) } @@ -123,8 +125,8 @@ fn members_for_expr( file_id: HirFileId, expr: ast::Expression<'_>, ) -> Option> { - let ty = type_of_expr(db, sema.resolve_expr(file_id, expr)?).ty; - let members = members_of_ty(db, &ty); + let ty = db.type_of_expr(sema.resolve_expr(file_id, expr)?); + let members = members_of_ty(db, &ty.ty); (!members.is_empty()).then_some(members) } diff --git a/crates/ide/src/completion/engine/typed_filter.rs b/crates/ide/src/completion/engine/typed_filter.rs index 51baee45..3fd85613 100644 --- a/crates/ide/src/completion/engine/typed_filter.rs +++ b/crates/ide/src/completion/engine/typed_filter.rs @@ -9,9 +9,7 @@ use hir::{ }, scope::ModuleEntry, semantics::pathres::PathResolution, - type_infer::{ - Ty, TyClass, packed_bit_width, type_class, type_of_decl, type_of_path_resolution, - }, + type_infer::{Ty, TyClass, packed_bit_width, type_class}, }; use utils::get::GetRef; @@ -27,11 +25,12 @@ pub(super) fn expected_port_ty( match entry { ModuleEntry::AnsiPortEntry(_) | ModuleEntry::NonAnsiPortEntry(_) => Some( - type_of_path_resolution( - db, - PathResolution::from(hir::container::InModule::new(target_module_id, entry)), - ) - .ty, + db.type_of_path_resolution(PathResolution::from(hir::container::InModule::new( + target_module_id, + entry, + ))) + .ty + .clone(), ), _ => None, } @@ -58,7 +57,7 @@ pub(super) fn expected_param_ty( param_decl .kind .is_overridable() - .then(|| type_of_decl(db, InContainer::new(target_module_id.into(), decl_id)).ty) + .then(|| db.type_of_decl(InContainer::new(target_module_id.into(), decl_id)).ty.clone()) } pub(super) fn value_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Vec<(String, Ty)> { @@ -73,7 +72,8 @@ pub(super) fn value_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Ve | Declaration::SpecparamDecl(_) => { for decl_id in decl.decls().clone() { if let Some(name) = module.get(decl_id).name.as_ref() { - let ty = type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty; + let ty = + db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(); candidates.push((name.to_string(), ty)); } } @@ -87,7 +87,8 @@ pub(super) fn value_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Ve for (_, port_decl) in port_decls.iter() { for decl_id in port_decl.decls.clone() { if let Some(name) = module.get(decl_id).name.as_ref() { - let ty = type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty; + let ty = + db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(); candidates.push((name.to_string(), ty)); } } @@ -97,7 +98,8 @@ pub(super) fn value_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Ve for (_, port_decl) in decls.iter() { for decl_id in port_decl.decls.clone() { if let Some(name) = module.get(decl_id).name.as_ref() { - let ty = type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty; + let ty = + db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(); candidates.push((name.to_string(), ty)); } } @@ -120,7 +122,7 @@ pub(super) fn const_candidates_in_module(db: &RootDb, module_id: ModuleId) -> Ve }; for decl_id in param_decl.decls.clone() { if let Some(name) = module.get(decl_id).name.as_ref() { - let ty = type_of_decl(db, InContainer::new(module_id.into(), decl_id)).ty; + let ty = db.type_of_decl(InContainer::new(module_id.into(), decl_id)).ty.clone(); candidates.push((name.to_string(), ty)); } }