Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions crates/hir/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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) {
Expand Down Expand Up @@ -120,6 +130,21 @@ pub trait HirDb: InternDb {

#[salsa::invoke(SubroutineScope::subroutine_scope_query)]
fn subroutine_scope(&self, subroutine_id: SubroutineId) -> Arc<SubroutineScope>;

#[salsa::invoke(crate::type_infer::type_of_decl_query)]
fn type_of_decl(&self, decl: InContainer<DeclId>) -> Arc<TyResult>;

#[salsa::invoke(crate::type_infer::type_of_typedef_query)]
fn type_of_typedef(&self, typedef: InContainer<TypedefId>) -> Arc<TyResult>;

#[salsa::invoke(crate::type_infer::type_of_expr_query)]
fn type_of_expr(&self, expr: InContainer<ExprId>) -> Arc<TyResult>;

#[salsa::invoke(crate::type_infer::type_of_path_resolution_query)]
fn type_of_path_resolution(&self, res: PathResolution) -> Arc<TyResult>;

#[salsa::invoke(crate::type_infer::type_of_subroutine_port_query)]
fn type_of_subroutine_port(&self, port: InSubroutine<SubroutinePortId>) -> Arc<TyResult>;
}

fn parse(db: &dyn HirDb, file_id: HirFileId) -> SyntaxTree {
Expand Down
2 changes: 1 addition & 1 deletion crates/hir/src/semantics/pathres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConfigDeclId>),
Expand Down
63 changes: 45 additions & 18 deletions crates/hir/src/type_infer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_hash::FxHashSet;
use triomphe::Arc;
use utils::get::GetRef;

use crate::{
Expand Down Expand Up @@ -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<TyInferDiagnostic>,
Expand Down Expand Up @@ -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<TypedefId>) -> TyResult {
pub(crate) fn type_of_typedef_query(
db: &dyn HirDb,
typedef: InContainer<TypedefId>,
) -> Arc<TyResult> {
Arc::new(type_of_typedef_impl(db, typedef))
}

pub(crate) fn type_of_decl_query(db: &dyn HirDb, decl: InContainer<DeclId>) -> Arc<TyResult> {
Arc::new(type_of_decl_impl(db, decl))
}

pub(crate) fn type_of_path_resolution_query(db: &dyn HirDb, res: PathResolution) -> Arc<TyResult> {
Arc::new(type_of_path_resolution_impl(db, res))
}

pub(crate) fn type_of_expr_query(db: &dyn HirDb, expr: InContainer<ExprId>) -> Arc<TyResult> {
Arc::new(type_of_expr_impl(db, expr))
}

pub(crate) fn type_of_subroutine_port_query(
db: &dyn HirDb,
port: InSubroutine<SubroutinePortId>,
) -> Arc<TyResult> {
Arc::new(type_of_subroutine_port_impl(db, port))
}

fn type_of_typedef_impl(db: &dyn HirDb, typedef: InContainer<TypedefId>) -> TyResult {
type_of_typedef_inner(db, typedef, &mut FxHashSet::default())
}

pub fn type_of_decl(db: &dyn HirDb, decl: InContainer<DeclId>) -> TyResult {
fn type_of_decl_impl(db: &dyn HirDb, decl: InContainer<DeclId>) -> 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)))
Expand All @@ -116,28 +143,28 @@ pub fn type_of_path_resolution(db: &dyn HirDb, res: PathResolution) -> TyResult
}
}

pub fn type_of_expr(db: &dyn HirDb, expr: InContainer<ExprId>) -> TyResult {
fn type_of_expr_impl(db: &dyn HirDb, expr: InContainer<ExprId>) -> 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;
}
let mut selected = select_member(db, &base.ty, &field);
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),
}
Expand Down Expand Up @@ -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),
}
}
Expand Down Expand Up @@ -336,7 +363,7 @@ fn module_members(db: &dyn HirDb, module_id: ModuleId) -> Vec<TyMember> {
.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();
Expand All @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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<SubroutinePortId>) -> TyResult {
fn type_of_subroutine_port_impl(db: &dyn HirDb, port: InSubroutine<SubroutinePortId>) -> TyResult {
let subroutine = db.subroutine(port.subroutine);
let port_id = port;
let Some(port) = subroutine.ports.get(port_id.value.0 as usize) else {
Expand Down
8 changes: 5 additions & 3 deletions crates/ide/src/code_action/handlers/extract_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -176,7 +177,8 @@ fn trim_range(text: &str, range: TextRange) -> Option<TextRange> {
}

fn extracted_variable_type(ctx: &CodeActionCtx<'_>, expr: ast::Expression<'_>) -> Option<String> {
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)))
}
Expand All @@ -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<String> {
Expand Down
43 changes: 21 additions & 22 deletions crates/ide/src/completion/engine/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) => {
Expand All @@ -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(),
});
}
}
Expand All @@ -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 });
}
_ => {}
Expand All @@ -176,11 +174,10 @@ fn collect_file_names(db: &RootDb, file_id: HirFileId, names: &mut BTreeMap<Stri
for (ident, entry) in scope.iter() {
if let UnitEntry::FiledDeclId(decl_id) = entry {
names.entry(ident.to_string()).or_insert(NameKind::Value {
ty: type_of_decl(
db,
InContainer::new(ContainerId::HirFileId(file_id), decl_id.value),
)
.ty,
ty: db
.type_of_decl(InContainer::new(ContainerId::HirFileId(file_id), decl_id.value))
.ty
.clone(),
});
}
}
Expand All @@ -192,18 +189,20 @@ fn collect_module_names(db: &RootDb, module_id: ModuleId, names: &mut BTreeMap<S
match entry {
ModuleEntry::DeclId(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::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 });
}
Expand Down Expand Up @@ -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(
Expand All @@ -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 {
Expand Down
10 changes: 6 additions & 4 deletions crates/ide/src/completion/engine/member.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -123,8 +125,8 @@ fn members_for_expr(
file_id: HirFileId,
expr: ast::Expression<'_>,
) -> Option<Vec<TyMember>> {
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)
}

Expand Down
Loading
Loading