@@ -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,6 +254,7 @@ 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
@@ -271,6 +273,7 @@ impl PartialEq for ConstVal {
271
273
( & Bool ( a) , & Bool ( b) ) => a == b,
272
274
( & Struct ( a) , & Struct ( b) ) => a == b,
273
275
( & Tuple ( a) , & Tuple ( b) ) => a == b,
276
+ ( & Function ( a) , & Function ( b) ) => a == b,
274
277
_ => false ,
275
278
}
276
279
}
@@ -288,6 +291,7 @@ impl ConstVal {
288
291
Bool ( _) => "boolean" ,
289
292
Struct ( _) => "struct" ,
290
293
Tuple ( _) => "tuple" ,
294
+ Function ( _) => "function definition" ,
291
295
}
292
296
}
293
297
}
@@ -350,12 +354,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat>
350
354
}
351
355
352
356
pub 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 ) {
354
358
Ok ( r) => r,
355
359
Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
356
360
}
357
361
}
358
362
363
+ pub type FnArgMap < ' a > = Option < & ' a NodeMap < ConstVal > > ;
359
364
360
365
#[ derive( Clone ) ]
361
366
pub struct ConstEvalErr {
@@ -739,7 +744,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
739
744
/// computing the length of an array. (See also the FIXME above EvalHint.)
740
745
pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
741
746
e : & Expr ,
742
- ty_hint : EvalHint < ' tcx > ) -> EvalResult {
747
+ ty_hint : EvalHint < ' tcx > ,
748
+ fn_args : FnArgMap ) -> EvalResult {
743
749
fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
744
750
745
751
// 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>,
776
782
777
783
let result = match e. node {
778
784
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 ) ) {
780
786
Float ( f) => Float ( -f) ,
781
787
Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
782
788
Uint ( i) => {
@@ -786,7 +792,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
786
792
}
787
793
}
788
794
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 ) ) {
790
796
Int ( i) => Int ( !i) ,
791
797
Uint ( i) => const_uint_not ( i, expr_uint_type) ,
792
798
Bool ( b) => Bool ( !b) ,
@@ -804,8 +810,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
804
810
}
805
811
_ => ty_hint
806
812
} ;
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 ) ) ) {
809
815
( Float ( a) , Float ( b) ) => {
810
816
match op. node {
811
817
hir:: BiAdd => Float ( a + b) ,
@@ -912,7 +918,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
912
918
}
913
919
} ;
914
920
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 ) ) ;
916
922
match cast_const ( tcx, val, ety) {
917
923
Ok ( val) => val,
918
924
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>,
990
996
Some ( def:: DefStruct ( _) ) => {
991
997
return Ok ( ConstVal :: Struct ( e. id ) )
992
998
}
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?
993
1009
_ => ( None , None )
994
1010
} ;
995
1011
let const_expr = match const_expr {
@@ -1007,14 +1023,68 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1007
1023
} else {
1008
1024
ty_hint
1009
1025
} ;
1010
- try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
1026
+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint, fn_args ) )
1011
1027
}
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
+ } ,
1012
1082
hir:: ExprLit ( ref lit) => {
1013
1083
lit_to_const ( & * * lit, ety)
1014
1084
}
1015
1085
hir:: ExprBlock ( ref block) => {
1016
1086
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 ) ) ,
1018
1088
None => Int ( 0 )
1019
1089
}
1020
1090
}
@@ -1026,11 +1096,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1026
1096
} else {
1027
1097
UncheckedExprNoHint
1028
1098
} ;
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 ) {
1030
1100
if let Tuple ( tup_id) = c {
1031
1101
if let hir:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
1032
1102
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 )
1034
1104
} else {
1035
1105
signal ! ( e, TupleIndexOutOfBounds ) ;
1036
1106
}
@@ -1051,14 +1121,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1051
1121
} else {
1052
1122
UncheckedExprNoHint
1053
1123
} ;
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 ) {
1055
1125
if let Struct ( struct_id) = c {
1056
1126
if let hir:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
1057
1127
// Check that the given field exists and evaluate it
1058
1128
// if the idents are compared run-pass/issue-19244 fails
1059
1129
if let Some ( f) = fields. iter ( ) . find ( |f| f. name . node
1060
1130
== 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 )
1062
1132
} else {
1063
1133
signal ! ( e, MissingStructField ) ;
1064
1134
}
@@ -1237,14 +1307,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
1237
1307
pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
1238
1308
a : & Expr ,
1239
1309
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 ) {
1241
1311
Ok ( a) => a,
1242
1312
Err ( e) => {
1243
1313
tcx. sess . span_err ( a. span , & e. description ( ) ) ;
1244
1314
return None ;
1245
1315
}
1246
1316
} ;
1247
- let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
1317
+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked , None ) {
1248
1318
Ok ( b) => b,
1249
1319
Err ( e) => {
1250
1320
tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments