1
1
use crate :: data:: diagnostic:: { Diagnostic , DiagnosticAddable , DiagnosticBuilder , Diagnostics , ErrorGuaranteed } ;
2
2
use crate :: new:: block:: TypedIrExpression ;
3
3
use crate :: new:: compile:: CompileState ;
4
- use crate :: new:: misc:: { DomainSignal , ValueDomain } ;
4
+ use crate :: new:: misc:: ValueDomain ;
5
5
use crate :: new:: types:: { ClosedIncRange , HardwareType , IncRange , Type } ;
6
6
use crate :: new:: value:: { CompileValue , MaybeCompile } ;
7
7
use crate :: syntax:: ast:: { Spanned , SyncDomain } ;
8
8
use crate :: syntax:: pos:: Span ;
9
- use crate :: throw;
10
9
use annotate_snippets:: Level ;
11
10
use num_bigint:: BigInt ;
12
11
13
12
impl CompileState < ' _ > {
14
13
pub fn check_valid_domain_crossing (
15
14
& self ,
16
- assignment_span : Span ,
15
+ crossing_span : Span ,
17
16
target : Spanned < & ValueDomain > ,
18
17
source : Spanned < & ValueDomain > ,
19
18
required_reason : & str ,
20
19
) -> Result < ( ) , ErrorGuaranteed > {
21
20
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 ( ( ) ) ,
26
22
( ValueDomain :: Clock , _) => Err ( "non-clock to clock" ) ,
27
23
( ValueDomain :: Sync ( _) , ValueDomain :: Clock ) => Err ( "clock to sync" ) ,
28
24
( ValueDomain :: Sync ( _) , ValueDomain :: Async ) => Err ( "async to sync" ) ,
@@ -56,69 +52,61 @@ impl CompileState<'_> {
56
52
} ;
57
53
58
54
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 ) ;
61
57
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" )
63
59
. add_info ( target. span , format ! ( "target domain is {target_str}" ) )
64
60
. add_info ( source. span , format ! ( "source domain is {source_str}" ) )
65
61
. footer ( Level :: Info , required_reason)
66
62
. finish ( ) ;
67
63
self . diags . report ( diag)
68
64
} )
69
65
}
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
- }
95
66
}
96
67
97
68
#[ derive( Debug , Copy , Clone ) ]
98
69
pub enum TypeContainsReason {
99
70
Assignment {
100
- span_assignment : Span ,
71
+ span_target : Span ,
101
72
span_target_ty : Span ,
102
73
} ,
103
74
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 } ,
104
78
}
105
79
106
80
impl TypeContainsReason {
107
81
pub fn add_diag_info ( self , diag : DiagnosticBuilder , target_ty : & Type ) -> DiagnosticBuilder {
82
+ let target_ty_str = target_ty. to_diagnostic_string ( ) ;
108
83
match self {
84
+ // TODO improve assignment error message
109
85
TypeContainsReason :: Assignment {
110
- span_assignment ,
86
+ span_target ,
111
87
span_target_ty,
112
88
} => diag
113
- . add_info ( span_assignment , "assignment requires type match" )
89
+ . add_info ( span_target , format ! ( "target requires type `{}`" , target_ty_str ) )
114
90
. add_info (
115
91
span_target_ty,
116
- format ! ( "target type `{}` set here" , target_ty . to_diagnostic_string ( ) ) ,
92
+ format ! ( "target type `{}` set here" , target_ty_str ) ,
117
93
) ,
118
94
TypeContainsReason :: Operator ( span) => diag. add_info (
119
95
span,
120
- format ! ( "operator requires type `{}`" , target_ty . to_diagnostic_string ( ) ) ,
96
+ format ! ( "operator requires type `{}`" , target_ty_str ) ,
121
97
) ,
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
+ }
122
110
}
123
111
}
124
112
}
@@ -139,23 +127,11 @@ pub fn check_type_contains_value(
139
127
check_type_contains_compile_value ( diags, reason, target_ty, value, accept_undefined)
140
128
}
141
129
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)
159
135
}
160
136
}
161
137
}
@@ -179,7 +155,7 @@ pub fn check_type_contains_compile_value(
179
155
. add_error (
180
156
value. span ,
181
157
format ! (
182
- "source value `{}` here does not fit" ,
158
+ "source value `{}` does not fit" ,
183
159
value. inner. to_diagnostic_string( )
184
160
) ,
185
161
)
@@ -188,6 +164,30 @@ pub fn check_type_contains_compile_value(
188
164
}
189
165
}
190
166
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
+
191
191
// TODO reduce boilerplate with a trait?
192
192
pub fn check_type_is_int (
193
193
diags : & Diagnostics ,
0 commit comments