Skip to content

Commit b482ab4

Browse files
committed
Implement module instance in frontend.
1 parent 5366130 commit b482ab4

File tree

16 files changed

+878
-356
lines changed

16 files changed

+878
-356
lines changed

design/project/std/types.kh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
// TODO allow signature declarations for everything, even types!
2+
// TODO switch to consistent capital for types, lowercase for variables/signals?
23

34
// Basic types
45
pub type any = __builtin("type", "any");
56

67
// TODO bool should be an enum :)
78
pub type bool = __builtin("type", "bool");
89

10+
pub type Range = __builtin("type", "Range");
11+
912
// TODO what is the difference if anything between "type" and "const" for types?
1013
//const bool: type = __builtin("type", );
1114

rust/hwl_language/src/data/diagnostic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl Diagnostics {
7070
self.report(Diagnostic::new_simple(title, span, label))
7171
}
7272

73+
#[track_caller]
7374
pub fn report_todo(&self, span: Span, feature: impl Into<String>) -> ErrorGuaranteed {
7475
self.report(Diagnostic::new_todo(span, feature))
7576
}

rust/hwl_language/src/data/parsed.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::data::diagnostic::{Diagnostics, ErrorGuaranteed};
22
use crate::data::source::SourceDatabase;
3-
use crate::syntax::ast::{FileContent, Identifier, ModulePortInBlock, ModulePortSingle, PortKind, Spanned};
3+
use crate::syntax::ast::{FileContent, Identifier, ModulePortInBlock, ModulePortSingle, Spanned, WireKind};
44
use crate::syntax::pos::{FileId, Span};
55
use crate::syntax::{ast, parse_error_to_diagnostic, parse_file_content};
66
use crate::util::data::IndexMapExt;
@@ -150,8 +150,8 @@ impl<'a> ModulePort<'a> {
150150
pub fn ty_span(self) -> Span {
151151
match self {
152152
ModulePort::Single(port) => match &port.kind.inner {
153-
PortKind::Clock => port.kind.span,
154-
PortKind::Normal { domain: _, ty } => ty.span,
153+
WireKind::Clock => port.kind.span,
154+
WireKind::Normal { domain: _, ty } => ty.span,
155155
},
156156
ModulePort::InBlock(port) => port.ty.span,
157157
}

rust/hwl_language/src/new/block.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl CompileState<'_> {
176176
if let Some(ty) = &ty {
177177
if let Some(init) = &init {
178178
let reason = TypeContainsReason::Assignment {
179-
span_assignment: stmt.span,
179+
span_target: id.span(),
180180
span_target_ty: ty.span,
181181
};
182182
check_type_contains_value(diags, reason, &ty.inner, init.as_ref(), true)?;
@@ -343,7 +343,7 @@ impl CompileState<'_> {
343343
}
344344
AssignmentTarget::Wire(wire) => {
345345
let info = &self.wires[wire];
346-
let domain = ValueDomain::from_domain_kind(info.domain.inner.clone());
346+
let domain = info.domain.inner.clone();
347347
(&info.ty, domain, IrAssignmentTarget::Wire(info.ir))
348348
}
349349
AssignmentTarget::Register(reg) => {
@@ -366,7 +366,7 @@ impl CompileState<'_> {
366366
// check type
367367
if let Some(ty) = ty {
368368
let reason = TypeContainsReason::Assignment {
369-
span_assignment: stmt.span,
369+
span_target: id.span(),
370370
span_target_ty: ty.span,
371371
};
372372
check_type_contains_value(diags, reason, &ty.inner, value.as_ref(), true)?;
@@ -407,7 +407,7 @@ impl CompileState<'_> {
407407

408408
// check type
409409
let reason = TypeContainsReason::Assignment {
410-
span_assignment: stmt.span,
410+
span_target: target.span,
411411
span_target_ty: target_ty.span,
412412
};
413413
let target_ty = target_ty.inner.as_type();

rust/hwl_language/src/new/check.rs

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
use crate::data::diagnostic::{Diagnostic, DiagnosticAddable, DiagnosticBuilder, Diagnostics, ErrorGuaranteed};
22
use crate::new::block::TypedIrExpression;
33
use crate::new::compile::CompileState;
4-
use crate::new::misc::{DomainSignal, ValueDomain};
4+
use crate::new::misc::ValueDomain;
55
use crate::new::types::{ClosedIncRange, HardwareType, IncRange, Type};
66
use crate::new::value::{CompileValue, MaybeCompile};
77
use crate::syntax::ast::{Spanned, SyncDomain};
88
use crate::syntax::pos::Span;
9-
use crate::throw;
109
use annotate_snippets::Level;
1110
use num_bigint::BigInt;
1211

1312
impl CompileState<'_> {
1413
pub fn check_valid_domain_crossing(
1514
&self,
16-
assignment_span: Span,
15+
crossing_span: Span,
1716
target: Spanned<&ValueDomain>,
1817
source: Spanned<&ValueDomain>,
1918
required_reason: &str,
2019
) -> Result<(), ErrorGuaranteed> {
2120
let valid = match (target.inner, source.inner) {
22-
// clock only clock, and even that is not yet supported
23-
(ValueDomain::Clock, ValueDomain::Clock) => {
24-
throw!(self.diags.report_todo(assignment_span, "clock assignments"))
25-
}
21+
(ValueDomain::Clock, ValueDomain::Clock) => Ok(()),
2622
(ValueDomain::Clock, _) => Err("non-clock to clock"),
2723
(ValueDomain::Sync(_), ValueDomain::Clock) => Err("clock to sync"),
2824
(ValueDomain::Sync(_), ValueDomain::Async) => Err("async to sync"),
@@ -56,69 +52,61 @@ impl CompileState<'_> {
5652
};
5753

5854
valid.map_err(|invalid_reason| {
59-
let target_str = self.value_domain_to_diagnostic_string(&target.inner);
60-
let source_str = self.value_domain_to_diagnostic_string(source.inner);
55+
let target_str = target.inner.to_diagnostic_string(self);
56+
let source_str = source.inner.to_diagnostic_string(self);
6157
let diag = Diagnostic::new(format!("invalid domain crossing: {invalid_reason}"))
62-
.add_error(assignment_span, "invalid domain crossing here")
58+
.add_error(crossing_span, "invalid domain crossing here")
6359
.add_info(target.span, format!("target domain is {target_str}"))
6460
.add_info(source.span, format!("source domain is {source_str}"))
6561
.footer(Level::Info, required_reason)
6662
.finish();
6763
self.diags.report(diag)
6864
})
6965
}
70-
71-
fn value_domain_to_diagnostic_string(&self, domain: &ValueDomain) -> String {
72-
match domain {
73-
ValueDomain::CompileTime => "compile-time".to_string(),
74-
ValueDomain::Clock => "clock".to_string(),
75-
ValueDomain::Async => "async".to_string(),
76-
ValueDomain::Sync(sync) => {
77-
let SyncDomain { clock, reset } = sync;
78-
format!(
79-
"sync({}, {})",
80-
self.domain_signal_to_diagnostic_string(clock),
81-
self.domain_signal_to_diagnostic_string(reset),
82-
)
83-
}
84-
}
85-
}
86-
87-
fn domain_signal_to_diagnostic_string(&self, signal: &DomainSignal) -> String {
88-
match signal {
89-
&DomainSignal::Port(port) => self.ports[port].id.string.clone(),
90-
&DomainSignal::Wire(wire) => self.wires[wire].id.string().to_string(),
91-
&DomainSignal::Register(reg) => self.registers[reg].id.string().to_string(),
92-
DomainSignal::BoolNot(signal) => format!("!{}", self.domain_signal_to_diagnostic_string(signal)),
93-
}
94-
}
9566
}
9667

9768
#[derive(Debug, Copy, Clone)]
9869
pub enum TypeContainsReason {
9970
Assignment {
100-
span_assignment: Span,
71+
span_target: Span,
10172
span_target_ty: Span,
10273
},
10374
Operator(Span),
75+
InstanceModule(Span),
76+
InstancePortInput { span_connection_port_id: Span, span_port_ty: Span },
77+
InstancePortOutput { span_connection_signal_id: Span, span_signal_ty: Span },
10478
}
10579

10680
impl TypeContainsReason {
10781
pub fn add_diag_info(self, diag: DiagnosticBuilder, target_ty: &Type) -> DiagnosticBuilder {
82+
let target_ty_str = target_ty.to_diagnostic_string();
10883
match self {
84+
// TODO improve assignment error message
10985
TypeContainsReason::Assignment {
110-
span_assignment,
86+
span_target,
11187
span_target_ty,
11288
} => diag
113-
.add_info(span_assignment, "assignment requires type match")
89+
.add_info(span_target, format!("target requires type `{}`", target_ty_str))
11490
.add_info(
11591
span_target_ty,
116-
format!("target type `{}` set here", target_ty.to_diagnostic_string()),
92+
format!("target type `{}` set here", target_ty_str),
11793
),
11894
TypeContainsReason::Operator(span) => diag.add_info(
11995
span,
120-
format!("operator requires type `{}`", target_ty.to_diagnostic_string()),
96+
format!("operator requires type `{}`", target_ty_str),
12197
),
98+
TypeContainsReason::InstanceModule(span) => diag.add_info(
99+
span,
100+
format!("module instance requires `{}`", target_ty_str),
101+
),
102+
TypeContainsReason::InstancePortInput { span_connection_port_id, span_port_ty } => {
103+
diag.add_info(span_connection_port_id, format!("input port has type `{}`", target_ty_str))
104+
.add_info(span_port_ty, "port type set here")
105+
}
106+
TypeContainsReason::InstancePortOutput { span_connection_signal_id, span_signal_ty } => {
107+
diag.add_info(span_connection_signal_id, format!("target signal has type `{}`", target_ty_str))
108+
.add_info(span_signal_ty, "target signal type set here")
109+
}
122110
}
123111
}
124112
}
@@ -139,23 +127,11 @@ pub fn check_type_contains_value(
139127
check_type_contains_compile_value(diags, reason, target_ty, value, accept_undefined)
140128
}
141129
MaybeCompile::Other(value_inner) => {
142-
let value_ty = value_inner.ty.as_type();
143-
if target_ty.contains_type(&value_ty) {
144-
Ok(())
145-
} else {
146-
let mut diag = Diagnostic::new("type does not fit in type");
147-
diag = reason.add_diag_info(diag, target_ty);
148-
let diag = diag
149-
.add_error(
150-
value.span,
151-
format!(
152-
"source value with type `{}` does not fit",
153-
value_ty.to_diagnostic_string()
154-
),
155-
)
156-
.finish();
157-
Err(diags.report(diag))
158-
}
130+
let value_ty = Spanned {
131+
span: value.span,
132+
inner: &value_inner.ty.as_type(),
133+
};
134+
check_type_contains_type(diags, reason, target_ty, value_ty)
159135
}
160136
}
161137
}
@@ -179,7 +155,7 @@ pub fn check_type_contains_compile_value(
179155
.add_error(
180156
value.span,
181157
format!(
182-
"source value `{}` here does not fit",
158+
"source value `{}` does not fit",
183159
value.inner.to_diagnostic_string()
184160
),
185161
)
@@ -188,6 +164,30 @@ pub fn check_type_contains_compile_value(
188164
}
189165
}
190166

167+
pub fn check_type_contains_type(
168+
diags: &Diagnostics,
169+
reason: TypeContainsReason,
170+
target_ty: &Type,
171+
value_ty: Spanned<&Type>,
172+
) -> Result<(), ErrorGuaranteed> {
173+
if target_ty.contains_type(value_ty.inner) {
174+
Ok(())
175+
} else {
176+
let mut diag = Diagnostic::new("value does not fit in type");
177+
diag = reason.add_diag_info(diag, target_ty);
178+
let diag = diag
179+
.add_error(
180+
value_ty.span,
181+
format!(
182+
"source value with type `{}` does not fit",
183+
value_ty.inner.to_diagnostic_string()
184+
),
185+
)
186+
.finish();
187+
Err(diags.report(diag))
188+
}
189+
}
190+
191191
// TODO reduce boilerplate with a trait?
192192
pub fn check_type_is_int(
193193
diags: &Diagnostics,

0 commit comments

Comments
 (0)