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
23 changes: 23 additions & 0 deletions crates/hir/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
literal::Literal,
module::port::{PortDirection, PortHeader},
ty::{NetKind, NetType},
typedef::TypedefId,
},
};

Expand Down Expand Up @@ -504,6 +505,28 @@ impl HirDisplay for InContainer<DeclId> {
}
}

impl HirDisplay for InContainer<TypedefId> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let InContainer { cont_id, value: typedef_id } = self;
let container = cont_id.to_container(f.db);
let typedef = container.get(*typedef_id);

f.write_str("typedef ")?;
if let Some(ty) = typedef.ty {
InContainer::new(*cont_id, ty).hir_fmt(f)?;
if typedef.name.is_some() {
f.write_str(" ")?;
}
}

if let Some(name) = &typedef.name {
f.write_str(name)?;
}

Ok(())
}
}

impl HirDisplay for InContainer<Selector> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
f.write_char('[')?;
Expand Down
24 changes: 23 additions & 1 deletion crates/hir/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,27 @@ use crate::{
},
stmt::{StmtId, StmtKind},
subroutine::{SubroutineId, SubroutineLoc, SubroutinePortId, SubroutineSrc},
typedef::TypedefId,
},
};

define_enum_deriving_from! {
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum UnitEntry {
pub enum UnitEntry {
ModuleId,
FiledDeclId,
FiledTypedefId,
}
}

pub type FiledDeclId = InFile<DeclId>;
pub type FiledTypedefId = InFile<TypedefId>;

define_enum_deriving_from! {
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum ModuleEntry {
DeclId,
TypedefId,
NonAnsiPortEntry,
AnsiPortEntry,
InstanceId,
Expand All @@ -59,6 +63,7 @@ define_enum_deriving_from! {
pub enum BlockEntry {
StmtId,
DeclId,
TypedefId,
BlockId,
}
}
Expand All @@ -68,6 +73,7 @@ define_enum_deriving_from! {
pub enum SubroutineEntry {
StmtId,
DeclId,
TypedefId,
BlockId,
SubroutinePortId,
}
Expand Down Expand Up @@ -138,6 +144,10 @@ impl UnitScope {
scope.insert_opt(&decl.name, InFile::new(file_id, decl_id).into());
}

for (typedef_id, typedef) in hir_file.typedefs.iter() {
scope.insert_opt(&typedef.name, InFile::new(file_id, typedef_id).into());
}

Arc::new(scope)
}
}
Expand Down Expand Up @@ -196,6 +206,10 @@ impl ModuleScope {
scope.insert(name, entry);
}

for (typedef_id, typedef) in module.typedefs.iter() {
scope.insert_opt(&typedef.name, typedef_id.into());
}

for (instance_id, instance) in module.instances.iter() {
scope.insert_opt(&instance.name, instance_id.into());
}
Expand All @@ -221,6 +235,10 @@ impl BlockScope {
scope.insert_opt(&decl.name, decl_id.into());
}

for (typedef_id, typedef) in block.typedefs.iter() {
scope.insert_opt(&typedef.name, typedef_id.into());
}

for (stmt_id, stmt) in block.stmts.iter() {
scope.insert_opt(&stmt.label, stmt_id.into());

Expand All @@ -247,6 +265,10 @@ impl SubroutineScope {
scope.insert_opt(&decl.name, decl_id.into());
}

for (typedef_id, typedef) in subroutine.typedefs.iter() {
scope.insert_opt(&typedef.name, typedef_id.into());
}

for (stmt_id, stmt) in subroutine.stmts.iter() {
scope.insert_opt(&stmt.label, stmt_id.into());

Expand Down
8 changes: 7 additions & 1 deletion crates/hir/src/semantics/pathres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
module::{ModuleId, instantiation::InstanceId, port::NonAnsiPortId},
stmt::StmtId,
subroutine::{SubroutineId, SubroutinePortId},
typedef::TypedefId,
},
scope::{self, BlockEntry, ModuleEntry, SubroutineEntry, UnitEntry},
};
Expand Down Expand Up @@ -85,7 +86,7 @@ impl SemanticsImpl<'_> {
let module_name = lower_ident_opt(instantiation.type_())?;
match self.db.unit_scope().get(&module_name)? {
UnitEntry::ModuleId(module_id) => Some(module_id),
UnitEntry::FiledDeclId(_) => None,
UnitEntry::FiledDeclId(_) | UnitEntry::FiledTypedefId(_) => None,
}
}

Expand All @@ -98,6 +99,7 @@ impl SemanticsImpl<'_> {
pub enum PathResolution {
Module(ModuleId),
Decl(InContainer<DeclId>),
Typedef(InContainer<TypedefId>),
ParamDecl(InModule<DeclId>),
Subroutine(SubroutineId),
SubroutinePort(InSubroutine<SubroutinePortId>),
Expand All @@ -120,6 +122,7 @@ impl From<UnitEntry> for PathResolution {
match entry {
ModuleId(idx) => Self::Module(idx),
FiledDeclId(idx) => Self::Decl(idx.into()),
FiledTypedefId(idx) => Self::Typedef(idx.into()),
}
}
}
Expand All @@ -129,6 +132,7 @@ impl From<InModule<ModuleEntry>> for PathResolution {
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)),
StmtId(idx) => Self::Stmt(entry.with_value(idx).into()),
SubroutineId(subroutine_id) => Self::Subroutine(subroutine_id),
Expand All @@ -146,6 +150,7 @@ impl From<InBlock<BlockEntry>> for PathResolution {
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),
}
Expand All @@ -157,6 +162,7 @@ impl From<InSubroutine<SubroutineEntry>> for PathResolution {
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)),
Expand Down
48 changes: 47 additions & 1 deletion crates/ide/src/completion/engine/paren_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use syntax::{
ast::{self, AstNode},
has_text_range::HasTextRange,
};
use utils::get::Get;
use utils::text_edit::TextEditItem;

use super::{
Expand Down Expand Up @@ -37,7 +38,9 @@ pub(super) fn complete_in_paren_list(
ParenListKind::ParamValueAssignment => {
complete_param_value_assignment(db, position, prefix, ctx)
}
ParenListKind::ParameterPortList => complete_parameter_port_list(prefix, ctx),
ParenListKind::ParameterPortList => {
complete_parameter_port_list_with_typedefs(db, position, prefix, ctx)
}
ParenListKind::Arguments => expr::complete_argument_exprs(db, position, prefix, ctx),
}
}
Expand Down Expand Up @@ -99,6 +102,49 @@ fn complete_parameter_port_list(prefix: &str, ctx: &CompletionContext) -> Vec<Co
items
}

fn complete_parameter_port_list_with_typedefs(
db: &RootDb,
position: FilePosition,
prefix: &str,
ctx: &CompletionContext,
) -> Vec<CompletionItem> {
let sema = Semantics::new(db);
let file = sema.parse(position.file_id);
let Some(module) =
sema.find_node_at_offset::<ast::ModuleDeclaration>(file.syntax(), position.offset)
else {
return complete_parameter_port_list(prefix, ctx);
};
let file_id = sema.find_file(module.syntax());
let (_, file_src_map) = db.hir_file_with_source_map(file_id);
let module_src = hir::hir_def::module::ModuleSrc::from(module);
let module_id = hir::hir_def::module::ModuleId::new(file_id, file_src_map.get(module_src));

let mut items: Vec<CompletionItem> = db
.unit_scope()
.iter()
.filter_map(|(ident, entry)| {
matches!(entry, hir::scope::UnitEntry::FiledTypedefId(_)).then_some(ident)
})
.chain(db.module_scope(module_id).iter().filter_map(|(ident, entry)| {
matches!(entry, hir::scope::ModuleEntry::TypedefId(_)).then_some(ident)
}))
.map(|ident| ident.to_string())
.filter(|name| name.starts_with(prefix))
.map(|name| CompletionItem {
label: name.clone(),
kind: CompletionItemKind::Text,
edit: Some(TextEditItem::replace(ctx.replacement, name)),
snippet_edit: None,
})
.collect();

items.sort_by(|a, b| a.label.cmp(&b.label));
items.dedup_by(|a, b| a.label == b.label);
items.extend(complete_parameter_port_list(prefix, ctx));
items
}

fn complete_port_connections(
db: &RootDb,
position: FilePosition,
Expand Down
60 changes: 55 additions & 5 deletions crates/ide/src/completion/engine/port_list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use hir::{
db::HirDb,
hir_def::module::{ModuleId, ModuleSrc},
scope::{ModuleEntry, UnitEntry},
semantics::Semantics,
};
use ide_db::root_db::RootDb;
Expand All @@ -19,28 +20,77 @@ pub(super) fn complete_in_port_list(
kind: PortListKind,
) -> Vec<CompletionItem> {
match kind {
PortListKind::Ansi => complete_ansi_port_list(prefix, ctx),
PortListKind::Ansi => complete_ansi_port_list(db, position, prefix, ctx),
PortListKind::NonAnsi => complete_non_ansi_port_list(db, position, prefix, ctx),
}
}

fn complete_ansi_port_list(prefix: &str, ctx: &CompletionContext) -> Vec<CompletionItem> {
fn complete_ansi_port_list(
db: &RootDb,
position: FilePosition,
prefix: &str,
ctx: &CompletionContext,
) -> Vec<CompletionItem> {
let keywords = [
"input", "output", "inout", "wire", "reg", "tri", "tri0", "tri1", "trireg", "triand",
"trior", "wand", "wor", "supply0", "supply1", "integer", "real", "realtime", "time",
"signed", "unsigned",
];

keywords
let mut items = visible_typedefs_in_module_header(db, position)
.into_iter()
.filter(|name| name.starts_with(prefix))
.map(|name| CompletionItem {
label: name.clone(),
kind: CompletionItemKind::Text,
edit: Some(TextEditItem::replace(ctx.replacement, name)),
snippet_edit: None,
})
.collect::<Vec<_>>();

items.extend(keywords
.iter()
.filter(|kw| kw.starts_with(prefix))
.map(|kw| CompletionItem {
label: (*kw).to_string(),
kind: CompletionItemKind::Keyword,
edit: Some(TextEditItem::replace(ctx.replacement, (*kw).to_string())),
snippet_edit: None,
})
.collect()
}));

items
}

fn visible_typedefs_in_module_header(db: &RootDb, position: FilePosition) -> Vec<String> {
let sema = Semantics::new(db);
let file = sema.parse(position.file_id);
let root = file.syntax();
let module = sema.find_node_at_offset::<ast::ModuleDeclaration>(root, position.offset);
let Some(module) = module else {
return Vec::new();
};
let file_id = sema.find_file(module.syntax());
let (_, file_src_map) = db.hir_file_with_source_map(file_id);
let module_src = ModuleSrc::from(module);
let module_id = ModuleId::new(file_id, file_src_map.get(module_src));

let mut names: Vec<String> = db
.unit_scope()
.iter()
.filter_map(|(ident, entry)| matches!(entry, UnitEntry::FiledTypedefId(_)).then_some(ident))
.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.sort();
names.dedup();
names
}

fn complete_non_ansi_port_list(
Expand Down
Loading
Loading