Skip to content

Commit 8e64e22

Browse files
committed
implement calling of const fn-methods in true constants
1 parent e5aa92a commit 8e64e22

File tree

5 files changed

+56
-29
lines changed

5 files changed

+56
-29
lines changed

src/librustc/middle/const_eval.rs

+51-27
Original file line numberDiff line numberDiff line change
@@ -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+
}

src/test/compile-fail/const-eval-span.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
struct S(i32);
1515

1616
const CONSTANT: S = S(0);
17-
//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080]
17+
//~^ ERROR: constant evaluation error: call on struct [E0080]
1818

1919
enum E {
2020
V = CONSTANT,

src/test/compile-fail/const-fn-stability-calls-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ extern crate const_fn_lib;
1717
use const_fn_lib::foo;
1818

1919
fn main() {
20-
let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
20+
let x: [usize; foo()] = [];
21+
//~^ ERROR unimplemented constant expression: calling non-local const fn [E0250]
2122
}

src/test/run-pass/const-fn-method.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ const FOO: Foo = Foo::new();
2222

2323
pub fn main() {
2424
assert_eq!(FOO.value, 22);
25+
let _: [&'static str; Foo::new().value as usize] = ["hey"; 22];
2526
}

src/test/run-pass/const-fn.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ fn main() {
2929

3030
assert_eq!(DIFF, 22);
3131

32+
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
3233
}

0 commit comments

Comments
 (0)