implement calling of const fn
-methods in true constants
This commit is contained in:
parent
e5aa92a0df
commit
8e64e22ef7
5 changed files with 56 additions and 29 deletions
|
@ -395,6 +395,7 @@ pub enum ErrKind {
|
|||
InvalidOpForUintInt(hir::BinOp_),
|
||||
NegateOn(ConstVal),
|
||||
NotOn(ConstVal),
|
||||
CallOn(ConstVal),
|
||||
|
||||
NegateWithOverflow(i64),
|
||||
AddiWithOverflow(i64, i64),
|
||||
|
@ -411,6 +412,7 @@ pub enum ErrKind {
|
|||
ShiftRightWithOverflow,
|
||||
MissingStructField,
|
||||
NonConstPath,
|
||||
UnimplementedConstVal(&'static str),
|
||||
UnresolvedPath,
|
||||
ExpectedConstTuple,
|
||||
ExpectedConstStruct,
|
||||
|
@ -435,6 +437,7 @@ impl ConstEvalErr {
|
|||
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
|
||||
NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
|
||||
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
|
||||
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
|
||||
|
||||
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
|
||||
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
|
||||
|
@ -451,6 +454,8 @@ impl ConstEvalErr {
|
|||
ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
|
||||
MissingStructField => "nonexistent struct field".into_cow(),
|
||||
NonConstPath => "non-constant path in constant expression".into_cow(),
|
||||
UnimplementedConstVal(what) =>
|
||||
format!("unimplemented constant expression: {}", what).into_cow(),
|
||||
UnresolvedPath => "unresolved path in constant expression".into_cow(),
|
||||
ExpectedConstTuple => "expected constant tuple".into_cow(),
|
||||
ExpectedConstStruct => "expected constant struct".into_cow(),
|
||||
|
@ -1023,8 +1028,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
(None, None)
|
||||
}
|
||||
},
|
||||
Some(def::DefFn(id, _)) => return Ok(Function(id)),
|
||||
// FIXME: implement const methods?
|
||||
Some(def::DefMethod(id)) | Some(def::DefFn(id, _)) => return Ok(Function(id)),
|
||||
_ => (None, None)
|
||||
};
|
||||
let const_expr = match const_expr {
|
||||
|
@ -1050,31 +1054,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
} else {
|
||||
UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
|
||||
};
|
||||
let (
|
||||
decl,
|
||||
block,
|
||||
constness,
|
||||
) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
|
||||
Function(did) => if did.is_local() {
|
||||
match tcx.map.find(did.index.as_u32()) {
|
||||
Some(ast_map::NodeItem(it)) => match it.node {
|
||||
hir::ItemFn(
|
||||
ref decl,
|
||||
hir::Unsafety::Normal,
|
||||
constness,
|
||||
abi::Abi::Rust,
|
||||
_, // ducktype generics? types are funky in const_eval
|
||||
ref block,
|
||||
) => (decl, block, constness),
|
||||
_ => signal!(e, NonConstPath),
|
||||
},
|
||||
_ => signal!(e, NonConstPath),
|
||||
}
|
||||
} else {
|
||||
signal!(e, NonConstPath)
|
||||
},
|
||||
_ => signal!(e, NonConstPath),
|
||||
};
|
||||
let callee_val = try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args));
|
||||
let (decl, block, constness) = try!(get_fn_def(tcx, e, callee_val));
|
||||
match (ty_hint, constness) {
|
||||
(ExprTypeChecked, _) => {
|
||||
// no need to check for constness... either check_const
|
||||
|
@ -1349,3 +1330,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
};
|
||||
compare_const_vals(&a, &b)
|
||||
}
|
||||
|
||||
|
||||
// returns Err if callee is not `Function`
|
||||
// `e` is only used for error reporting/spans
|
||||
fn get_fn_def<'a>(tcx: &'a ty::ctxt,
|
||||
e: &hir::Expr,
|
||||
callee: ConstVal)
|
||||
-> Result<(&'a hir::FnDecl, &'a hir::Block, hir::Constness), ConstEvalErr> {
|
||||
let did = match callee {
|
||||
Function(did) => did,
|
||||
callee => signal!(e, CallOn(callee)),
|
||||
};
|
||||
debug!("fn call: {:?}", tcx.map.get_if_local(did));
|
||||
match tcx.map.get_if_local(did) {
|
||||
None => signal!(e, UnimplementedConstVal("calling non-local const fn")), // non-local
|
||||
Some(ast_map::NodeItem(it)) => match it.node {
|
||||
hir::ItemFn(
|
||||
ref decl,
|
||||
hir::Unsafety::Normal,
|
||||
constness,
|
||||
abi::Abi::Rust,
|
||||
_, // ducktype generics? types are funky in const_eval
|
||||
ref block,
|
||||
) => Ok((&**decl, &**block, constness)),
|
||||
_ => signal!(e, NonConstPath),
|
||||
},
|
||||
Some(ast_map::NodeImplItem(it)) => match it.node {
|
||||
hir::ImplItemKind::Method(
|
||||
hir::MethodSig {
|
||||
ref decl,
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
constness,
|
||||
abi: abi::Abi::Rust,
|
||||
.. // ducktype generics? types are funky in const_eval
|
||||
},
|
||||
ref block,
|
||||
) => Ok((decl, block, constness)),
|
||||
_ => signal!(e, NonConstPath),
|
||||
},
|
||||
Some(ast_map::NodeTraitItem(..)) => signal!(e, NonConstPath),
|
||||
Some(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
struct S(i32);
|
||||
|
||||
const CONSTANT: S = S(0);
|
||||
//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080]
|
||||
//~^ ERROR: constant evaluation error: call on struct [E0080]
|
||||
|
||||
enum E {
|
||||
V = CONSTANT,
|
||||
|
|
|
@ -17,5 +17,6 @@ extern crate const_fn_lib;
|
|||
use const_fn_lib::foo;
|
||||
|
||||
fn main() {
|
||||
let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
|
||||
let x: [usize; foo()] = [];
|
||||
//~^ ERROR unimplemented constant expression: calling non-local const fn [E0250]
|
||||
}
|
||||
|
|
|
@ -22,4 +22,5 @@ const FOO: Foo = Foo::new();
|
|||
|
||||
pub fn main() {
|
||||
assert_eq!(FOO.value, 22);
|
||||
let _: [&'static str; Foo::new().value as usize] = ["hey"; 22];
|
||||
}
|
||||
|
|
|
@ -29,4 +29,5 @@ fn main() {
|
|||
|
||||
assert_eq!(DIFF, 22);
|
||||
|
||||
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue