@@ -8,22 +8,19 @@ use std::{
8
8
9
9
use chalk_ir:: { BoundVar , DebruijnIndex , GenericArgData , IntTy , Scalar } ;
10
10
use hir_def:: {
11
- expr:: { ArithOp , BinaryOp , Expr , Literal , Pat } ,
11
+ expr:: { ArithOp , BinaryOp , Expr , ExprId , Literal , Pat , PatId } ,
12
12
path:: ModPath ,
13
- resolver:: { Resolver , ValueNs } ,
13
+ resolver:: { resolver_for_expr , ResolveValueResult , Resolver , ValueNs } ,
14
14
type_ref:: ConstScalar ,
15
+ ConstId , DefWithBodyId ,
15
16
} ;
16
- use hir_expand:: name:: Name ;
17
17
use la_arena:: { Arena , Idx } ;
18
18
use stdx:: never;
19
19
20
20
use crate :: {
21
- db:: HirDatabase ,
22
- infer:: { Expectation , InferenceContext } ,
23
- lower:: ParamLoweringMode ,
24
- to_placeholder_idx,
25
- utils:: Generics ,
26
- Const , ConstData , ConstValue , GenericArg , Interner , Ty , TyKind ,
21
+ db:: HirDatabase , infer:: InferenceContext , lower:: ParamLoweringMode , to_placeholder_idx,
22
+ utils:: Generics , Const , ConstData , ConstValue , GenericArg , InferenceResult , Interner , Ty ,
23
+ TyKind ,
27
24
} ;
28
25
29
26
/// Extension trait for [`Const`]
@@ -55,21 +52,30 @@ impl ConstExt for Const {
55
52
}
56
53
57
54
pub struct ConstEvalCtx < ' a > {
55
+ pub db : & ' a dyn HirDatabase ,
56
+ pub owner : DefWithBodyId ,
58
57
pub exprs : & ' a Arena < Expr > ,
59
58
pub pats : & ' a Arena < Pat > ,
60
- pub local_data : HashMap < Name , ComputedExpr > ,
61
- pub infer : & ' a mut dyn FnMut ( Idx < Expr > ) -> Ty ,
59
+ pub local_data : HashMap < PatId , ComputedExpr > ,
60
+ infer : & ' a InferenceResult ,
62
61
}
63
62
64
- #[ derive( Debug , Clone ) ]
63
+ impl ConstEvalCtx < ' _ > {
64
+ fn expr_ty ( & mut self , expr : ExprId ) -> Ty {
65
+ self . infer [ expr] . clone ( )
66
+ }
67
+ }
68
+
69
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
65
70
pub enum ConstEvalError {
66
71
NotSupported ( & ' static str ) ,
67
- TypeError ,
72
+ SemanticError ( & ' static str ) ,
73
+ Loop ,
68
74
IncompleteExpr ,
69
75
Panic ( String ) ,
70
76
}
71
77
72
- #[ derive( Debug , Clone ) ]
78
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
73
79
pub enum ComputedExpr {
74
80
Literal ( Literal ) ,
75
81
Tuple ( Box < [ ComputedExpr ] > ) ,
@@ -80,14 +86,14 @@ impl Display for ComputedExpr {
80
86
match self {
81
87
ComputedExpr :: Literal ( l) => match l {
82
88
Literal :: Int ( x, _) => {
83
- if * x >= 16 {
89
+ if * x >= 10 {
84
90
write ! ( f, "{} ({:#X})" , x, x)
85
91
} else {
86
92
x. fmt ( f)
87
93
}
88
94
}
89
95
Literal :: Uint ( x, _) => {
90
- if * x >= 16 {
96
+ if * x >= 10 {
91
97
write ! ( f, "{} ({:#X})" , x, x)
92
98
} else {
93
99
x. fmt ( f)
@@ -143,12 +149,17 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
143
149
}
144
150
}
145
151
146
- pub fn eval_const ( expr : & Expr , ctx : & mut ConstEvalCtx < ' _ > ) -> Result < ComputedExpr , ConstEvalError > {
152
+ pub fn eval_const (
153
+ expr_id : ExprId ,
154
+ ctx : & mut ConstEvalCtx < ' _ > ,
155
+ ) -> Result < ComputedExpr , ConstEvalError > {
156
+ let expr = & ctx. exprs [ expr_id] ;
147
157
match expr {
158
+ Expr :: Missing => Err ( ConstEvalError :: IncompleteExpr ) ,
148
159
Expr :: Literal ( l) => Ok ( ComputedExpr :: Literal ( l. clone ( ) ) ) ,
149
160
& Expr :: UnaryOp { expr, op } => {
150
- let ty = & ( ctx. infer ) ( expr) ;
151
- let ev = eval_const ( & ctx . exprs [ expr] , ctx) ?;
161
+ let ty = & ctx. expr_ty ( expr) ;
162
+ let ev = eval_const ( expr, ctx) ?;
152
163
match op {
153
164
hir_def:: expr:: UnaryOp :: Deref => Err ( ConstEvalError :: NotSupported ( "deref" ) ) ,
154
165
hir_def:: expr:: UnaryOp :: Not => {
@@ -203,9 +214,9 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
203
214
}
204
215
}
205
216
& Expr :: BinaryOp { lhs, rhs, op } => {
206
- let ty = & ( ctx. infer ) ( lhs) ;
207
- let lhs = eval_const ( & ctx . exprs [ lhs] , ctx) ?;
208
- let rhs = eval_const ( & ctx . exprs [ rhs] , ctx) ?;
217
+ let ty = & ctx. expr_ty ( lhs) ;
218
+ let lhs = eval_const ( lhs, ctx) ?;
219
+ let rhs = eval_const ( rhs, ctx) ?;
209
220
let op = op. ok_or ( ConstEvalError :: IncompleteExpr ) ?;
210
221
let v1 = match lhs {
211
222
ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
@@ -249,31 +260,31 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
249
260
}
250
261
Ok ( ComputedExpr :: Literal ( Literal :: Int ( r, None ) ) )
251
262
}
252
- BinaryOp :: LogicOp ( _) => Err ( ConstEvalError :: TypeError ) ,
263
+ BinaryOp :: LogicOp ( _) => Err ( ConstEvalError :: SemanticError ( "logic op on numbers" ) ) ,
253
264
_ => Err ( ConstEvalError :: NotSupported ( "bin op on this operators" ) ) ,
254
265
}
255
266
}
256
267
Expr :: Block { statements, tail, .. } => {
257
- let mut prev_values = HashMap :: < Name , Option < ComputedExpr > > :: default ( ) ;
268
+ let mut prev_values = HashMap :: < PatId , Option < ComputedExpr > > :: default ( ) ;
258
269
for statement in & * * statements {
259
270
match * statement {
260
- hir_def:: expr:: Statement :: Let { pat, initializer, .. } => {
261
- let pat = & ctx. pats [ pat ] ;
262
- let name = match pat {
263
- Pat :: Bind { name , subpat, .. } if subpat. is_none ( ) => name . clone ( ) ,
271
+ hir_def:: expr:: Statement :: Let { pat : pat_id , initializer, .. } => {
272
+ let pat = & ctx. pats [ pat_id ] ;
273
+ match pat {
274
+ Pat :: Bind { subpat, .. } if subpat. is_none ( ) => ( ) ,
264
275
_ => {
265
276
return Err ( ConstEvalError :: NotSupported ( "complex patterns in let" ) )
266
277
}
267
278
} ;
268
279
let value = match initializer {
269
- Some ( x) => eval_const ( & ctx . exprs [ x ] , ctx) ?,
280
+ Some ( x) => eval_const ( x , ctx) ?,
270
281
None => continue ,
271
282
} ;
272
- if !prev_values. contains_key ( & name ) {
273
- let prev = ctx. local_data . insert ( name . clone ( ) , value) ;
274
- prev_values. insert ( name , prev) ;
283
+ if !prev_values. contains_key ( & pat_id ) {
284
+ let prev = ctx. local_data . insert ( pat_id , value) ;
285
+ prev_values. insert ( pat_id , prev) ;
275
286
} else {
276
- ctx. local_data . insert ( name , value) ;
287
+ ctx. local_data . insert ( pat_id , value) ;
277
288
}
278
289
}
279
290
hir_def:: expr:: Statement :: Expr { .. } => {
@@ -282,7 +293,7 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
282
293
}
283
294
}
284
295
let r = match tail {
285
- & Some ( x) => eval_const ( & ctx . exprs [ x ] , ctx) ,
296
+ & Some ( x) => eval_const ( x , ctx) ,
286
297
None => Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
287
298
} ;
288
299
// clean up local data, so caller will receive the exact map that passed to us
@@ -295,19 +306,48 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
295
306
r
296
307
}
297
308
Expr :: Path ( p) => {
298
- let name = p. mod_path ( ) . as_ident ( ) . ok_or ( ConstEvalError :: NotSupported ( "big paths" ) ) ?;
299
- let r = ctx
300
- . local_data
301
- . get ( name)
302
- . ok_or ( ConstEvalError :: NotSupported ( "Non local name resolution" ) ) ?;
303
- Ok ( r. clone ( ) )
309
+ let resolver = resolver_for_expr ( ctx. db . upcast ( ) , ctx. owner , expr_id) ;
310
+ let pr = resolver
311
+ . resolve_path_in_value_ns ( ctx. db . upcast ( ) , p. mod_path ( ) )
312
+ . ok_or ( ConstEvalError :: SemanticError ( "unresolved path" ) ) ?;
313
+ let pr = match pr {
314
+ ResolveValueResult :: ValueNs ( v) => v,
315
+ ResolveValueResult :: Partial ( ..) => {
316
+ return match ctx
317
+ . infer
318
+ . assoc_resolutions_for_expr ( expr_id)
319
+ . ok_or ( ConstEvalError :: SemanticError ( "unresolved assoc item" ) ) ?
320
+ {
321
+ hir_def:: AssocItemId :: FunctionId ( _) => {
322
+ Err ( ConstEvalError :: NotSupported ( "assoc function" ) )
323
+ }
324
+ hir_def:: AssocItemId :: ConstId ( c) => ctx. db . const_eval ( c) ,
325
+ hir_def:: AssocItemId :: TypeAliasId ( _) => {
326
+ Err ( ConstEvalError :: NotSupported ( "assoc type alias" ) )
327
+ }
328
+ }
329
+ }
330
+ } ;
331
+ match pr {
332
+ ValueNs :: LocalBinding ( pat_id) => {
333
+ let r = ctx
334
+ . local_data
335
+ . get ( & pat_id)
336
+ . ok_or ( ConstEvalError :: NotSupported ( "Unexpected missing local" ) ) ?;
337
+ Ok ( r. clone ( ) )
338
+ }
339
+ ValueNs :: ConstId ( id) => ctx. db . const_eval ( id) ,
340
+ ValueNs :: GenericParam ( _) => {
341
+ Err ( ConstEvalError :: NotSupported ( "const generic without substitution" ) )
342
+ }
343
+ _ => Err ( ConstEvalError :: NotSupported ( "path that are not const or local" ) ) ,
344
+ }
304
345
}
305
346
_ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
306
347
}
307
348
}
308
349
309
350
pub fn eval_usize ( expr : Idx < Expr > , mut ctx : ConstEvalCtx < ' _ > ) -> Option < u64 > {
310
- let expr = & ctx. exprs [ expr] ;
311
351
if let Ok ( ce) = eval_const ( expr, & mut ctx) {
312
352
match ce {
313
353
ComputedExpr :: Literal ( Literal :: Int ( x, _) ) => return x. try_into ( ) . ok ( ) ,
@@ -380,10 +420,39 @@ pub fn usize_const(value: Option<u64>) -> Const {
380
420
. intern ( Interner )
381
421
}
382
422
383
- pub ( crate ) fn eval_to_const (
423
+ pub ( crate ) fn const_eval_recover (
424
+ _: & dyn HirDatabase ,
425
+ _: & [ String ] ,
426
+ _: & ConstId ,
427
+ ) -> Result < ComputedExpr , ConstEvalError > {
428
+ Err ( ConstEvalError :: Loop )
429
+ }
430
+
431
+ pub ( crate ) fn const_eval_query (
432
+ db : & dyn HirDatabase ,
433
+ const_id : ConstId ,
434
+ ) -> Result < ComputedExpr , ConstEvalError > {
435
+ let def = const_id. into ( ) ;
436
+ let body = db. body ( def) ;
437
+ let infer = & db. infer ( def) ;
438
+ let result = eval_const (
439
+ body. body_expr ,
440
+ & mut ConstEvalCtx {
441
+ db,
442
+ owner : const_id. into ( ) ,
443
+ exprs : & body. exprs ,
444
+ pats : & body. pats ,
445
+ local_data : HashMap :: default ( ) ,
446
+ infer,
447
+ } ,
448
+ ) ;
449
+ result
450
+ }
451
+
452
+ pub ( crate ) fn eval_to_const < ' a > (
384
453
expr : Idx < Expr > ,
385
454
mode : ParamLoweringMode ,
386
- ctx : & mut InferenceContext ,
455
+ ctx : & mut InferenceContext < ' a > ,
387
456
args : impl FnOnce ( ) -> Generics ,
388
457
debruijn : DebruijnIndex ,
389
458
) -> Const {
@@ -396,10 +465,15 @@ pub(crate) fn eval_to_const(
396
465
}
397
466
let body = ctx. body . clone ( ) ;
398
467
let ctx = ConstEvalCtx {
468
+ db : ctx. db ,
469
+ owner : ctx. owner ,
399
470
exprs : & body. exprs ,
400
471
pats : & body. pats ,
401
472
local_data : HashMap :: default ( ) ,
402
- infer : & mut |x| ctx. infer_expr ( x , & Expectation :: None ) ,
473
+ infer : & ctx. result ,
403
474
} ;
404
475
usize_const ( eval_usize ( expr, ctx) )
405
476
}
477
+
478
+ #[ cfg( test) ]
479
+ mod tests;
0 commit comments