]> git.lizzy.rs Git - rust.git/commitdiff
implement calling of `const fn`-methods in true constants
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Fri, 27 Nov 2015 15:43:24 +0000 (16:43 +0100)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Fri, 27 Nov 2015 15:43:24 +0000 (16:43 +0100)
src/librustc/middle/const_eval.rs
src/test/compile-fail/const-eval-span.rs
src/test/compile-fail/const-fn-stability-calls-2.rs
src/test/run-pass/const-fn-method.rs
src/test/run-pass/const-fn.rs

index 21ece8f381ebfb60a0d25e074c3f5891357af30c..276eaa36a015121d68e55be4c7effb34c96be67a 100644 (file)
@@ -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 @@ pub fn description(&self) -> Cow<str> {
             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 @@ pub fn description(&self) -> Cow<str> {
             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!(),
+    }
+}
index 3e75afcda6d71823f45538b7f9b921f7b4bdefc6..44ab798f4911b4a17c9cef11952aa577f6f27ced 100644 (file)
@@ -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,
index 59e0db7b35508c8ca8cd6375604a99b51d3b9f94..592a312d80048a32f2cfb0d5520250c976ef9d58 100644 (file)
@@ -17,5 +17,6 @@
 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]
 }
index 42c7a47c59db1f24791dfa6772a1e90a6c883306..7d8d941439cf8c953848bdcd29267c6083cc0c71 100644 (file)
@@ -22,4 +22,5 @@ const fn new() -> Foo {
 
 pub fn main() {
     assert_eq!(FOO.value, 22);
+    let _: [&'static str; Foo::new().value as usize] = ["hey"; 22];
 }
index 9bd8eb55cc388351f937a64e4bf4dd0cad349afb..38c73febc310843de85447d67ff64ad311e53c21 100644 (file)
@@ -29,4 +29,5 @@ fn main() {
 
     assert_eq!(DIFF, 22);
 
+    let _: [&'static str; sub(100, 99) as usize] = ["hi"];
 }