about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-03-12 09:14:44 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-03-12 09:14:44 +0530
commitcc6ef80fa4b04ad8247091c19b2c380c7fc5306a (patch)
tree76dee933ea471c59e338c5c8263215e560a65620 /src
parente4e5640a6e189004c81417902a94242074acf530 (diff)
parenta83db812385f9bf281078c7c8ede44f6863f2966 (diff)
downloadrust-cc6ef80fa4b04ad8247091c19b2c380c7fc5306a.tar.gz
rust-cc6ef80fa4b04ad8247091c19b2c380c7fc5306a.zip
Rollup merge of #23275 - aochagavia:constants, r=eddyb
 Fixes #23260

r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/const_eval.rs81
-rw-r--r--src/librustc/middle/ty.rs17
-rw-r--r--src/test/compile-fail/repeat_count.rs2
-rw-r--r--src/test/run-pass/issue-19244.rs29
4 files changed, 90 insertions, 39 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index f215b59a6cd..96433729a9b 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -17,7 +17,7 @@ use metadata::csearch;
 use middle::{astencode, def};
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty};
-use middle::astconv_util::{ast_ty_to_prim_ty};
+use middle::astconv_util::ast_ty_to_prim_ty;
 
 use syntax::ast::{self, Expr};
 use syntax::codemap::Span;
@@ -132,16 +132,16 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
     }
 }
 
-// FIXME (#33): this doesn't handle big integer/float literals correctly
-// (nor does the rest of our literal handling).
 #[derive(Clone, PartialEq)]
 pub enum const_val {
     const_float(f64),
     const_int(i64),
     const_uint(u64),
     const_str(InternedString),
-    const_binary(Rc<Vec<u8> >),
-    const_bool(bool)
+    const_binary(Rc<Vec<u8>>),
+    const_bool(bool),
+    Struct(ast::NodeId),
+    Tuple(ast::NodeId)
 }
 
 pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
@@ -226,9 +226,13 @@ pub enum ErrKind {
     NegateOnString,
     NegateOnBoolean,
     NegateOnBinary,
+    NegateOnStruct,
+    NegateOnTuple,
     NotOnFloat,
     NotOnString,
     NotOnBinary,
+    NotOnStruct,
+    NotOnTuple,
 
     AddiWithOverflow(i64, i64),
     SubiWithOverflow(i64, i64),
@@ -242,7 +246,8 @@ pub enum ErrKind {
     ModuloWithOverflow,
     MissingStructField,
     NonConstPath,
-    NonConstStruct,
+    ExpectedConstTuple,
+    ExpectedConstStruct,
     TupleIndexOutOfBounds,
 
     MiscBinaryOp,
@@ -262,9 +267,13 @@ impl ConstEvalErr {
             NegateOnString => "negate on string".into_cow(),
             NegateOnBoolean => "negate on boolean".into_cow(),
             NegateOnBinary => "negate on binary literal".into_cow(),
+            NegateOnStruct => "negate on struct".into_cow(),
+            NegateOnTuple => "negate on tuple".into_cow(),
             NotOnFloat => "not on float or string".into_cow(),
             NotOnString => "not on float or string".into_cow(),
             NotOnBinary => "not on binary literal".into_cow(),
+            NotOnStruct => "not on struct".into_cow(),
+            NotOnTuple => "not on tuple".into_cow(),
 
             AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
             SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
@@ -278,7 +287,8 @@ impl ConstEvalErr {
             ModuloWithOverflow   => "attempted remainder with overflow".into_cow(),
             MissingStructField  => "nonexistent struct field".into_cow(),
             NonConstPath        => "non-constant path in constant expr".into_cow(),
-            NonConstStruct      => "non-constant struct in constant expr".into_cow(),
+            ExpectedConstTuple => "expected constant tuple".into_cow(),
+            ExpectedConstStruct => "expected constant struct".into_cow(),
             TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
 
             MiscBinaryOp => "bad operands for binary".into_cow(),
@@ -341,6 +351,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
           const_str(_) => signal!(e, NegateOnString),
           const_bool(_) => signal!(e, NegateOnBoolean),
           const_binary(_) => signal!(e, NegateOnBinary),
+          const_val::Tuple(_) => signal!(e, NegateOnTuple),
+          const_val::Struct(..) => signal!(e, NegateOnStruct),
         }
       }
       ast::ExprUnary(ast::UnNot, ref inner) => {
@@ -351,6 +363,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
           const_str(_) => signal!(e, NotOnString),
           const_float(_) => signal!(e, NotOnFloat),
           const_binary(_) => signal!(e, NotOnBinary),
+          const_val::Tuple(_) => signal!(e, NotOnTuple),
+          const_val::Struct(..) => signal!(e, NotOnStruct),
         }
       }
       ast::ExprBinary(op, ref a, ref b) => {
@@ -540,33 +554,52 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
             None => const_int(0)
         }
       }
