@@ -4,14 +4,13 @@ use std::{collections::HashMap, convert::TryInto, fmt::Display};
4
4
5
5
use chalk_ir:: { IntTy , Scalar } ;
6
6
use hir_def:: {
7
- builtin_type:: BuiltinUint ,
8
7
expr:: { ArithOp , BinaryOp , Expr , Literal , Pat } ,
9
8
type_ref:: ConstScalar ,
10
9
} ;
11
10
use hir_expand:: name:: Name ;
12
- use la_arena:: Arena ;
11
+ use la_arena:: { Arena , Idx } ;
13
12
14
- use crate :: { Const , ConstData , ConstValue , InferenceResult , Interner , TyKind } ;
13
+ use crate :: { Const , ConstData , ConstValue , Interner , Ty , TyKind } ;
15
14
16
15
/// Extension trait for [`Const`]
17
16
pub trait ConstExt {
@@ -41,12 +40,11 @@ impl ConstExt for Const {
41
40
}
42
41
}
43
42
44
- #[ derive( Clone ) ]
45
43
pub struct ConstEvalCtx < ' a > {
46
44
pub exprs : & ' a Arena < Expr > ,
47
45
pub pats : & ' a Arena < Pat > ,
48
46
pub local_data : HashMap < Name , ComputedExpr > ,
49
- pub infer : & ' a InferenceResult ,
47
+ pub infer : & ' a mut dyn FnMut ( Idx < Expr > ) -> Ty ,
50
48
}
51
49
52
50
#[ derive( Debug , Clone ) ]
@@ -57,7 +55,7 @@ pub enum ConstEvalError {
57
55
Panic ( String ) ,
58
56
}
59
57
60
- #[ derive( Clone ) ]
58
+ #[ derive( Debug , Clone ) ]
61
59
pub enum ComputedExpr {
62
60
Literal ( Literal ) ,
63
61
Tuple ( Box < [ ComputedExpr ] > ) ,
@@ -130,11 +128,11 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
130
128
}
131
129
}
132
130
133
- pub fn eval_const ( expr : & Expr , mut ctx : ConstEvalCtx < ' _ > ) -> Result < ComputedExpr , ConstEvalError > {
131
+ pub fn eval_const ( expr : & Expr , ctx : & mut ConstEvalCtx < ' _ > ) -> Result < ComputedExpr , ConstEvalError > {
134
132
match expr {
135
133
Expr :: Literal ( l) => Ok ( ComputedExpr :: Literal ( l. clone ( ) ) ) ,
136
134
& Expr :: UnaryOp { expr, op } => {
137
- let ty = & ctx. infer [ expr] ;
135
+ let ty = & ( ctx. infer ) ( expr) ;
138
136
let ev = eval_const ( & ctx. exprs [ expr] , ctx) ?;
139
137
match op {
140
138
hir_def:: expr:: UnaryOp :: Deref => Err ( ConstEvalError :: NotSupported ( "deref" ) ) ,
@@ -190,9 +188,9 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
190
188
}
191
189
}
192
190
& Expr :: BinaryOp { lhs, rhs, op } => {
193
- let ty = & ctx. infer [ lhs] ;
194
- let lhs = eval_const ( & ctx. exprs [ lhs] , ctx. clone ( ) ) ?;
195
- let rhs = eval_const ( & ctx. exprs [ rhs] , ctx. clone ( ) ) ?;
191
+ let ty = & ( ctx. infer ) ( lhs) ;
192
+ let lhs = eval_const ( & ctx. exprs [ lhs] , ctx) ?;
193
+ let rhs = eval_const ( & ctx. exprs [ rhs] , ctx) ?;
196
194
let op = op. ok_or ( ConstEvalError :: IncompleteExpr ) ?;
197
195
let v1 = match lhs {
198
196
ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
@@ -241,6 +239,7 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
241
239
}
242
240
}
243
241
Expr :: Block { statements, tail, .. } => {
242
+ let mut prev_values = HashMap :: < Name , Option < ComputedExpr > > :: default ( ) ;
244
243
for statement in & * * statements {
245
244
match statement {
246
245
& hir_def:: expr:: Statement :: Let { pat, initializer, .. } => {
@@ -252,21 +251,33 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
252
251
}
253
252
} ;
254
253
let value = match initializer {
255
- Some ( x) => eval_const ( & ctx. exprs [ x] , ctx. clone ( ) ) ?,
254
+ Some ( x) => eval_const ( & ctx. exprs [ x] , ctx) ?,
256
255
None => continue ,
257
256
} ;
258
- ctx. local_data . insert ( name, value) ;
257
+ if !prev_values. contains_key ( & name) {
258
+ let prev = ctx. local_data . insert ( name. clone ( ) , value) ;
259
+ prev_values. insert ( name, prev) ;
260
+ } else {
261
+ ctx. local_data . insert ( name, value) ;
262
+ }
259
263
}
260
264
& hir_def:: expr:: Statement :: Expr { .. } => {
261
265
return Err ( ConstEvalError :: NotSupported ( "this kind of statement" ) )
262
266
}
263
267
}
264
268
}
265
- let tail_expr = match tail {
266
- & Some ( x) => & ctx. exprs [ x] ,
267
- None => return Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
269
+ let r = match tail {
270
+ & Some ( x) => eval_const ( & ctx. exprs [ x] , ctx ) ,
271
+ None => Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
268
272
} ;
269
- eval_const ( tail_expr, ctx)
273
+ // clean up local data, so caller will receive the exact map that passed to us
274
+ for ( name, val) in prev_values {
275
+ match val {
276
+ Some ( x) => ctx. local_data . insert ( name, x) ,
277
+ None => ctx. local_data . remove ( & name) ,
278
+ } ;
279
+ }
280
+ r
270
281
}
271
282
Expr :: Path ( p) => {
272
283
let name = p. mod_path ( ) . as_ident ( ) . ok_or ( ConstEvalError :: NotSupported ( "big paths" ) ) ?;
@@ -280,12 +291,16 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
280
291
}
281
292
}
282
293
283
- // FIXME: support more than just evaluating literals
284
- pub fn eval_usize ( expr : & Expr ) -> Option < u64 > {
285
- match expr {
286
- Expr :: Literal ( Literal :: Uint ( v, None | Some ( BuiltinUint :: Usize ) ) ) => ( * v) . try_into ( ) . ok ( ) ,
287
- _ => None ,
294
+ pub fn eval_usize ( expr : Idx < Expr > , mut ctx : ConstEvalCtx < ' _ > ) -> Option < u64 > {
295
+ let expr = & ctx. exprs [ expr] ;
296
+ if let Ok ( ce) = eval_const ( & expr, & mut ctx) {
297
+ match ce {
298
+ ComputedExpr :: Literal ( Literal :: Int ( x, _) ) => return x. try_into ( ) . ok ( ) ,
299
+ ComputedExpr :: Literal ( Literal :: Uint ( x, _) ) => return x. try_into ( ) . ok ( ) ,
300
+ _ => { }
301
+ }
288
302
}
303
+ None
289
304
}
290
305
291
306
/// Interns a possibly-unknown target usize
0 commit comments