@@ -395,6 +395,7 @@ pub enum ErrKind {
395395 InvalidOpForUintInt ( hir:: BinOp_ ) ,
396396 NegateOn ( ConstVal ) ,
397397 NotOn ( ConstVal ) ,
398+ CallOn ( ConstVal ) ,
398399
399400 NegateWithOverflow ( i64 ) ,
400401 AddiWithOverflow ( i64 , i64 ) ,
@@ -411,6 +412,7 @@ pub enum ErrKind {
411412 ShiftRightWithOverflow ,
412413 MissingStructField ,
413414 NonConstPath ,
415+ UnimplementedConstVal ( & ' static str ) ,
414416 UnresolvedPath ,
415417 ExpectedConstTuple ,
416418 ExpectedConstStruct ,
@@ -435,6 +437,7 @@ impl ConstEvalErr {
435437 InvalidOpForUintInt ( ..) => "can't do this op on a usize and isize" . into_cow ( ) ,
436438 NegateOn ( ref const_val) => format ! ( "negate on {}" , const_val. description( ) ) . into_cow ( ) ,
437439 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 ( ) ,
438441
439442 NegateWithOverflow ( ..) => "attempted to negate with overflow" . into_cow ( ) ,
440443 AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
@@ -451,6 +454,8 @@ impl ConstEvalErr {
451454 ShiftRightWithOverflow => "attempted right shift with overflow" . into_cow ( ) ,
452455 MissingStructField => "nonexistent struct field" . into_cow ( ) ,
453456 NonConstPath => "non-constant path in constant expression" . into_cow ( ) ,
457+ UnimplementedConstVal ( what) =>
458+ format ! ( "unimplemented constant expression: {}" , what) . into_cow ( ) ,
454459 UnresolvedPath => "unresolved path in constant expression" . into_cow ( ) ,
455460 ExpectedConstTuple => "expected constant tuple" . into_cow ( ) ,
456461 ExpectedConstStruct => "expected constant struct" . into_cow ( ) ,
@@ -1023,8 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10231028 ( None , None )
10241029 }
10251030 } ,
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) ) ,
10281032 _ => ( None , None )
10291033 } ;
10301034 let const_expr = match const_expr {
@@ -1050,31 +1054,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10501054 } else {
10511055 UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
10521056 } ;
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) ) ;
10781059 match ( ty_hint, constness) {
10791060 ( ExprTypeChecked , _) => {
10801061 // no need to check for constness... either check_const
@@ -1349,3 +1330,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
13491330 } ;
13501331 compare_const_vals ( & a, & b)
13511332}
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