@@ -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,14 +254,14 @@ 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
259261/// constant, not that the rust values are equal. In particular, `NaN
260262/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
261263/// are considering unequal).
262264impl PartialEq for ConstVal {
263- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
264265 fn eq ( & self , other : & ConstVal ) -> bool {
265266 match ( self , other) {
266267 ( & Float ( a) , & Float ( b) ) => unsafe { transmute :: < _ , u64 > ( a) == transmute :: < _ , u64 > ( b) } ,
@@ -271,6 +272,7 @@ impl PartialEq for ConstVal {
271272 ( & Bool ( a) , & Bool ( b) ) => a == b,
272273 ( & Struct ( a) , & Struct ( b) ) => a == b,
273274 ( & Tuple ( a) , & Tuple ( b) ) => a == b,
275+ ( & Function ( a) , & Function ( b) ) => a == b,
274276 _ => false ,
275277 }
276278 }
@@ -288,6 +290,7 @@ impl ConstVal {
288290 Bool ( _) => "boolean" ,
289291 Struct ( _) => "struct" ,
290292 Tuple ( _) => "tuple" ,
293+ Function ( _) => "function definition" ,
291294 }
292295 }
293296}
@@ -350,12 +353,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat>
350353}
351354
352355pub fn eval_const_expr ( tcx : & ty:: ctxt , e : & Expr ) -> ConstVal {
353- match eval_const_expr_partial ( tcx, e, ExprTypeChecked ) {
356+ match eval_const_expr_partial ( tcx, e, ExprTypeChecked , None ) {
354357 Ok ( r) => r,
355358 Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
356359 }
357360}
358361
362+ pub type FnArgMap < ' a > = Option < & ' a NodeMap < ConstVal > > ;
359363
360364#[ derive( Clone ) ]
361365pub struct ConstEvalErr {
@@ -739,7 +743,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
739743/// computing the length of an array. (See also the FIXME above EvalHint.)
740744pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
741745 e : & Expr ,
742- ty_hint : EvalHint < ' tcx > ) -> EvalResult {
746+ ty_hint : EvalHint < ' tcx > ,
747+ fn_args : FnArgMap ) -> EvalResult {
743748 fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
744749
745750 // Try to compute the type of the expression based on the EvalHint.
@@ -776,7 +781,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
776781
777782 let result = match e. node {
778783 hir:: ExprUnary ( hir:: UnNeg , ref inner) => {
779- match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint) ) {
784+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint, fn_args ) ) {
780785 Float ( f) => Float ( -f) ,
781786 Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
782787 Uint ( i) => {
@@ -786,7 +791,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
786791 }
787792 }
788793 hir:: ExprUnary ( hir:: UnNot , ref inner) => {
789- match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint) ) {
794+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint, fn_args ) ) {
790795 Int ( i) => Int ( !i) ,
791796 Uint ( i) => const_uint_not ( i, expr_uint_type) ,
792797 Bool ( b) => Bool ( !b) ,
@@ -804,8 +809,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
804809 }
805810 _ => ty_hint
806811 } ;
807- match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint) ) ,
808- try!( eval_const_expr_partial ( tcx, & * * b, b_ty) ) ) {
812+ match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint, fn_args ) ) ,
813+ try!( eval_const_expr_partial ( tcx, & * * b, b_ty, fn_args ) ) ) {
809814 ( Float ( a) , Float ( b) ) => {
810815 match op. node {
811816 hir:: BiAdd => Float ( a + b) ,
@@ -912,7 +917,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
912917 }
913918 } ;
914919
915- let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint) ) ;
920+ let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint, fn_args ) ) ;
916921 match cast_const ( tcx, val, ety) {
917922 Ok ( val) => val,
918923 Err ( kind) => return Err ( ConstEvalErr { span : e. span , kind : kind } ) ,
@@ -990,6 +995,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
990995 Some ( def:: DefStruct ( _) ) => {
991996 return Ok ( ConstVal :: Struct ( e. id ) )
992997 }
998+ Some ( def:: DefLocal ( _, id) ) => {
999+ debug ! ( "DefLocal({:?}): {:?}" , id, fn_args) ;
1000+ if let Some ( val) = fn_args. and_then ( |args| args. get ( & id) ) {
1001+ return Ok ( val. clone ( ) ) ;
1002+ } else {
1003+ ( None , None )
1004+ }
1005+ } ,
1006+ Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1007+ // FIXME: implement const methods?
9931008 _ => ( None , None )
9941009 } ;
9951010 let const_expr = match const_expr {
@@ -1007,14 +1022,76 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10071022 } else {
10081023 ty_hint
10091024 } ;
1010- try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
1025+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint, fn_args ) )
10111026 }
1027+ hir:: ExprCall ( ref callee, ref args) => {
1028+ let sub_ty_hint = if let ExprTypeChecked = ty_hint {
1029+ ExprTypeChecked
1030+ } else {
1031+ UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
1032+ } ;
1033+ let (
1034+ decl,
1035+ unsafety,
1036+ abi,
1037+ block,
1038+ constness,
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+ constness,
1047+ abi,
1048+ _, // ducktype generics? types are funky in const_eval
1049+ ref block,
1050+ ) => ( decl, unsafety, abi, block, constness) ,
1051+ _ => signal ! ( e, NonConstPath ) ,
1052+ } ,
1053+ _ => signal ! ( e, NonConstPath ) ,
1054+ }
1055+ } else {
1056+ signal ! ( e, NonConstPath )
1057+ } ,
1058+ _ => signal ! ( e, NonConstPath ) ,
1059+ } ;
1060+ if let ExprTypeChecked = ty_hint {
1061+ // no need to check for constness... either check_const
1062+ // already forbids this or we const eval over whatever
1063+ // we want
1064+ } else {
1065+ // we don't know much about the function, so we force it to be a const fn
1066+ // so compilation will fail later in case the const fn's body is not const
1067+ assert_eq ! ( constness, hir:: Constness :: Const )
1068+ }
1069+ assert_eq ! ( decl. inputs. len( ) , args. len( ) ) ;
1070+ assert_eq ! ( unsafety, hir:: Unsafety :: Normal ) ;
1071+ assert_eq ! ( abi, abi:: Abi :: Rust ) ;
1072+
1073+ let mut call_args = NodeMap ( ) ;
1074+ for ( arg, arg_expr) in decl. inputs . iter ( ) . zip ( args. iter ( ) ) {
1075+ let arg_val = try!( eval_const_expr_partial (
1076+ tcx,
1077+ arg_expr,
1078+ sub_ty_hint,
1079+ fn_args
1080+ ) ) ;
1081+ debug ! ( "const call arg: {:?}" , arg) ;
1082+ let old = call_args. insert ( arg. pat . id , arg_val) ;
1083+ assert ! ( old. is_none( ) ) ;
1084+ }
1085+ let result = block. expr . as_ref ( ) . unwrap ( ) ;
1086+ debug ! ( "const call({:?})" , call_args) ;
1087+ try!( eval_const_expr_partial ( tcx, & * * result, ty_hint, Some ( & call_args) ) )
1088+ } ,
10121089 hir:: ExprLit ( ref lit) => {
10131090 lit_to_const ( & * * lit, ety)
10141091 }
10151092 hir:: ExprBlock ( ref block) => {
10161093 match block. expr {
1017- Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint) ) ,
1094+ Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint, fn_args ) ) ,
10181095 None => Int ( 0 )
10191096 }
10201097 }
@@ -1026,11 +1103,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10261103 } else {
10271104 UncheckedExprNoHint
10281105 } ;
1029- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
1106+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args ) {
10301107 if let Tuple ( tup_id) = c {
10311108 if let hir:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
10321109 if index. node < fields. len ( ) {
1033- return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint)
1110+ return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint, fn_args )
10341111 } else {
10351112 signal ! ( e, TupleIndexOutOfBounds ) ;
10361113 }
@@ -1051,14 +1128,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10511128 } else {
10521129 UncheckedExprNoHint
10531130 } ;
1054- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
1131+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args ) {
10551132 if let Struct ( struct_id) = c {
10561133 if let hir:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
10571134 // Check that the given field exists and evaluate it
10581135 // if the idents are compared run-pass/issue-19244 fails
10591136 if let Some ( f) = fields. iter ( ) . find ( |f| f. name . node
10601137 == field_name. node ) {
1061- return eval_const_expr_partial ( tcx, & * f. expr , base_hint)
1138+ return eval_const_expr_partial ( tcx, & * f. expr , base_hint, fn_args )
10621139 } else {
10631140 signal ! ( e, MissingStructField ) ;
10641141 }
@@ -1237,14 +1314,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
12371314pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
12381315 a : & Expr ,
12391316 b : & Expr ) -> Option < Ordering > {
1240- let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked ) {
1317+ let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked , None ) {
12411318 Ok ( a) => a,
12421319 Err ( e) => {
12431320 tcx. sess . span_err ( a. span , & e. description ( ) ) ;
12441321 return None ;
12451322 }
12461323 } ;
1247- let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
1324+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked , None ) {
12481325 Ok ( b) => b,
12491326 Err ( e) => {
12501327 tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments