1
- use crate :: expression:: { Expr , Noop , Resolved } ;
1
+ use crate :: expression:: { self , Expr , Noop , Resolved } ;
2
2
use crate :: parser:: { ast, Node } ;
3
3
use crate :: { value, Context , Expression , State , TypeDef , Value } ;
4
- use diagnostic:: { DiagnosticError , Label , Span } ;
4
+ use diagnostic:: { DiagnosticError , Label , Note , Span } ;
5
5
use std:: fmt;
6
6
7
7
#[ derive( Clone , PartialEq ) ]
@@ -12,20 +12,42 @@ pub struct Op {
12
12
}
13
13
14
14
impl Op {
15
- pub fn new ( lhs : Expr , opcode : Node < ast:: Opcode > , rhs : Expr ) -> Result < Self , Error > {
16
- use ast:: Opcode :: * ;
15
+ pub fn new (
16
+ lhs : Node < Expr > ,
17
+ opcode : Node < ast:: Opcode > ,
18
+ rhs : Node < Expr > ,
19
+ state : & State ,
20
+ ) -> Result < Self , Error > {
21
+ use ast:: Opcode :: { Eq , Ge , Gt , Le , Lt , Ne } ;
22
+
23
+ let ( op_span, opcode) = opcode. take ( ) ;
24
+
25
+ let ( lhs_span, lhs) = lhs. take ( ) ;
26
+ let lhs_type_def = lhs. type_def ( state) ;
17
27
18
- let ( span, opcode) = opcode. take ( ) ;
28
+ let ( rhs_span, rhs) = rhs. take ( ) ;
29
+ let rhs_type_def = rhs. type_def ( state) ;
19
30
20
31
if matches ! ( opcode, Eq | Ne | Lt | Le | Gt | Ge ) {
21
32
if let Expr :: Op ( op) = & lhs {
22
33
if matches ! ( op. opcode, Eq | Ne | Lt | Le | Gt | Ge ) {
23
- let error = Error :: ChainedComparison { span } ;
24
- return std:: result:: Result :: Err ( error) ;
34
+ return Err ( Error :: ChainedComparison { span : op_span } ) ;
25
35
}
26
36
}
27
37
}
28
38
39
+ if let ast:: Opcode :: Err = opcode {
40
+ if lhs_type_def. is_infallible ( ) {
41
+ return Err ( Error :: ErrInfallible {
42
+ lhs_span,
43
+ rhs_span,
44
+ op_span,
45
+ } ) ;
46
+ } else if rhs_type_def. is_fallible ( ) {
47
+ return Err ( expression:: Error :: Fallible { span : rhs_span } . into ( ) ) ;
48
+ }
49
+ }
50
+
29
51
Ok ( Op {
30
52
lhs : Box :: new ( lhs) ,
31
53
rhs : Box :: new ( rhs) ,
@@ -85,11 +107,13 @@ impl Expression for Op {
85
107
86
108
let lhs_kind = lhs_def. kind ( ) ;
87
109
let rhs_kind = rhs_def. kind ( ) ;
88
- let merged_kind = merged_def. kind ( ) ;
89
110
90
111
match self . opcode {
91
- // null || null
92
- Or if merged_kind. is_null ( ) => TypeDef :: new ( ) . infallible ( ) . null ( ) ,
112
+ // ok/err ?? ok
113
+ Err if rhs_def. is_infallible ( ) => merged_def. infallible ( ) ,
114
+
115
+ // ... ?? ...
116
+ Err => merged_def,
93
117
94
118
// null || ...
95
119
Or if lhs_kind. is_null ( ) => rhs_def,
@@ -107,15 +131,6 @@ impl Expression for Op {
107
131
// ... || ...
108
132
Or => merged_def,
109
133
110
- // ok ?? ...
111
- Err if lhs_def. is_infallible ( ) => lhs_def,
112
-
113
- // ok/err ?? ok
114
- Err if rhs_def. is_infallible ( ) => merged_def. infallible ( ) ,
115
-
116
- // ... ?? ...
117
- Err => merged_def,
118
-
119
134
// null && ...
120
135
And if lhs_kind. is_null ( ) => rhs_def. scalar ( K :: Boolean ) ,
121
136
@@ -162,18 +177,14 @@ impl Expression for Op {
162
177
// 1 * 1
163
178
// 1 % 1
164
179
Add | Sub | Mul | Rem if lhs_kind. is_integer ( ) && rhs_kind. is_integer ( ) => {
165
- merged_def. infallible ( ) . scalar ( K :: Integer )
180
+ merged_def. scalar ( K :: Integer )
166
181
}
167
182
168
183
// "bar" * 1
169
- Mul if lhs_kind. is_bytes ( ) && rhs_kind. is_integer ( ) => {
170
- merged_def. infallible ( ) . scalar ( K :: Bytes )
171
- }
184
+ Mul if lhs_kind. is_bytes ( ) && rhs_kind. is_integer ( ) => merged_def. scalar ( K :: Bytes ) ,
172
185
173
186
// 1 * "bar"
174
- Mul if lhs_kind. is_integer ( ) && rhs_kind. is_bytes ( ) => {
175
- merged_def. infallible ( ) . scalar ( K :: Bytes )
176
- }
187
+ Mul if lhs_kind. is_integer ( ) && rhs_kind. is_bytes ( ) => merged_def. scalar ( K :: Bytes ) ,
177
188
178
189
// ... + ...
179
190
// ... * ...
@@ -206,6 +217,16 @@ impl fmt::Debug for Op {
206
217
pub enum Error {
207
218
#[ error( "comparison operators cannot be chained" ) ]
208
219
ChainedComparison { span : Span } ,
220
+
221
+ #[ error( "unneeded error-coalesce operation" ) ]
222
+ ErrInfallible {
223
+ lhs_span : Span ,
224
+ rhs_span : Span ,
225
+ op_span : Span ,
226
+ } ,
227
+
228
+ #[ error( "fallible operation" ) ]
229
+ Expr ( #[ from] expression:: Error ) ,
209
230
}
210
231
211
232
impl DiagnosticError for Error {
@@ -214,6 +235,17 @@ impl DiagnosticError for Error {
214
235
215
236
match self {
216
237
ChainedComparison { .. } => 650 ,
238
+ ErrInfallible { .. } => 651 ,
239
+ Expr ( err) => err. code ( ) ,
240
+ }
241
+ }
242
+
243
+ fn message ( & self ) -> String {
244
+ use Error :: * ;
245
+
246
+ match self {
247
+ Expr ( err) => err. message ( ) ,
248
+ err => err. to_string ( ) ,
217
249
}
218
250
}
219
251
@@ -222,6 +254,25 @@ impl DiagnosticError for Error {
222
254
223
255
match self {
224
256
ChainedComparison { span } => vec ! [ Label :: primary( "" , span) ] ,
257
+ ErrInfallible {
258
+ lhs_span,
259
+ rhs_span,
260
+ op_span,
261
+ } => vec ! [
262
+ Label :: primary( "this expression cannot fail" , lhs_span) ,
263
+ Label :: context( "this expression never resolves" , rhs_span) ,
264
+ Label :: context( "remove this error coalesce operation" , op_span) ,
265
+ ] ,
266
+ Expr ( err) => err. labels ( ) ,
267
+ }
268
+ }
269
+
270
+ fn notes ( & self ) -> Vec < Note > {
271
+ use Error :: * ;
272
+
273
+ match self {
274
+ Expr ( err) => err. notes ( ) ,
275
+ _ => vec ! [ ] ,
225
276
}
226
277
}
227
278
}
@@ -389,20 +440,6 @@ mod tests {
389
440
want: TypeDef :: new( ) . fallible( ) . boolean( ) ,
390
441
}
391
442
392
- error_or_lhs_infallible {
393
- expr: |_| Op {
394
- lhs: Box :: new( Literal :: from( "foo" ) . into( ) ) ,
395
- rhs: Box :: new( Op {
396
- lhs: Box :: new( Literal :: from( "foo" ) . into( ) ) ,
397
- rhs: Box :: new( Literal :: from( 1 ) . into( ) ) ,
398
- opcode: Div ,
399
- } . into( ) ,
400
- ) ,
401
- opcode: Err ,
402
- } ,
403
- want: TypeDef :: new( ) . bytes( ) ,
404
- }
405
-
406
443
error_or_rhs_infallible {
407
444
expr: |_| Op {
408
445
lhs: Box :: new( Op {
0 commit comments