+      ast::ExprTup(_) => {
+        const_val::Tuple(e.id)
+      }
+      ast::ExprStruct(..) => {
+        const_val::Struct(e.id)
+      }
       ast::ExprTupField(ref base, index) => {
-        // Get the base tuple if it is constant
-        if let Some(&ast::ExprTup(ref fields)) = lookup_const(tcx, &**base).map(|s| &s.node) {
-            // Check that the given index is within bounds and evaluate its value
-            if fields.len() > index.node {
-                return eval_const_expr_partial(tcx, &*fields[index.node], None);
+        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+            if let const_val::Tuple(tup_id) = c {
+                if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
+                    if index.node < fields.len() {
+                        return eval_const_expr_partial(tcx, &fields[index.node], None)
+                    } else {
+                        signal!(e, TupleIndexOutOfBounds);
+                    }
+                } else {
+                    unreachable!()
+                }
             } else {
-                signal!(e, TupleIndexOutOfBounds);
+                signal!(base, ExpectedConstTuple);
             }
+        } else {
+            signal!(base, NonConstPath)
         }
-
-        signal!(e, NonConstStruct);
       }
       ast::ExprField(ref base, field_name) => {
         // Get the base expression if it is a struct and it is constant
-        if let Some(&ast::ExprStruct(_, ref fields, _)) = lookup_const(tcx, &**base)
-                                                            .map(|s| &s.node) {
-            // Check that the given field exists and evaluate it
-            if let Some(f) = fields.iter().find(|f|
-                                           f.ident.node.as_str() == field_name.node.as_str()) {
-                return eval_const_expr_partial(tcx, &*f.expr, None);
+        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+            if let const_val::Struct(struct_id) = c {
+                if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
+                    // Check that the given field exists and evaluate it
+                    if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
+                                                         == field_name.node.as_str()) {
+                        return eval_const_expr_partial(tcx, &*f.expr, None)
+                    } else {
+                        signal!(e, MissingStructField);
+                    }
+                } else {
+                    unreachable!()
+                }
             } else {
-                signal!(e, MissingStructField);
+                signal!(base, ExpectedConstStruct);
             }
+        } else {
+            signal!(base, NonConstPath);
         }
-
-        signal!(e, NonConstStruct);
       }
       _ => signal!(e, MiscCatchAll)
     };
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4cb4d343de7..a871602b865 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -5853,16 +5853,13 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
             let found = match val {
                 const_eval::const_uint(count) => return count as uint,
                 const_eval::const_int(count) if count >= 0 => return count as uint,
-                const_eval::const_int(_) =>
-                    "negative integer",
-                const_eval::const_float(_) =>
-                    "float",
-                const_eval::const_str(_) =>
-                    "string",
-                const_eval::const_bool(_) =>
-                    "boolean",
-                const_eval::const_binary(_) =>
-                    "binary array"
+                const_eval::const_int(_) => "negative integer",
+                const_eval::const_float(_) => "float",
+                const_eval::const_str(_) => "string",
+                const_eval::const_bool(_) => "boolean",
+                const_eval::const_binary(_) => "binary array",
+                const_eval::Struct(..) => "struct",
+                const_eval::Tuple(_) => "tuple"
             };
             span_err!(tcx.sess, count_expr.span, E0306,
                 "expected positive integer for repeat count, found {}",
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index 9b3e2668042..12158141220 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -19,7 +19,7 @@ fn main() {
 //~| found `()`
 //~| expected usize
 //~| found ()
-//~| ERROR expected constant integer for repeat count, found non-constant expression
+//~| ERROR expected positive integer for repeat count, found tuple
     let c = [0; true];
     //~^ ERROR mismatched types
     //~| expected `usize`
diff --git a/src/test/run-pass/issue-19244.rs b/src/test/run-pass/issue-19244.rs
index 9af4d30c4f6..35e053110df 100644
--- a/src/test/run-pass/issue-19244.rs
+++ b/src/test/run-pass/issue-19244.rs
@@ -8,14 +8,35 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct MyStruct { field: uint }
+struct MyStruct { field: usize }
+struct Nested { nested: MyStruct }
+struct Mix2 { nested: ((usize,),) }
+
 const STRUCT: MyStruct = MyStruct { field: 42 };
-const TUP: (uint,) = (43,);
+const TUP: (usize,) = (43,);
+const NESTED_S: Nested = Nested { nested: MyStruct { field: 5 } };
+const NESTED_T: ((usize,),) = ((4,),);
+const MIX_1: ((Nested,),) = ((Nested { nested: MyStruct { field: 3 } },),);
+const MIX_2: Mix2 = Mix2 { nested: ((2,),) };
+const INSTANT_1: usize = (MyStruct { field: 1 }).field;
+const INSTANT_2: usize = (0,).0;
 
 fn main() {
     let a = [0; STRUCT.field];
     let b = [0; TUP.0];
+    let c = [0; NESTED_S.nested.field];
+    let d = [0; (NESTED_T.0).0];
+    let e = [0; (MIX_1.0).0.nested.field];
+    let f = [0; (MIX_2.nested.0).0];
+    let g = [0; INSTANT_1];
+    let h = [0; INSTANT_2];
 
-    assert!(a.len() == 42);
-    assert!(b.len() == 43);
+    assert_eq!(a.len(), 42);
+    assert_eq!(b.len(), 43);
+    assert_eq!(c.len(), 5);
+    assert_eq!(d.len(), 4);
+    assert_eq!(e.len(), 3);
+    assert_eq!(f.len(), 2);
+    assert_eq!(g.len(), 1);
+    assert_eq!(h.len(), 0);
 }