Rollup merge of #23275 - aochagavia:constants, r=eddyb
Fixes #23260 r? @eddyb
This commit is contained in:
commit
cc6ef80fa4
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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 {}",
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue