@@ -19,13 +19,14 @@ use front::map::blocks::FnLikeNode;
19
19
use metadata:: csearch;
20
20
use metadata:: inline:: InlinedItem ;
21
21
use middle:: { astencode, def, infer, subst, traits} ;
22
- use middle:: def_id:: { DefId } ;
22
+ use middle:: def_id:: DefId ;
23
23
use middle:: pat_util:: def_to_path;
24
24
use middle:: ty:: { self , Ty } ;
25
25
use middle:: astconv_util:: ast_ty_to_prim_ty;
26
26
use util:: num:: ToPrimitive ;
27
+ use util:: nodemap:: NodeMap ;
27
28
28
- use syntax:: ast;
29
+ use syntax:: { ast, abi } ;
29
30
use rustc_front:: hir:: Expr ;
30
31
use rustc_front:: hir;
31
32
use rustc_front:: visit:: FnKind ;
@@ -253,14 +254,14 @@ pub enum ConstVal {
253
254
Bool ( bool ) ,
254
255
Struct ( ast:: NodeId ) ,
255
256
Tuple ( ast:: NodeId ) ,
257
+ Function ( DefId ) ,
256
258
}
257
259
258
260
/// Note that equality for `ConstVal` means that the it is the same
259
261
/// constant, not that the rust values are equal. In particular, `NaN
260
262
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
261
263
/// are considering unequal).
262
264
impl PartialEq for ConstVal {
263
- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
264
265
fn eq ( & self , other : & ConstVal ) -> bool {
265
266
match ( self , other) {
266
267
( & Float ( a) , & Float ( b) ) => unsafe { transmute :: < _ , u64 > ( a) == transmute :: < _ , u64 > ( b) } ,
@@ -271,6 +272,7 @@ impl PartialEq for ConstVal {
271
272
( & Bool ( a) , & Bool ( b) ) => a == b,
272
273
( & Struct ( a) , & Struct ( b) ) => a == b,
273
274
( & Tuple ( a) , & Tuple ( b) ) => a == b,
275
+ ( & Function ( a) , & Function ( b) ) => a == b,
274
276
_ => false ,
275
277
}
276
278
}
@@ -288,6 +290,7 @@ impl ConstVal {
288
290
Bool ( _) => "boolean" ,
289
291
Struct ( _) => "struct" ,
290
292
Tuple ( _) => "tuple" ,
293
+ Function ( _) => "function definition" ,
291
294
}
292
295
}
293
296
}
@@ -350,12 +353,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat>
350
353
}
351
354
352
355
pub 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 ) {
354
357
Ok ( r) => r,
355
358
Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
356
359
}
357
360
}
358
361
362
+ pub type FnArgMap < ' a > = Option < & ' a NodeMap < ConstVal > > ;
359
363
360
364
#[ derive( Clone ) ]
361
365
pub struct ConstEvalErr {
@@ -739,7 +743,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
739
743
/// computing the length of an array. (See also the FIXME above EvalHint.)
740
744
pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
741
745
e : & Expr ,
742
- ty_hint : EvalHint < ' tcx > ) -> EvalResult {
746
+ ty_hint : EvalHint < ' tcx > ,
747
+ fn_args : FnArgMap ) -> EvalResult {
743
748
fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
744
749
745
750
// 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>,
776
781
777
782
let result = match e. node {
778
783
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 ) ) {
780
785
Float ( f) => Float ( -f) ,
781
786
Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
782
787
Uint ( i) => {
@@ -786,7 +791,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
786
791
}
787
792
}
788
793
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 ) ) {
790
795
Int ( i) => Int ( !i) ,
791
796
Uint ( i) => const_uint_not ( i, expr_uint_type) ,
792
797
Bool ( b) => Bool ( !b) ,
@@ -804,8 +809,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
804
809
}
805
810
_ => ty_hint
806
811
} ;
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 ) ) ) {
809
814
( Float ( a) , Float ( b) ) => {
810
815
match op. node {
811
816
hir:: BiAdd => Float ( a + b) ,
@@ -912,7 +917,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
912
917
}
913
918
} ;
914
919
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 ) ) ;
916
921
match cast_const ( tcx, val, ety) {
917
922
Ok ( val) => val,
918
923
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>,
990
995
Some ( def:: DefStruct ( _) ) => {
991
996
return Ok ( ConstVal :: Struct ( e. id ) )
992
997
}
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?
993
1008
_ => ( None , None )
994
1009
} ;
995
1010
let const_expr = match const_expr {
@@ -1007,14 +1022,76 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1007
1022
} else {
1008
1023
ty_hint
1009
1024
} ;
1010
- try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
1025
+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint, fn_args ) )
1011
1026
}
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
+ } ,
1012
1089
hir:: ExprLit ( ref lit) => {
1013
1090
lit_to_const ( & * * lit, ety)
1014
1091
}
1015
1092
hir:: ExprBlock ( ref block) => {
1016
1093
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 ) ) ,
1018
1095
None => Int ( 0 )
1019
1096
}
1020
1097
}
@@ -1026,11 +1103,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1026
1103
} else {
1027
1104
UncheckedExprNoHint
1028
1105
} ;
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 ) {
1030
1107
if let Tuple ( tup_id) = c {
1031
1108
if let hir:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
1032
1109
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 )
1034
1111
} else {
1035
1112
signal ! ( e, TupleIndexOutOfBounds ) ;
1036
1113
}
@@ -1051,14 +1128,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1051
1128
} else {
1052
1129
UncheckedExprNoHint
1053
1130
} ;
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 ) {
1055
1132
if let Struct ( struct_id) = c {
1056
1133
if let hir:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
1057
1134
// Check that the given field exists and evaluate it
1058
1135
// if the idents are compared run-pass/issue-19244 fails
1059
1136
if let Some ( f) = fields. iter ( ) . find ( |f| f. name . node
1060
1137
== 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 )
1062
1139
} else {
1063
1140
signal ! ( e, MissingStructField ) ;
1064
1141
}
@@ -1237,14 +1314,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
1237
1314
pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
1238
1315
a : & Expr ,
1239
1316
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 ) {
1241
1318
Ok ( a) => a,
1242
1319
Err ( e) => {
1243
1320
tcx. sess . span_err ( a. span , & e. description ( ) ) ;
1244
1321
return None ;
1245
1322
}
1246
1323
} ;
1247
- let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
1324
+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked , None ) {
1248
1325
Ok ( b) => b,
1249
1326
Err ( e) => {
1250
1327
tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments