@@ -8,22 +8,20 @@ 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 } ,
1212 path:: ModPath ,
13- resolver:: { Resolver , ValueNs } ,
13+ resolver:: { resolver_for_expr , ResolveValueResult , Resolver , ValueNs } ,
1414 type_ref:: ConstScalar ,
15+ ConstId , DefWithBodyId ,
1516} ;
1617use hir_expand:: name:: Name ;
1718use la_arena:: { Arena , Idx } ;
1819use stdx:: never;
1920
2021use 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 ,
2725} ;
2826
2927/// Extension trait for [`Const`]
@@ -55,21 +53,30 @@ impl ConstExt for Const {
5553}
5654
5755pub struct ConstEvalCtx < ' a > {
56+ pub db : & ' a dyn HirDatabase ,
57+ pub owner : DefWithBodyId ,
5858 pub exprs : & ' a Arena < Expr > ,
5959 pub pats : & ' a Arena < Pat > ,
6060 pub local_data : HashMap < Name , ComputedExpr > ,
61- pub infer : & ' a mut dyn FnMut ( Idx < Expr > ) -> Ty ,
61+ infer : & ' a InferenceResult ,
6262}
6363
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 ) ]
6571pub enum ConstEvalError {
6672 NotSupported ( & ' static str ) ,
67- TypeError ,
73+ SemanticError ( & ' static str ) ,
74+ Loop ,
6875 IncompleteExpr ,
6976 Panic ( String ) ,
7077}
7178
72- #[ derive( Debug , Clone ) ]
79+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
7380pub enum ComputedExpr {
7481 Literal ( Literal ) ,
7582 Tuple ( Box < [ ComputedExpr ] > ) ,
@@ -143,12 +150,16 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
143150 }
144151}
145152
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] ;
147158 match expr {
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,7 +260,7 @@ 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 }
@@ -266,7 +277,7 @@ pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExp
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 } ;
272283 if !prev_values. contains_key ( & name) {
@@ -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,47 @@ 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 ( _) => {
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+ }
304344 }
305345 _ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
306346 }
307347}
308348
309349pub fn eval_usize ( expr : Idx < Expr > , mut ctx : ConstEvalCtx < ' _ > ) -> Option < u64 > {
310- let expr = & ctx. exprs [ expr] ;
311350 if let Ok ( ce) = eval_const ( expr, & mut ctx) {
312351 match ce {
313352 ComputedExpr :: Literal ( Literal :: Int ( x, _) ) => return x. try_into ( ) . ok ( ) ,
@@ -380,10 +419,39 @@ pub fn usize_const(value: Option<u64>) -> Const {
380419 . intern ( Interner )
381420}
382421
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 > (
384452 expr : Idx < Expr > ,
385453 mode : ParamLoweringMode ,
386- ctx : & mut InferenceContext ,
454+ ctx : & mut InferenceContext < ' a > ,
387455 args : impl FnOnce ( ) -> Generics ,
388456 debruijn : DebruijnIndex ,
389457) -> Const {
@@ -396,10 +464,12 @@ pub(crate) fn eval_to_const(
396464 }
397465 let body = ctx. body . clone ( ) ;
398466 let ctx = ConstEvalCtx {
467+ db : ctx. db ,
468+ owner : ctx. owner ,
399469 exprs : & body. exprs ,
400470 pats : & body. pats ,
401471 local_data : HashMap :: default ( ) ,
402- infer : & mut |x| ctx. infer_expr ( x , & Expectation :: None ) ,
472+ infer : & ctx. result ,
403473 } ;
404474 usize_const ( eval_usize ( expr, ctx) )
405475}
0 commit comments