@@ -403,6 +403,7 @@ pub enum ErrKind {
403403 InvalidOpForUintInt ( hir:: BinOp_ ) ,
404404 NegateOn ( ConstVal ) ,
405405 NotOn ( ConstVal ) ,
406+ CallOn ( ConstVal ) ,
406407
407408 NegateWithOverflow ( i64 ) ,
408409 AddiWithOverflow ( i64 , i64 ) ,
@@ -419,6 +420,7 @@ pub enum ErrKind {
419420 ShiftRightWithOverflow ,
420421 MissingStructField ,
421422 NonConstPath ,
423+ UnimplementedConstVal ( & ' static str ) ,
422424 UnresolvedPath ,
423425 ExpectedConstTuple ,
424426 ExpectedConstStruct ,
@@ -449,6 +451,7 @@ impl ConstEvalErr {
449451 InvalidOpForUintInt ( ..) => "can't do this op on a usize and isize" . into_cow ( ) ,
450452 NegateOn ( ref const_val) => format ! ( "negate on {}" , const_val. description( ) ) . into_cow ( ) ,
451453 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 ( ) ,
452455
453456 NegateWithOverflow ( ..) => "attempted to negate with overflow" . into_cow ( ) ,
454457 AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
@@ -465,6 +468,8 @@ impl ConstEvalErr {
465468 ShiftRightWithOverflow => "attempted right shift with overflow" . into_cow ( ) ,
466469 MissingStructField => "nonexistent struct field" . into_cow ( ) ,
467470 NonConstPath => "non-constant path in constant expression" . into_cow ( ) ,
471+ UnimplementedConstVal ( what) =>
472+ format ! ( "unimplemented constant expression: {}" , what) . into_cow ( ) ,
468473 UnresolvedPath => "unresolved path in constant expression" . into_cow ( ) ,
469474 ExpectedConstTuple => "expected constant tuple" . into_cow ( ) ,
470475 ExpectedConstStruct => "expected constant struct" . into_cow ( ) ,
@@ -1043,8 +1048,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10431048 ( None , None )
10441049 }
10451050 } ,
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) ) ,
10481052 _ => ( None , None )
10491053 } ;
10501054 let const_expr = match const_expr {
@@ -1070,31 +1074,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10701074 } else {
10711075 UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
10721076 } ;
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) ) ;
10981079 match ( ty_hint, constness) {
10991080 ( ExprTypeChecked , _) => {
11001081 // no need to check for constness... either check_const
@@ -1441,3 +1422,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
14411422 } ;
14421423 compare_const_vals ( & a, & b)
14431424}
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