@@ -8,22 +8,19 @@ use std::{
88
99use chalk_ir:: { BoundVar , DebruijnIndex , GenericArgData , IntTy , Scalar } ;
1010use hir_def:: {
11- expr:: { ArithOp , BinaryOp , Expr , Literal , Pat } ,
11+ expr:: { ArithOp , BinaryOp , Expr , ExprId , Literal , Pat , PatId } ,
1212 path:: ModPath ,
13- resolver:: { Resolver , ValueNs } ,
13+ resolver:: { resolver_for_expr , ResolveValueResult , Resolver , ValueNs } ,
1414 type_ref:: ConstScalar ,
15+ ConstId , DefWithBodyId ,
1516} ;
16- use hir_expand:: name:: Name ;
1717use la_arena:: { Arena , Idx } ;
1818use stdx:: never;
1919
2020use 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 ,
2724} ;
2825
2926/// Extension trait for [`Const`]
@@ -55,21 +52,30 @@ impl ConstExt for Const {
5552}
5653
5754pub struct ConstEvalCtx < ' a > {
55+ pub db : & ' a dyn HirDatabase ,
56+ pub owner : DefWithBodyId ,
5857 pub exprs : & ' a Arena < Expr > ,
5958 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 ,
6261}
6362
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 ) ]
6570pub enum ConstEvalError {
6671 NotSupported ( & ' static str ) ,
67- TypeError ,
72+ SemanticError ( & ' static str ) ,
73+ Loop ,
6874 IncompleteExpr ,
6975 Panic ( String ) ,
7076}
7177
72- #[ derive( Debug , Clone ) ]
78+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
7379pub enum ComputedExpr {
7480 Literal ( Literal ) ,
7581 Tuple ( Box < [ ComputedExpr ] > ) ,
@@ -80,14 +86,14 @@ impl Display for ComputedExpr {
8086 match self {
8187 ComputedExpr :: Literal ( l) => match l {
8288 Literal :: Int ( x, _) => {
83- if * x >= 16 {
89+ if * x >= 10 {
8490 write ! ( f, "{} ({:#X})" , x, x)
8591 } else {
8692 x. fmt ( f)
8793 }
8894 }
8995 Literal :: Uint ( x, _) => {
90- if * x >= 16 {
96+ if * x >= 10 {
9197 write ! ( f, "{} ({:#X})" , x, x)
9298 } else {
9399 x. fmt ( f)
@@ -143,12 +149,17 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
143149 }
144150}
145151
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] ;
147157 match expr {
158+ Expr :: Missing => Err ( ConstEvalError :: IncompleteExpr ) ,
148159 Expr :: Literal ( l) => Ok ( ComputedExpr :: Literal ( l. clone ( ) ) ) ,
149160 & 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) ?;
152163 match op {
153164 hir_def:: expr:: UnaryOp :: Deref => Err ( ConstEvalError :: NotSupported ( "deref" ) ) ,
154165 hir_def:: expr:: UnaryOp :: Not => {
@@ -203,9 +214,9 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
203214 }
204215 }
205216 & 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) ?;
209220 let op = op. ok_or ( ConstEvalError :: IncompleteExpr ) ?;
210221 let v1 = match lhs {
211222 ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
@@ -249,31 +260,31 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
249260 }
250261 Ok ( ComputedExpr :: Literal ( Literal :: Int ( r, None ) ) )
251262 }
252- BinaryOp :: LogicOp ( _) => Err ( ConstEvalError :: TypeError ) ,
263+ BinaryOp :: LogicOp ( _) => Err ( ConstEvalError :: SemanticError ( "logic op on numbers" ) ) ,
253264 _ => Err ( ConstEvalError :: NotSupported ( "bin op on this operators" ) ) ,
254265 }
255266 }
256267 Expr :: Block { statements, tail, .. } => {
257- let mut prev_values = HashMap :: < Name , Option < ComputedExpr > > :: default ( ) ;
268+ let mut prev_values = HashMap :: < PatId , Option < ComputedExpr > > :: default ( ) ;
258269 for statement in & * * statements {
259270 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 ( ) => ( ) ,
264275 _ => {
265276 return Err ( ConstEvalError :: NotSupported ( "complex patterns in let" ) )
266277 }
267278 } ;
268279 let value = match initializer {
269- Some ( x) => eval_const ( & ctx . exprs [ x ] , ctx) ?,
280+ Some ( x) => eval_const ( x , ctx) ?,
270281 None => continue ,
271282 } ;
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) ;
275286 } else {
276- ctx. local_data . insert ( name , value) ;
287+ ctx. local_data . insert ( pat_id , value) ;
277288 }
278289 }
279290 hir_def:: expr:: Statement :: Expr { .. } => {
@@ -282,7 +293,7 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
282293 }
283294 }
284295 let r = match tail {
285- & Some ( x) => eval_const ( & ctx . exprs [ x ] , ctx) ,
296+ & Some ( x) => eval_const ( x , ctx) ,
286297 None => Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
287298 } ;
288299 // 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
295306 r
296307 }
297308 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+ }
304345 }
305346 _ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
306347 }
307348}
308349
309350pub fn eval_usize ( expr : Idx < Expr > , mut ctx : ConstEvalCtx < ' _ > ) -> Option < u64 > {
310- let expr = & ctx. exprs [ expr] ;
311351 if let Ok ( ce) = eval_const ( expr, & mut ctx) {
312352 match ce {
313353 ComputedExpr :: Literal ( Literal :: Int ( x, _) ) => return x. try_into ( ) . ok ( ) ,
@@ -380,10 +420,39 @@ pub fn usize_const(value: Option<u64>) -> Const {
380420 . intern ( Interner )
381421}
382422
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 > (
384453 expr : Idx < Expr > ,
385454 mode : ParamLoweringMode ,
386- ctx : & mut InferenceContext ,
455+ ctx : & mut InferenceContext < ' a > ,
387456 args : impl FnOnce ( ) -> Generics ,
388457 debruijn : DebruijnIndex ,
389458) -> Const {
@@ -396,10 +465,15 @@ pub(crate) fn eval_to_const(
396465 }
397466 let body = ctx. body . clone ( ) ;
398467 let ctx = ConstEvalCtx {
468+ db : ctx. db ,
469+ owner : ctx. owner ,
399470 exprs : & body. exprs ,
400471 pats : & body. pats ,
401472 local_data : HashMap :: default ( ) ,
402- infer : & mut |x| ctx. infer_expr ( x , & Expectation :: None ) ,
473+ infer : & ctx. result ,
403474 } ;
404475 usize_const ( eval_usize ( expr, ctx) )
405476}
477+
478+ #[ cfg( test) ]
479+ mod tests;
0 commit comments