@@ -395,6 +395,7 @@ pub enum ErrKind {
395
395
InvalidOpForUintInt ( hir:: BinOp_ ) ,
396
396
NegateOn ( ConstVal ) ,
397
397
NotOn ( ConstVal ) ,
398
+ CallOn ( ConstVal ) ,
398
399
399
400
NegateWithOverflow ( i64 ) ,
400
401
AddiWithOverflow ( i64 , i64 ) ,
@@ -411,6 +412,7 @@ pub enum ErrKind {
411
412
ShiftRightWithOverflow ,
412
413
MissingStructField ,
413
414
NonConstPath ,
415
+ UnimplementedConstVal ( & ' static str ) ,
414
416
UnresolvedPath ,
415
417
ExpectedConstTuple ,
416
418
ExpectedConstStruct ,
@@ -435,6 +437,7 @@ impl ConstEvalErr {
435
437
InvalidOpForUintInt ( ..) => "can't do this op on a usize and isize" . into_cow ( ) ,
436
438
NegateOn ( ref const_val) => format ! ( "negate on {}" , const_val. description( ) ) . into_cow ( ) ,
437
439
NotOn ( ref const_val) => format ! ( "not on {}" , const_val. description( ) ) . into_cow ( ) ,
440
+ CallOn ( ref const_val) => format ! ( "call on {}" , const_val. description( ) ) . into_cow ( ) ,
438
441
439
442
NegateWithOverflow ( ..) => "attempted to negate with overflow" . into_cow ( ) ,
440
443
AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
@@ -451,6 +454,8 @@ impl ConstEvalErr {
451
454
ShiftRightWithOverflow => "attempted right shift with overflow" . into_cow ( ) ,
452
455
MissingStructField => "nonexistent struct field" . into_cow ( ) ,
453
456
NonConstPath => "non-constant path in constant expression" . into_cow ( ) ,
457
+ UnimplementedConstVal ( what) =>
458
+ format ! ( "unimplemented constant expression: {}" , what) . into_cow ( ) ,
454
459
UnresolvedPath => "unresolved path in constant expression" . into_cow ( ) ,
455
460
ExpectedConstTuple => "expected constant tuple" . into_cow ( ) ,
456
461
ExpectedConstStruct => "expected constant struct" . into_cow ( ) ,
@@ -1023,8 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1023
1028
( None , None )
1024
1029
}
1025
1030
} ,
1026
- Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1027
- // FIXME: implement const methods?
1031
+ Some ( def:: DefMethod ( id) ) | Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1028
1032
_ => ( None , None )
1029
1033
} ;
1030
1034
let const_expr = match const_expr {
@@ -1050,31 +1054,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1050
1054
} else {
1051
1055
UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
1052
1056
} ;
1053
- let (
1054
- decl,
1055
- block,
1056
- constness,
1057
- ) = match try!( eval_const_expr_partial ( tcx, callee, sub_ty_hint, fn_args) ) {
1058
- Function ( did) => if did. is_local ( ) {
1059
- match tcx. map . find ( did. index . as_u32 ( ) ) {
1060
- Some ( ast_map:: NodeItem ( it) ) => match it. node {
1061
- hir:: ItemFn (
1062
- ref decl,
1063
- hir:: Unsafety :: Normal ,
1064
- constness,
1065
- abi:: Abi :: Rust ,
1066
- _, // ducktype generics? types are funky in const_eval
1067
- ref block,
1068
- ) => ( decl, block, constness) ,
1069
- _ => signal ! ( e, NonConstPath ) ,
1070
- } ,
1071
- _ => signal ! ( e, NonConstPath ) ,
1072
- }
1073
- } else {
1074
- signal ! ( e, NonConstPath )
1075
- } ,
1076
- _ => signal ! ( e, NonConstPath ) ,
1077
- } ;
1057
+ let callee_val = try!( eval_const_expr_partial ( tcx, callee, sub_ty_hint, fn_args) ) ;
1058
+ let ( decl, block, constness) = try!( get_fn_def ( tcx, e, callee_val) ) ;
1078
1059
match ( ty_hint, constness) {
1079
1060
( ExprTypeChecked , _) => {
1080
1061
// no need to check for constness... either check_const
@@ -1349,3 +1330,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
1349
1330
} ;
1350
1331
compare_const_vals ( & a, & b)
1351
1332
}
1333
+
1334
+
1335
+ // returns Err if callee is not `Function`
1336
+ // `e` is only used for error reporting/spans
1337
+ fn get_fn_def < ' a > ( tcx : & ' a ty:: ctxt ,
1338
+ e : & hir:: Expr ,
1339
+ callee : ConstVal )
1340
+ -> Result < ( & ' a hir:: FnDecl , & ' a hir:: Block , hir:: Constness ) , ConstEvalErr > {
1341
+ let did = match callee {
1342
+ Function ( did) => did,
1343
+ callee => signal ! ( e, CallOn ( callee) ) ,
1344
+ } ;
1345
+ debug ! ( "fn call: {:?}" , tcx. map. get_if_local( did) ) ;
1346
+ match tcx. map . get_if_local ( did) {
1347
+ None => signal ! ( e, UnimplementedConstVal ( "calling non-local const fn" ) ) , // non-local
1348
+ Some ( ast_map:: NodeItem ( it) ) => match it. node {
1349
+ hir:: ItemFn (
1350
+ ref decl,
1351
+ hir:: Unsafety :: Normal ,
1352
+ constness,
1353
+ abi:: Abi :: Rust ,
1354
+ _, // ducktype generics? types are funky in const_eval
1355
+ ref block,
1356
+ ) => Ok ( ( & * * decl, & * * block, constness) ) ,
1357
+ _ => signal ! ( e, NonConstPath ) ,
1358
+ } ,
1359
+ Some ( ast_map:: NodeImplItem ( it) ) => match it. node {
1360
+ hir:: ImplItemKind :: Method (
1361
+ hir:: MethodSig {
1362
+ ref decl,
1363
+ unsafety : hir:: Unsafety :: Normal ,
1364
+ constness,
1365
+ abi : abi:: Abi :: Rust ,
1366
+ .. // ducktype generics? types are funky in const_eval
1367
+ } ,
1368
+ ref block,
1369
+ ) => Ok ( ( decl, block, constness) ) ,
1370
+ _ => signal ! ( e, NonConstPath ) ,
1371
+ } ,
1372
+ Some ( ast_map:: NodeTraitItem ( ..) ) => signal ! ( e, NonConstPath ) ,
1373
+ Some ( _) => unimplemented ! ( ) ,
1374
+ }
1375
+ }
0 commit comments