@@ -7,14 +7,17 @@ use std::{
77
88use chalk_ir:: { BoundVar , DebruijnIndex , GenericArgData , IntTy , Scalar } ;
99use hir_def:: {
10+ builtin_type:: BuiltinInt ,
1011 expr:: { ArithOp , BinaryOp , Expr , ExprId , Literal , Pat , PatId } ,
1112 path:: ModPath ,
1213 resolver:: { resolver_for_expr, ResolveValueResult , Resolver , ValueNs } ,
14+ src:: HasChildSource ,
1315 type_ref:: ConstScalar ,
14- ConstId , DefWithBodyId , EnumVariantId ,
16+ ConstId , DefWithBodyId , EnumVariantId , Lookup ,
1517} ;
16- use la_arena:: { Arena , Idx } ;
18+ use la_arena:: { Arena , Idx , RawIdx } ;
1719use stdx:: never;
20+ use syntax:: ast:: HasName ;
1821
1922use crate :: {
2023 db:: HirDatabase , infer:: InferenceContext , lower:: ParamLoweringMode , to_placeholder_idx,
@@ -77,6 +80,7 @@ pub enum ConstEvalError {
7780#[ derive( Debug , Clone , PartialEq , Eq ) ]
7881pub enum ComputedExpr {
7982 Literal ( Literal ) ,
83+ Enum ( String , EnumVariantId , Literal ) ,
8084 Tuple ( Box < [ ComputedExpr ] > ) ,
8185}
8286
@@ -104,6 +108,7 @@ impl Display for ComputedExpr {
104108 Literal :: String ( x) => std:: fmt:: Debug :: fmt ( x, f) ,
105109 Literal :: ByteString ( x) => std:: fmt:: Debug :: fmt ( x, f) ,
106110 } ,
111+ ComputedExpr :: Enum ( name, _, _) => name. fmt ( f) ,
107112 ComputedExpr :: Tuple ( t) => {
108113 f. write_char ( '(' ) ?;
109114 for x in & * * t {
@@ -116,6 +121,15 @@ impl Display for ComputedExpr {
116121 }
117122}
118123
124+ impl ComputedExpr {
125+ pub fn enum_value ( & self ) -> Option < ComputedExpr > {
126+ match self {
127+ ComputedExpr :: Enum ( _, _, lit) => Some ( ComputedExpr :: Literal ( lit. clone ( ) ) ) ,
128+ _ => None ,
129+ }
130+ }
131+ }
132+
119133fn scalar_max ( scalar : & Scalar ) -> i128 {
120134 match scalar {
121135 Scalar :: Bool => 1 ,
@@ -148,17 +162,56 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
148162 }
149163}
150164
165+ fn get_name ( variant : EnumVariantId , ctx : & mut ConstEvalCtx < ' _ > ) -> String {
166+ let loc = variant. parent . lookup ( ctx. db . upcast ( ) ) ;
167+ let children = variant. parent . child_source ( ctx. db . upcast ( ) ) ;
168+ let item_tree = loc. id . item_tree ( ctx. db . upcast ( ) ) ;
169+
170+ let variant_name = children. value [ variant. local_id ] . name ( ) ;
171+ let enum_name = item_tree[ loc. id . value ] . name . to_string ( ) ;
172+ enum_name + "::" + & variant_name. unwrap ( ) . to_string ( )
173+ }
174+
151175pub fn eval_const (
152176 expr_id : ExprId ,
153177 ctx : & mut ConstEvalCtx < ' _ > ,
178+ variant : Option < EnumVariantId > ,
154179) -> Result < ComputedExpr , ConstEvalError > {
155180 let expr = & ctx. exprs [ expr_id] ;
156181 match expr {
157- Expr :: Missing => Err ( ConstEvalError :: IncompleteExpr ) ,
182+ Expr :: Missing => match variant {
183+ Some ( variant) => {
184+ let prev_idx: u32 = variant. local_id . into_raw ( ) . into ( ) ;
185+ let prev_idx = prev_idx. checked_sub ( 1 ) . map ( |idx| Idx :: from_raw ( RawIdx :: from ( idx) ) ) ;
186+ let value = match prev_idx {
187+ Some ( prev) => {
188+ let prev_variant = EnumVariantId { local_id : prev, ..variant } ;
189+ 1 + match ctx. db . const_eval_variant ( prev_variant) ? {
190+ ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
191+ ComputedExpr :: Literal ( Literal :: Uint ( v, _) ) => v
192+ . try_into ( )
193+ . map_err ( |_| ConstEvalError :: NotSupported ( "too big u128" ) ) ?,
194+ _ => {
195+ return Err ( ConstEvalError :: NotSupported (
196+ "Enum can't contain this kind of value" ,
197+ ) )
198+ }
199+ }
200+ }
201+ _ => 0 ,
202+ } ;
203+ Ok ( ComputedExpr :: Enum (
204+ get_name ( variant, ctx) ,
205+ variant,
206+ Literal :: Int ( value + 1 , Some ( BuiltinInt :: I128 ) ) ,
207+ ) )
208+ }
209+ _ => Err ( ConstEvalError :: IncompleteExpr ) ,
210+ } ,
158211 Expr :: Literal ( l) => Ok ( ComputedExpr :: Literal ( l. clone ( ) ) ) ,
159212 & Expr :: UnaryOp { expr, op } => {
160213 let ty = & ctx. expr_ty ( expr) ;
161- let ev = eval_const ( expr, ctx) ?;
214+ let ev = eval_const ( expr, ctx, None ) ?;
162215 match op {
163216 hir_def:: expr:: UnaryOp :: Deref => Err ( ConstEvalError :: NotSupported ( "deref" ) ) ,
164217 hir_def:: expr:: UnaryOp :: Not => {
@@ -214,8 +267,8 @@ pub fn eval_const(
214267 }
215268 & Expr :: BinaryOp { lhs, rhs, op } => {
216269 let ty = & ctx. expr_ty ( lhs) ;
217- let lhs = eval_const ( lhs, ctx) ?;
218- let rhs = eval_const ( rhs, ctx) ?;
270+ let lhs = eval_const ( lhs, ctx, None ) ?;
271+ let rhs = eval_const ( rhs, ctx, None ) ?;
219272 let op = op. ok_or ( ConstEvalError :: IncompleteExpr ) ?;
220273 let v1 = match lhs {
221274 ComputedExpr :: Literal ( Literal :: Int ( v, _) ) => v,
@@ -276,7 +329,7 @@ pub fn eval_const(
276329 }
277330 } ;
278331 let value = match initializer {
279- Some ( x) => eval_const ( x, ctx) ?,
332+ Some ( x) => eval_const ( x, ctx, None ) ?,
280333 None => continue ,
281334 } ;
282335 if !prev_values. contains_key ( & pat_id) {
@@ -292,7 +345,7 @@ pub fn eval_const(
292345 }
293346 }
294347 let r = match tail {
295- & Some ( x) => eval_const ( x, ctx) ,
348+ & Some ( x) => eval_const ( x, ctx, None ) ,
296349 None => Ok ( ComputedExpr :: Tuple ( Box :: new ( [ ] ) ) ) ,
297350 } ;
298351 // clean up local data, so caller will receive the exact map that passed to us
@@ -339,10 +392,24 @@ pub fn eval_const(
339392 ValueNs :: GenericParam ( _) => {
340393 Err ( ConstEvalError :: NotSupported ( "const generic without substitution" ) )
341394 }
342- ValueNs :: EnumVariantId ( id) => ctx. db . const_eval_variant ( id) ,
395+ ValueNs :: EnumVariantId ( id) => match ctx. db . const_eval_variant ( id) ? {
396+ ComputedExpr :: Literal ( lit) => {
397+ Ok ( ComputedExpr :: Enum ( get_name ( id, ctx) , id, lit) )
398+ }
399+ _ => Err ( ConstEvalError :: NotSupported (
400+ "Enums can't evalute to anything but numbers" ,
401+ ) ) ,
402+ } ,
343403 _ => Err ( ConstEvalError :: NotSupported ( "path that are not const or local" ) ) ,
344404 }
345405 }
406+ Expr :: Cast { expr, .. } => match eval_const ( * expr, ctx, None ) ? {
407+ ComputedExpr :: Enum ( _, _, lit) => Ok ( ComputedExpr :: Literal ( lit) ) ,
408+ expr => Err ( ConstEvalError :: NotSupported ( Box :: leak ( Box :: new ( format ! (
409+ "Can't cast type: {:?}" ,
410+ expr
411+ ) ) ) ) ) ,
412+ } ,
346413 _ => Err ( ConstEvalError :: NotSupported ( "This kind of expression" ) ) ,
347414 }
348415}
@@ -438,6 +505,7 @@ pub(crate) fn const_eval_query(
438505 local_data : HashMap :: default ( ) ,
439506 infer,
440507 } ,
508+ None ,
441509 ) ;
442510 result
443511}
@@ -459,6 +527,7 @@ pub(crate) fn const_eval_query_variant(
459527 local_data : HashMap :: default ( ) ,
460528 infer,
461529 } ,
530+ Some ( variant_id) ,
462531 )
463532}
464533
@@ -485,7 +554,7 @@ pub(crate) fn eval_to_const<'a>(
485554 local_data : HashMap :: default ( ) ,
486555 infer : & ctx. result ,
487556 } ;
488- let computed_expr = eval_const ( expr, & mut ctx) ;
557+ let computed_expr = eval_const ( expr, & mut ctx, None ) ;
489558 let const_scalar = match computed_expr {
490559 Ok ( ComputedExpr :: Literal ( literal) ) => literal. into ( ) ,
491560 _ => ConstScalar :: Unknown ,
0 commit comments