@@ -19,13 +19,14 @@ use front::map::blocks::FnLikeNode;
1919use metadata:: csearch;
2020use metadata:: inline:: InlinedItem ;
2121use middle:: { astencode, def, infer, subst, traits} ;
22- use middle:: def_id:: { DefId } ;
22+ use middle:: def_id:: DefId ;
2323use middle:: pat_util:: def_to_path;
2424use middle:: ty:: { self , Ty } ;
2525use middle:: astconv_util:: ast_ty_to_prim_ty;
2626use util:: num:: ToPrimitive ;
27+ use util:: nodemap:: NodeMap ;
2728
28- use syntax:: ast;
29+ use syntax:: { ast, abi } ;
2930use rustc_front:: hir:: Expr ;
3031use rustc_front:: hir;
3132use rustc_front:: visit:: FnKind ;
@@ -253,6 +254,7 @@ pub enum ConstVal {
253254 Bool ( bool ) ,
254255 Struct ( ast:: NodeId ) ,
255256 Tuple ( ast:: NodeId ) ,
257+ Function ( DefId ) ,
256258}
257259
258260/// Note that equality for `ConstVal` means that the it is the same
@@ -271,6 +273,7 @@ impl PartialEq for ConstVal {
271273 ( & Bool ( a) , & Bool ( b) ) => a == b,
272274 ( & Struct ( a) , & Struct ( b) ) => a == b,
273275 ( & Tuple ( a) , & Tuple ( b) ) => a == b,
276+ ( & Function ( a) , & Function ( b) ) => a == b,
274277 _ => false ,
275278 }
276279 }
@@ -288,6 +291,7 @@ impl ConstVal {
288291 Bool ( _) => "boolean" ,
289292 Struct ( _) => "struct" ,
290293 Tuple ( _) => "tuple" ,
294+ Function ( _) => "function definition" ,
291295 }
292296 }
293297}
@@ -350,12 +354,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat>
350354}
351355
352356pub fn eval_const_expr ( tcx : & ty:: ctxt , e : & Expr ) -> ConstVal {
353- match eval_const_expr_partial ( tcx, e, ExprTypeChecked ) {
357+ match eval_const_expr_partial ( tcx, e, ExprTypeChecked , None ) {
354358 Ok ( r) => r,
355359 Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
356360 }
357361}
358362
363+ pub type FnArgMap < ' a > = Option < & ' a NodeMap < ConstVal > > ;
359364
360365#[ derive( Clone ) ]
361366pub struct ConstEvalErr {
@@ -739,7 +744,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
739744/// computing the length of an array. (See also the FIXME above EvalHint.)
740745pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
741746 e : & Expr ,
742- ty_hint : EvalHint < ' tcx > ) -> EvalResult {
747+ ty_hint : EvalHint < ' tcx > ,
748+ fn_args : FnArgMap ) -> EvalResult {
743749 fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
744750
745751 // Try to compute the type of the expression based on the EvalHint.
@@ -776,7 +782,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
776782
777783 let result = match e. node {
778784 hir:: ExprUnary ( hir:: UnNeg , ref inner) => {
779- match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint) ) {
785+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint, fn_args ) ) {
780786 Float ( f) => Float ( -f) ,
781787 Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
782788 Uint ( i) => {
@@ -786,7 +792,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
786792 }
787793 }
788794 hir:: ExprUnary ( hir:: UnNot , ref inner) => {
789- match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint) ) {
795+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint, fn_args ) ) {
790796 Int ( i) => Int ( !i) ,
791797 Uint ( i) => const_uint_not ( i, expr_uint_type) ,
792798 Bool ( b) => Bool ( !b) ,
@@ -804,8 +810,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
804810 }
805811 _ => ty_hint
806812 } ;
807- match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint) ) ,
808- try!( eval_const_expr_partial ( tcx, & * * b, b_ty) ) ) {
813+ match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint, fn_args ) ) ,
814+ try!( eval_const_expr_partial ( tcx, & * * b, b_ty, fn_args ) ) ) {
809815 ( Float ( a) , Float ( b) ) => {
810816 match op. node {
811817 hir:: BiAdd => Float ( a + b) ,
@@ -912,7 +918,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
912918 }
913919 } ;
914920
915- let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint) ) ;
921+ let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint, fn_args ) ) ;
916922 match cast_const ( tcx, val, ety) {
917923 Ok ( val) => val,
918924 Err ( kind) => return Err ( ConstEvalErr { span : e. span , kind : kind } ) ,
@@ -990,6 +996,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
990996 Some ( def:: DefStruct ( _) ) => {
991997 return Ok ( ConstVal :: Struct ( e. id ) )
992998 }
999+ Some ( def:: DefLocal ( _, id) ) => {
1000+ debug ! ( "DefLocal({:?}): {:?}" , id, fn_args) ;
1001+ if let Some ( val) = fn_args. and_then ( |args| args. get ( & id) ) {
1002+ return Ok ( val. clone ( ) ) ;
1003+ } else {
1004+ ( None , None )
1005+ }
1006+ } ,
1007+ Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1008+ // FIXME: implement const methods?
9931009 _ => ( None , None )
9941010 } ;
9951011 let const_expr = match const_expr {
@@ -1007,14 +1023,68 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10071023 } else {
10081024 ty_hint
10091025 } ;
1010- try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
1026+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint, fn_args ) )
10111027 }
1028+ hir:: ExprCall ( ref callee, ref args) => {
1029+ let sub_ty_hint = if let ExprTypeChecked = ty_hint {
1030+ ExprTypeChecked
1031+ } else {
1032+ UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
1033+ } ;
1034+ let (
1035+ decl,
1036+ unsafety,
1037+ abi,
1038+ block,
1039+ ) = match try!( eval_const_expr_partial ( tcx, callee, sub_ty_hint, fn_args) ) {
1040+ Function ( did) => if did. is_local ( ) {
1041+ match tcx. map . find ( did. index . as_u32 ( ) ) {
1042+ Some ( ast_map:: NodeItem ( it) ) => match it. node {
1043+ hir:: ItemFn (
1044+ ref decl,
1045+ unsafety,
1046+ _, // no need to check for constness... either check_const
1047+ // already forbids this or we const eval over whatever
1048+ // we want
1049+ abi,
1050+ _, // ducktype generics? types are funky in const_eval
1051+ ref block,
1052+ ) => ( decl, unsafety, abi, block) ,
1053+ _ => signal ! ( e, NonConstPath ) ,
1054+ } ,
1055+ _ => signal ! ( e, NonConstPath ) ,
1056+ }
1057+ } else {
1058+ signal ! ( e, NonConstPath )
1059+ } ,
1060+ _ => signal ! ( e, NonConstPath ) ,
1061+ } ;
1062+ assert_eq ! ( decl. inputs. len( ) , args. len( ) ) ;
1063+ assert_eq ! ( unsafety, hir:: Unsafety :: Normal ) ;
1064+ assert_eq ! ( abi, abi:: Abi :: Rust ) ;
1065+
1066+ let mut call_args = NodeMap ( ) ;
1067+ for ( arg, arg_expr) in decl. inputs . iter ( ) . zip ( args. iter ( ) ) {
1068+ let arg_val = try!( eval_const_expr_partial (
1069+ tcx,
1070+ arg_expr,
1071+ sub_ty_hint,
1072+ fn_args
1073+ ) ) ;
1074+ debug ! ( "const call arg: {:?}" , arg) ;
1075+ let old = call_args. insert ( arg. pat . id , arg_val) ;
1076+ assert ! ( old. is_none( ) ) ;
1077+ }
1078+ let result = block. expr . as_ref ( ) . unwrap ( ) ;
1079+ debug ! ( "const call({:?})" , call_args) ;
1080+ try!( eval_const_expr_partial ( tcx, & * * result, ty_hint, Some ( & call_args) ) )
1081+ } ,
10121082 hir:: ExprLit ( ref lit) => {
10131083 lit_to_const ( & * * lit, ety)
10141084 }
10151085 hir:: ExprBlock ( ref block) => {
10161086 match block. expr {
1017- Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint) ) ,
1087+ Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint, fn_args ) ) ,
10181088 None => Int ( 0 )
10191089 }
10201090 }
@@ -1026,11 +1096,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10261096 } else {
10271097 UncheckedExprNoHint
10281098 } ;
1029- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
1099+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args ) {
10301100 if let Tuple ( tup_id) = c {
10311101 if let hir:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
10321102 if index. node < fields. len ( ) {
1033- return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint)
1103+ return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint, fn_args )
10341104 } else {
10351105 signal ! ( e, TupleIndexOutOfBounds ) ;
10361106 }
@@ -1051,14 +1121,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10511121 } else {
10521122 UncheckedExprNoHint
10531123 } ;
1054- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
1124+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args ) {
10551125 if let Struct ( struct_id) = c {
10561126 if let hir:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
10571127 // Check that the given field exists and evaluate it
10581128 // if the idents are compared run-pass/issue-19244 fails
10591129 if let Some ( f) = fields. iter ( ) . find ( |f| f. name . node
10601130 == field_name. node ) {
1061- return eval_const_expr_partial ( tcx, & * f. expr , base_hint)
1131+ return eval_const_expr_partial ( tcx, & * f. expr , base_hint, fn_args )
10621132 } else {
10631133 signal ! ( e, MissingStructField ) ;
10641134 }
@@ -1237,14 +1307,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
12371307pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
12381308 a : & Expr ,
12391309 b : & Expr ) -> Option < Ordering > {
1240- let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked ) {
1310+ let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked , None ) {
12411311 Ok ( a) => a,
12421312 Err ( e) => {
12431313 tcx. sess . span_err ( a. span , & e. description ( ) ) ;
12441314 return None ;
12451315 }
12461316 } ;
1247- let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
1317+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked , None ) {
12481318 Ok ( b) => b,
12491319 Err ( e) => {
12501320 tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments