15
15
*/
16
16
17
17
use crate :: ast:: * ;
18
+ use crate :: parser:: Loc ;
18
19
use itertools:: Itertools ;
19
- use miette:: Diagnostic ;
20
+ use miette:: { Diagnostic , LabeledSpan } ;
20
21
use nonempty:: { nonempty, NonEmpty } ;
21
22
use smol_str:: SmolStr ;
22
23
use std:: sync:: Arc ;
@@ -30,10 +31,13 @@ pub struct EvaluationError {
30
31
error_kind : EvaluationErrorKind ,
31
32
/// Optional advice on how to fix the error
32
33
advice : Option < String > ,
34
+ /// Source location of the error. (This overrides other sources if present,
35
+ /// but if this is `None`, we'll check for location info in the
36
+ /// `.error_kind`.)
37
+ source_loc : Option < Loc > ,
33
38
}
34
39
35
- // custom impl of `Diagnostic`: non-trivial implementation of `help()`,
36
- // everything else forwarded to `.error_kind`
40
+ // custom impl of `Diagnostic`
37
41
impl Diagnostic for EvaluationError {
38
42
fn help < ' a > ( & ' a self ) -> Option < Box < dyn std:: fmt:: Display + ' a > > {
39
43
match ( self . error_kind . help ( ) , self . advice . as_ref ( ) ) {
@@ -44,6 +48,23 @@ impl Diagnostic for EvaluationError {
44
48
}
45
49
}
46
50
51
+ fn source_code ( & self ) -> Option < & dyn miette:: SourceCode > {
52
+ self . source_loc
53
+ . as_ref ( )
54
+ . map ( |loc| & loc. src as & dyn miette:: SourceCode )
55
+ . or_else ( || self . error_kind . source_code ( ) )
56
+ }
57
+
58
+ fn labels ( & self ) -> Option < Box < dyn Iterator < Item = miette:: LabeledSpan > + ' _ > > {
59
+ self . source_loc
60
+ . as_ref ( )
61
+ . map ( |loc| {
62
+ Box :: new ( std:: iter:: once ( LabeledSpan :: underline ( loc. span ) ) )
63
+ as Box < dyn Iterator < Item = _ > >
64
+ } )
65
+ . or_else ( || self . error_kind . labels ( ) )
66
+ }
67
+
47
68
fn code < ' a > ( & ' a self ) -> Option < Box < dyn std:: fmt:: Display + ' a > > {
48
69
self . error_kind . code ( )
49
70
}
@@ -56,14 +77,6 @@ impl Diagnostic for EvaluationError {
56
77
self . error_kind . url ( )
57
78
}
58
79
59
- fn source_code ( & self ) -> Option < & dyn miette:: SourceCode > {
60
- self . error_kind . source_code ( )
61
- }
62
-
63
- fn labels ( & self ) -> Option < Box < dyn Iterator < Item = miette:: LabeledSpan > + ' _ > > {
64
- self . error_kind . labels ( )
65
- }
66
-
67
80
fn diagnostic_source ( & self ) -> Option < & dyn Diagnostic > {
68
81
self . error_kind . diagnostic_source ( )
69
82
}
@@ -79,137 +92,188 @@ impl EvaluationError {
79
92
& self . error_kind
80
93
}
81
94
95
+ /// Extract the source location of the error, if one is attached
96
+ pub fn source_loc ( & self ) -> Option < & Loc > {
97
+ self . source_loc . as_ref ( )
98
+ }
99
+
100
+ /// Extract the advice attached to the error, if any
101
+ pub fn advice ( & self ) -> Option < & str > {
102
+ self . advice . as_deref ( )
103
+ }
104
+
82
105
/// Set the advice field of an error
83
106
pub fn set_advice ( & mut self , advice : String ) {
84
107
self . advice = Some ( advice) ;
85
108
}
86
109
110
+ /// Return the `EvaluationError`, but with the new `source_loc` (or `None`).
111
+ pub ( crate ) fn with_maybe_source_loc ( self , source_loc : Option < Loc > ) -> Self {
112
+ Self { source_loc, ..self }
113
+ }
114
+
87
115
/// Construct a [`EntityDoesNotExist`] error
88
- pub ( crate ) fn entity_does_not_exist ( euid : Arc < EntityUID > ) -> Self {
116
+ pub ( crate ) fn entity_does_not_exist ( euid : Arc < EntityUID > , source_loc : Option < Loc > ) -> Self {
89
117
Self {
90
118
error_kind : EvaluationErrorKind :: EntityDoesNotExist ( euid) ,
91
119
advice : None ,
120
+ source_loc,
92
121
}
93
122
}
94
123
95
124
/// Construct a [`EntityAttrDoesNotExist`] error
96
- pub ( crate ) fn entity_attr_does_not_exist ( entity : Arc < EntityUID > , attr : SmolStr ) -> Self {
125
+ pub ( crate ) fn entity_attr_does_not_exist (
126
+ entity : Arc < EntityUID > ,
127
+ attr : SmolStr ,
128
+ source_loc : Option < Loc > ,
129
+ ) -> Self {
97
130
Self {
98
131
error_kind : EvaluationErrorKind :: EntityAttrDoesNotExist { entity, attr } ,
99
132
advice : None ,
133
+ source_loc,
100
134
}
101
135
}
102
136
103
137
/// Construct a [`UnspecifiedEntityAccess`] error
104
- pub ( crate ) fn unspecified_entity_access ( attr : SmolStr ) -> Self {
138
+ pub ( crate ) fn unspecified_entity_access ( attr : SmolStr , source_loc : Option < Loc > ) -> Self {
105
139
Self {
106
140
error_kind : EvaluationErrorKind :: UnspecifiedEntityAccess ( attr) ,
107
141
advice : None ,
142
+ source_loc,
108
143
}
109
144
}
110
145
111
146
/// Construct a [`RecordAttrDoesNotExist`] error
112
- pub ( crate ) fn record_attr_does_not_exist ( attr : SmolStr , alternatives : Vec < SmolStr > ) -> Self {
147
+ pub ( crate ) fn record_attr_does_not_exist (
148
+ attr : SmolStr ,
149
+ alternatives : Vec < SmolStr > ,
150
+ source_loc : Option < Loc > ,
151
+ ) -> Self {
113
152
Self {
114
153
error_kind : EvaluationErrorKind :: RecordAttrDoesNotExist ( attr, alternatives) ,
115
154
advice : None ,
155
+ source_loc,
116
156
}
117
157
}
118
158
119
159
/// Construct a [`TypeError`] error
120
- pub ( crate ) fn type_error ( expected : NonEmpty < Type > , actual : Type ) -> Self {
160
+ pub ( crate ) fn type_error ( expected : NonEmpty < Type > , actual : & Value ) -> Self {
121
161
Self {
122
- error_kind : EvaluationErrorKind :: TypeError { expected, actual } ,
162
+ error_kind : EvaluationErrorKind :: TypeError {
163
+ expected,
164
+ actual : actual. type_of ( ) ,
165
+ } ,
123
166
advice : None ,
167
+ source_loc : actual. source_loc ( ) . cloned ( ) ,
124
168
}
125
169
}
126
170
127
- pub ( crate ) fn type_error_single ( expected : Type , actual : Type ) -> Self {
171
+ pub ( crate ) fn type_error_single ( expected : Type , actual : & Value ) -> Self {
128
172
Self :: type_error ( nonempty ! [ expected] , actual)
129
173
}
130
174
131
175
/// Construct a [`TypeError`] error with the advice field set
132
176
pub ( crate ) fn type_error_with_advice (
133
177
expected : NonEmpty < Type > ,
134
- actual : Type ,
178
+ actual : & Value ,
135
179
advice : String ,
136
180
) -> Self {
137
181
Self {
138
- error_kind : EvaluationErrorKind :: TypeError { expected, actual } ,
182
+ error_kind : EvaluationErrorKind :: TypeError {
183
+ expected,
184
+ actual : actual. type_of ( ) ,
185
+ } ,
139
186
advice : Some ( advice) ,
187
+ source_loc : actual. source_loc ( ) . cloned ( ) ,
140
188
}
141
189
}
142
190
143
191
pub ( crate ) fn type_error_with_advice_single (
144
192
expected : Type ,
145
- actual : Type ,
193
+ actual : & Value ,
146
194
advice : String ,
147
195
) -> Self {
148
196
Self :: type_error_with_advice ( nonempty ! [ expected] , actual, advice)
149
197
}
150
198
151
199
/// Construct a [`WrongNumArguments`] error
152
- pub ( crate ) fn wrong_num_arguments ( function_name : Name , expected : usize , actual : usize ) -> Self {
200
+ pub ( crate ) fn wrong_num_arguments (
201
+ function_name : Name ,
202
+ expected : usize ,
203
+ actual : usize ,
204
+ source_loc : Option < Loc > ,
205
+ ) -> Self {
153
206
Self {
154
207
error_kind : EvaluationErrorKind :: WrongNumArguments {
155
208
function_name,
156
209
expected,
157
210
actual,
158
211
} ,
159
212
advice : None ,
213
+ source_loc,
160
214
}
161
215
}
162
216
163
217
/// Construct a [`UnlinkedSlot`] error
164
- pub ( crate ) fn unlinked_slot ( id : SlotId ) -> Self {
218
+ pub ( crate ) fn unlinked_slot ( id : SlotId , source_loc : Option < Loc > ) -> Self {
165
219
Self {
166
220
error_kind : EvaluationErrorKind :: UnlinkedSlot ( id) ,
167
221
advice : None ,
222
+ source_loc,
168
223
}
169
224
}
170
225
171
226
/// Construct a [`FailedExtensionFunctionApplication`] error
172
- pub ( crate ) fn failed_extension_function_application ( extension_name : Name , msg : String ) -> Self {
227
+ pub ( crate ) fn failed_extension_function_application (
228
+ extension_name : Name ,
229
+ msg : String ,
230
+ source_loc : Option < Loc > ,
231
+ ) -> Self {
173
232
Self {
174
233
error_kind : EvaluationErrorKind :: FailedExtensionFunctionApplication {
175
234
extension_name,
176
235
msg,
177
236
} ,
178
237
advice : None ,
238
+ source_loc,
179
239
}
180
240
}
181
241
182
242
/// Construct a [`NonValue`] error
183
243
pub ( crate ) fn non_value ( e : Expr ) -> Self {
244
+ let source_loc = e. source_loc ( ) . cloned ( ) ;
184
245
Self {
185
246
error_kind : EvaluationErrorKind :: NonValue ( e) ,
186
247
advice : Some ( "consider using the partial evaluation APIs" . into ( ) ) ,
248
+ source_loc,
187
249
}
188
250
}
189
251
190
252
/// Construct a [`RecursionLimit`] error
191
- pub ( crate ) fn recursion_limit ( ) -> Self {
253
+ pub ( crate ) fn recursion_limit ( source_loc : Option < Loc > ) -> Self {
192
254
Self {
193
255
error_kind : EvaluationErrorKind :: RecursionLimit ,
194
256
advice : None ,
257
+ source_loc,
195
258
}
196
259
}
197
- }
198
260
199
- impl From < crate :: extensions:: ExtensionFunctionLookupError > for EvaluationError {
200
- fn from ( err : crate :: extensions:: ExtensionFunctionLookupError ) -> Self {
261
+ pub ( crate ) fn extension_function_lookup (
262
+ err : crate :: extensions:: ExtensionFunctionLookupError ,
263
+ source_loc : Option < Loc > ,
264
+ ) -> Self {
201
265
Self {
202
266
error_kind : err. into ( ) ,
203
267
advice : None ,
268
+ source_loc,
204
269
}
205
270
}
206
- }
207
271
208
- impl From < IntegerOverflowError > for EvaluationError {
209
- fn from ( err : IntegerOverflowError ) -> Self {
272
+ pub ( crate ) fn integer_overflow ( err : IntegerOverflowError , source_loc : Option < Loc > ) -> Self {
210
273
Self {
211
274
error_kind : err. into ( ) ,
212
275
advice : None ,
276
+ source_loc,
213
277
}
214
278
}
215
279
}
@@ -219,6 +283,7 @@ impl From<RestrictedExprError> for EvaluationError {
219
283
Self {
220
284
error_kind : err. into ( ) ,
221
285
advice : None ,
286
+ source_loc : None , // defer to the source information embedded in the `RestrictedExprError` and thus stored in `error_kind`
222
287
}
223
288
}
224
289
}
0 commit comments