@@ -7,14 +7,17 @@ use std::{
7
7
8
8
use chalk_ir:: { BoundVar , DebruijnIndex , GenericArgData , IntTy , Scalar } ;
9
9
use hir_def:: {
10
+ builtin_type:: BuiltinInt ,
10
11
expr:: { ArithOp , BinaryOp , Expr , ExprId , Literal , Pat , PatId } ,
11
12
path:: ModPath ,
12
13
resolver:: { resolver_for_expr, ResolveValueResult , Resolver , ValueNs } ,
14
+ src:: HasChildSource ,
13
15
type_ref:: ConstScalar ,
14
- ConstId , DefWithBodyId , EnumVariantId ,
16
+ ConstId , DefWithBodyId , EnumVariantId , Lookup ,
15
17
} ;
16
- use la_arena:: { Arena , Idx } ;
18
+ use la_arena:: { Arena , Idx , RawIdx } ;
17
19
use stdx:: never;
20
+ use syntax:: ast:: HasName ;
18
21
19
22
use crate :: {
20
23
db:: HirDatabase , infer:: InferenceContext , lower:: ParamLoweringMode , to_placeholder_idx,
@@ -77,6 +80,7 @@ pub enum ConstEvalError {
77
80
#[ derive( Debug , Clone , PartialEq , Eq ) ]
78
81
pub enum ComputedExpr {
79
82
Literal ( Literal ) ,
83
+ Enum ( String , EnumVariantId , Literal ) ,
80
84
Tuple ( Box < [ ComputedExpr ] > ) ,
81
85
}
82
86
@@ -104,6 +108,7 @@ impl Display for ComputedExpr {
104
108
Literal :: String ( x) => std:: fmt:: Debug :: fmt ( x, f) ,
105
109
Literal :: ByteString ( x) => std:: fmt:: Debug :: fmt ( x, f) ,
106
110
} ,
111
+ ComputedExpr :: Enum ( name, _, _) => name. fmt ( f) ,
107
112
ComputedExpr :: Tuple ( t) => {
108
113
f. write_char ( '(' ) ?;
109
114
for x in & * * t {
@@ -116,6 +121,15 @@ impl Display for ComputedExpr {
116
121
}
117
122
}
118
123
124
+ impl ComputedExpr {
125
+ pub fn enum_value ( & self ) -> Option < ComputedExpr > {
126
+ match self {
127
+ ComputedExpr :: Enum ( _, _, lit) => Some ( ComputedExpr :: Literal ( lit. clone ( ) ) ) ,
128
+ _ => None ,
129
+ }
130
+ }
131
+ }
132
+
119
133
fn scalar_max ( scalar : & Scalar ) -> i128 {
120
134
match scalar {
121
135
Scalar :: Bool => 1 ,
@@ -148,17 +162,56 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
148
162
}
149
163
}
150
164
165
+ fn get_name ( variant : EnumVariantId , ctx : & mut ConstEvalCtx < ' _ > ) -> String {
166
+ let loc = variant. parent . lookup ( ctx. db . upcast ( ) ) ;
167
+ let children = variant. parent . child_source ( ctx. db . upcast ( ) ) ;
168
+ let item_tree = loc. id . item_tree ( ctx. db . upcast ( ) ) ;
169
+
170
+ let variant_name = children. value [ variant. local_id ] . name ( ) ;
171
+ let enum_name = item_tree[ loc. id . value ] . name . to_string ( ) ;
172
+ enum_name + "::" + & variant_name. unwrap ( ) . to_string ( )
173
+ }
174
+
151
175
pub fn eval_const (
152
176
expr_id : ExprId ,
153
177
ctx : & mut ConstEvalCtx < ' _ > ,
178
+ variant : Option < EnumVariantId > ,
154
179
) -> Result < ComputedExpr , ConstEvalError > {
155
180
let expr = & ctx. exprs [ expr_id] ;
156
181
match expr {
157
- Expr :: Missing => Err ( ConstEvalError :: IncompleteExpr ) ,
182
+ Expr :: Missing => match variant {
183
+ Some ( variant) => {
184
+ let prev_idx: u32 = variant. local_id . into_raw ( ) . into ( ) ;
185
+ let prev_idx = prev_idx. checked_sub ( 1 ) . map ( |idx| Idx :: from_raw ( RawIdx :: from ( idx) ) ) ;
186
+ let value = match prev_idx {
187
+ Some ( prev) => {
188
+ let prev_variant = EnumVariantId { local_id : prev, ..variant } ;
189
+ 1 + match ctx. db . const_eval_variant ( prev_variant) ? {
190
+ ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
191
+ ComputedExpr :: Literal ( Literal :: Uint ( v, _) ) => v
192
+ . try_into ( )
193
+ . map_err ( |_| ConstEvalError :: NotSupported ( "too big u128" ) ) ?,
194
+ _ => {
195
+ return Err ( ConstEvalError :: NotSupported (
196
+ "Enum can't contain this kind of value" ,
197
+ ) )
198
+ }
199
+ }
200
+ }
201
+ _ => 0 ,
202
+ } ;
203
+ Ok ( ComputedExpr :: Enum (
204
+ get_name ( variant, ctx) ,
205
+ variant,
206
+ Literal :: Int ( value + 1 , Some ( BuiltinInt :: I128 ) ) ,
207
+ ) )
208
+ }
209
+ _ => Err ( ConstEvalError :: IncompleteExpr ) ,
210
+ } ,
158
211
Expr :: Literal ( l) => Ok ( ComputedExpr :: Literal ( l. clone ( ) ) ) ,
159
212
& Expr :: UnaryOp { expr, op } => {
160
213
let ty = & ctx. expr_ty ( expr) ;
161
- let ev = eval_const ( expr, ctx) ?;
214
+ let ev = eval_const ( expr, ctx, None ) ?;
162
215
match op {
163
216
hir_def:: expr:: UnaryOp :: Deref => Err ( ConstEvalError :: NotSupported ( "deref" ) ) ,
164
217
hir_def:: expr:: UnaryOp :: Not => {
@@ -214,8 +267,8 @@ pub fn eval_const(
214
267
}
215
268
& Expr :: BinaryOp { lhs, rhs, op } => {
216
269
let ty = & ctx. expr_ty ( lhs) ;
217
- let lhs = eval_const ( lhs, ctx) ?;
218
- let rhs = eval_const ( rhs, ctx) ?;
270
+ let lhs = eval_const ( lhs, ctx, None ) ?;
271
+ let rhs = eval_const ( rhs, ctx, None ) ?;
219
272
let op = op. ok_or ( ConstEvalError :: IncompleteExpr ) ?;
220
273
let v1 = match lhs {
221
274
ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
@@ -276,7 +329,7 @@ pub fn eval_const(
276
329
}
277
330
} ;
278
331
let value = match initializer {
279
- Some ( x) => eval_const ( x, ctx) ?,
332
+ Some ( x) => eval_const ( x, ctx, None ) ?,
280
333
None => continue ,
281
334
} ;
282
335
if !prev_values. contains_key ( & pat_id) {
@@ -292,7 +345,7 @@ pub fn eval_const(
292
345
}
293
346
}
294
347
let r = match tail {
295
- & Some ( x) => eval_const ( x, ctx) ,
348
+ & Some ( x) => eval_const ( x, ctx, None ) ,
296
349
None => Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
297
350
} ;
298
351
// clean up local data, so caller will receive the exact map that passed to us
@@ -339,10 +392,24 @@ pub fn eval_const(
339
392
ValueNs :: GenericParam ( _) => {
340
393
Err ( ConstEvalError :: NotSupported ( "const generic without substitution" ) )
341
394
}
342
- ValueNs :: EnumVariantId ( id) => ctx. db . const_eval_variant ( id) ,
395
+ ValueNs :: EnumVariantId ( id) => match ctx. db . const_eval_variant ( id) ? {
396
+ ComputedExpr :: Literal ( lit) => {
397
+ Ok ( ComputedExpr :: Enum ( get_name ( id, ctx) , id, lit) )
398
+ }
399
+ _ => Err ( ConstEvalError :: NotSupported (
400
+ "Enums can't evalute to anything but numbers" ,
401
+ ) ) ,
402
+ } ,
343
403
_ => Err ( ConstEvalError :: NotSupported ( "path that are not const or local" ) ) ,
344
404
}
345
405
}
406
+ Expr :: Cast { expr, .. } => match eval_const ( * expr, ctx, None ) ? {
407
+ ComputedExpr :: Enum ( _, _, lit) => Ok ( ComputedExpr :: Literal ( lit) ) ,
408
+ expr => Err ( ConstEvalError :: NotSupported ( Box :: leak ( Box :: new ( format ! (
409
+ "Can't cast type: {:?}" ,
410
+ expr
411
+ ) ) ) ) ) ,
412
+ } ,
346
413
_ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
347
414
}
348
415
}
@@ -438,6 +505,7 @@ pub(crate) fn const_eval_query(
438
505
local_data : HashMap :: default ( ) ,
439
506
infer,
440
507
} ,
508
+ None ,
441
509
) ;
442
510
result
443
511
}
@@ -459,6 +527,7 @@ pub(crate) fn const_eval_query_variant(
459
527
local_data : HashMap :: default ( ) ,
460
528
infer,
461
529
} ,
530
+ Some ( variant_id) ,
462
531
)
463
532
}
464
533
@@ -485,7 +554,7 @@ pub(crate) fn eval_to_const<'a>(
485
554
local_data : HashMap :: default ( ) ,
486
555
infer : & ctx. result ,
487
556
} ;
488
- let computed_expr = eval_const ( expr, & mut ctx) ;
557
+ let computed_expr = eval_const ( expr, & mut ctx, None ) ;
489
558
let const_scalar = match computed_expr {
490
559
Ok ( ComputedExpr :: Literal ( literal) ) => literal. into ( ) ,
491
560
_ => ConstScalar :: Unknown ,
0 commit comments