@@ -8,22 +8,20 @@ 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 } ,
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
17
use hir_expand:: name:: Name ;
17
18
use la_arena:: { Arena , Idx } ;
18
19
use stdx:: never;
19
20
20
21
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 ,
22
+ db:: HirDatabase , infer:: InferenceContext , lower:: ParamLoweringMode , to_placeholder_idx,
23
+ utils:: Generics , Const , ConstData , ConstValue , GenericArg , InferenceResult , Interner , Ty ,
24
+ TyKind ,
27
25
} ;
28
26
29
27
/// Extension trait for [`Const`]
@@ -55,21 +53,30 @@ impl ConstExt for Const {
55
53
}
56
54
57
55
pub struct ConstEvalCtx < ' a > {
56
+ pub db : & ' a dyn HirDatabase ,
57
+ pub owner : DefWithBodyId ,
58
58
pub exprs : & ' a Arena < Expr > ,
59
59
pub pats : & ' a Arena < Pat > ,
60
60
pub local_data : HashMap < Name , ComputedExpr > ,
61
- pub infer : & ' a mut dyn FnMut ( Idx < Expr > ) -> Ty ,
61
+ infer : & ' a InferenceResult ,
62
62
}
63
63
64
- #[ derive( Debug , Clone ) ]
64
+ impl ConstEvalCtx < ' _ > {
65
+ fn expr_ty ( & mut self , expr : ExprId ) -> Ty {
66
+ self . infer [ expr] . clone ( )
67
+ }
68
+ }
69
+
70
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
65
71
pub enum ConstEvalError {
66
72
NotSupported ( & ' static str ) ,
67
- TypeError ,
73
+ SemanticError ( & ' static str ) ,
74
+ Loop ,
68
75
IncompleteExpr ,
69
76
Panic ( String ) ,
70
77
}
71
78
72
- #[ derive( Debug , Clone ) ]
79
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
73
80
pub enum ComputedExpr {
74
81
Literal ( Literal ) ,
75
82
Tuple ( Box < [ ComputedExpr ] > ) ,
@@ -143,12 +150,16 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
143
150
}
144
151
}
145
152
146
- pub fn eval_const ( expr : & Expr , ctx : & mut ConstEvalCtx < ' _ > ) -> Result < ComputedExpr , ConstEvalError > {
153
+ pub fn eval_const (
154
+ expr_id : ExprId ,
155
+ ctx : & mut ConstEvalCtx < ' _ > ,
156
+ ) -> Result < ComputedExpr , ConstEvalError > {
157
+ let expr = & ctx. exprs [ expr_id] ;
147
158
match expr {
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,7 +260,7 @@ 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
}
@@ -266,7 +277,7 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
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
283
if !prev_values. contains_key ( & name) {
@@ -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,47 @@ 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 ( _) => {
333
+ let name =
334
+ p. mod_path ( ) . as_ident ( ) . ok_or ( ConstEvalError :: NotSupported ( "big paths" ) ) ?;
335
+ let r = ctx
336
+ . local_data
337
+ . get ( name)
338
+ . ok_or ( ConstEvalError :: NotSupported ( "Unexpected missing local" ) ) ?;
339
+ Ok ( r. clone ( ) )
340
+ }
341
+ ValueNs :: ConstId ( id) => ctx. db . const_eval ( id) ,
342
+ _ => Err ( ConstEvalError :: NotSupported ( "path that are not const or local" ) ) ,
343
+ }
304
344
}
305
345
_ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
306
346
}
307
347
}
308
348
309
349
pub fn eval_usize ( expr : Idx < Expr > , mut ctx : ConstEvalCtx < ' _ > ) -> Option < u64 > {
310
- let expr = & ctx. exprs [ expr] ;
311
350
if let Ok ( ce) = eval_const ( expr, & mut ctx) {
312
351
match ce {
313
352
ComputedExpr :: Literal ( Literal :: Int ( x, _) ) => return x. try_into ( ) . ok ( ) ,
@@ -380,10 +419,39 @@ pub fn usize_const(value: Option<u64>) -> Const {
380
419
. intern ( Interner )
381
420
}
382
421
383
- pub ( crate ) fn eval_to_const (
422
+ pub ( crate ) fn const_eval_recover (
423
+ _: & dyn HirDatabase ,
424
+ _: & [ String ] ,
425
+ _: & ConstId ,
426
+ ) -> Result < ComputedExpr , ConstEvalError > {
427
+ Err ( ConstEvalError :: Loop )
428
+ }
429
+
430
+ pub ( crate ) fn const_eval_query (
431
+ db : & dyn HirDatabase ,
432
+ const_id : ConstId ,
433
+ ) -> Result < ComputedExpr , ConstEvalError > {
434
+ let def = const_id. into ( ) ;
435
+ let body = db. body ( def) ;
436
+ let mut infer = db. infer_query ( def) ;
437
+ let result = eval_const (
438
+ body. body_expr ,
439
+ & mut ConstEvalCtx {
440
+ db,
441
+ owner : const_id. into ( ) ,
442
+ exprs : & body. exprs ,
443
+ pats : & body. pats ,
444
+ local_data : HashMap :: default ( ) ,
445
+ infer : & mut infer,
446
+ } ,
447
+ ) ;
448
+ result
449
+ }
450
+
451
+ pub ( crate ) fn eval_to_const < ' a > (
384
452
expr : Idx < Expr > ,
385
453
mode : ParamLoweringMode ,
386
- ctx : & mut InferenceContext ,
454
+ ctx : & mut InferenceContext < ' a > ,
387
455
args : impl FnOnce ( ) -> Generics ,
388
456
debruijn : DebruijnIndex ,
389
457
) -> Const {
@@ -396,10 +464,12 @@ pub(crate) fn eval_to_const(
396
464
}
397
465
let body = ctx. body . clone ( ) ;
398
466
let ctx = ConstEvalCtx {
467
+ db : ctx. db ,
468
+ owner : ctx. owner ,
399
469
exprs : & body. exprs ,
400
470
pats : & body. pats ,
401
471
local_data : HashMap :: default ( ) ,
402
- infer : & mut |x| ctx. infer_expr ( x , & Expectation :: None ) ,
472
+ infer : & ctx. result ,
403
473
} ;
404
474
usize_const ( eval_usize ( expr, ctx) )
405
475
}
0 commit comments