@@ -403,6 +403,7 @@ pub enum ErrKind {
403
403
InvalidOpForUintInt ( hir:: BinOp_ ) ,
404
404
NegateOn ( ConstVal ) ,
405
405
NotOn ( ConstVal ) ,
406
+ CallOn ( ConstVal ) ,
406
407
407
408
NegateWithOverflow ( i64 ) ,
408
409
AddiWithOverflow ( i64 , i64 ) ,
@@ -419,6 +420,7 @@ pub enum ErrKind {
419
420
ShiftRightWithOverflow ,
420
421
MissingStructField ,
421
422
NonConstPath ,
423
+ UnimplementedConstVal ( & ' static str ) ,
422
424
UnresolvedPath ,
423
425
ExpectedConstTuple ,
424
426
ExpectedConstStruct ,
@@ -449,6 +451,7 @@ impl ConstEvalErr {
449
451
InvalidOpForUintInt ( ..) => "can't do this op on a usize and isize" . into_cow ( ) ,
450
452
NegateOn ( ref const_val) => format ! ( "negate on {}" , const_val. description( ) ) . into_cow ( ) ,
451
453
NotOn ( ref const_val) => format ! ( "not on {}" , const_val. description( ) ) . into_cow ( ) ,
454
+ CallOn ( ref const_val) => format ! ( "call on {}" , const_val. description( ) ) . into_cow ( ) ,
452
455
453
456
NegateWithOverflow ( ..) => "attempted to negate with overflow" . into_cow ( ) ,
454
457
AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
@@ -465,6 +468,8 @@ impl ConstEvalErr {
465
468
ShiftRightWithOverflow => "attempted right shift with overflow" . into_cow ( ) ,
466
469
MissingStructField => "nonexistent struct field" . into_cow ( ) ,
467
470
NonConstPath => "non-constant path in constant expression" . into_cow ( ) ,
471
+ UnimplementedConstVal ( what) =>
472
+ format ! ( "unimplemented constant expression: {}" , what) . into_cow ( ) ,
468
473
UnresolvedPath => "unresolved path in constant expression" . into_cow ( ) ,
469
474
ExpectedConstTuple => "expected constant tuple" . into_cow ( ) ,
470
475
ExpectedConstStruct => "expected constant struct" . into_cow ( ) ,
@@ -1043,8 +1048,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1043
1048
( None , None )
1044
1049
}
1045
1050
} ,
1046
- Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1047
- // FIXME: implement const methods?
1051
+ Some ( def:: DefMethod ( id) ) | Some ( def:: DefFn ( id, _) ) => return Ok ( Function ( id) ) ,
1048
1052
_ => ( None , None )
1049
1053
} ;
1050
1054
let const_expr = match const_expr {
@@ -1070,31 +1074,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1070
1074
} else {
1071
1075
UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
1072
1076
} ;
1073
- let (
1074
- decl,
1075
- block,
1076
- constness,
1077
- ) = match try!( eval_const_expr_partial ( tcx, callee, sub_ty_hint, fn_args) ) {
1078
- Function ( did) => if did. is_local ( ) {
1079
- match tcx. map . find ( did. index . as_u32 ( ) ) {
1080
- Some ( ast_map:: NodeItem ( it) ) => match it. node {
1081
- hir:: ItemFn (
1082
- ref decl,
1083
- hir:: Unsafety :: Normal ,
1084
- constness,
1085
- abi:: Abi :: Rust ,
1086
- _, // ducktype generics? types are funky in const_eval
1087
- ref block,
1088
- ) => ( decl, block, constness) ,
1089
- _ => signal ! ( e, NonConstPath ) ,
1090
- } ,
1091
- _ => signal ! ( e, NonConstPath ) ,
1092
- }
1093
- } else {
1094
- signal ! ( e, NonConstPath )
1095
- } ,
1096
- _ => signal ! ( e, NonConstPath ) ,
1097
- } ;
1077
+ let callee_val = try!( eval_const_expr_partial ( tcx, callee, sub_ty_hint, fn_args) ) ;
1078
+ let ( decl, block, constness) = try!( get_fn_def ( tcx, e, callee_val) ) ;
1098
1079
match ( ty_hint, constness) {
1099
1080
( ExprTypeChecked , _) => {
1100
1081
// no need to check for constness... either check_const
@@ -1441,3 +1422,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
1441
1422
} ;
1442
1423
compare_const_vals ( & a, & b)
1443
1424
}
1425
+
1426
+
1427
+ // returns Err if callee is not `Function`
1428
+ // `e` is only used for error reporting/spans
1429
+ fn get_fn_def < ' a > ( tcx : & ' a ty:: ctxt ,
1430
+ e : & hir:: Expr ,
1431
+ callee : ConstVal )
1432
+ -> Result < ( & ' a hir:: FnDecl , & ' a hir:: Block , hir:: Constness ) , ConstEvalErr > {
1433
+ let did = match callee {
1434
+ Function ( did) => did,
1435
+ callee => signal ! ( e, CallOn ( callee) ) ,
1436
+ } ;
1437
+ debug ! ( "fn call: {:?}" , tcx. map. get_if_local( did) ) ;
1438
+ match tcx. map . get_if_local ( did) {
1439
+ None => signal ! ( e, UnimplementedConstVal ( "calling non-local const fn" ) ) , // non-local
1440
+ Some ( ast_map:: NodeItem ( it) ) => match it. node {
1441
+ hir:: ItemFn (
1442
+ ref decl,
1443
+ hir:: Unsafety :: Normal ,
1444
+ constness,
1445
+ abi:: Abi :: Rust ,
1446
+ _, // ducktype generics? types are funky in const_eval
1447
+ ref block,
1448
+ ) => Ok ( ( & * * decl, & * * block, constness) ) ,
1449
+ _ => signal ! ( e, NonConstPath ) ,
1450
+ } ,
1451
+ Some ( ast_map:: NodeImplItem ( it) ) => match it. node {
1452
+ hir:: ImplItemKind :: Method (
1453
+ hir:: MethodSig {
1454
+ ref decl,
1455
+ unsafety : hir:: Unsafety :: Normal ,
1456
+ constness,
1457
+ abi : abi:: Abi :: Rust ,
1458
+ .. // ducktype generics? types are funky in const_eval
1459
+ } ,
1460
+ ref block,
1461
+ ) => Ok ( ( decl, block, constness) ) ,
1462
+ _ => signal ! ( e, NonConstPath ) ,
1463
+ } ,
1464
+ Some ( ast_map:: NodeTraitItem ( ..) ) => signal ! ( e, NonConstPath ) ,
1465
+ Some ( _) => unimplemented ! ( ) ,
1466
+ }
1467
+ }
0 commit comments