allow indexing into constant arrays

This commit is contained in:
Oliver Schneider 2015-11-18 10:57:52 +01:00
parent af5d9d65e7
commit 6683fa4d42
10 changed files with 190 additions and 28 deletions

View File

@ -256,6 +256,8 @@ pub enum ConstVal {
Struct(ast::NodeId),
Tuple(ast::NodeId),
Function(DefId),
Array(ast::NodeId, u64),
Repeat(ast::NodeId, u64),
}
impl hash::Hash for ConstVal {
@ -270,6 +272,8 @@ impl hash::Hash for ConstVal {
Struct(a) => a.hash(state),
Tuple(a) => a.hash(state),
Function(a) => a.hash(state),
Array(a, n) => { a.hash(state); n.hash(state) },
Repeat(a, n) => { a.hash(state); n.hash(state) },
}
}
}
@ -290,6 +294,8 @@ impl PartialEq for ConstVal {
(&Struct(a), &Struct(b)) => a == b,
(&Tuple(a), &Tuple(b)) => a == b,
(&Function(a), &Function(b)) => a == b,
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
_ => false,
}
}
@ -310,6 +316,8 @@ impl ConstVal {
Struct(_) => "struct",
Tuple(_) => "tuple",
Function(_) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
}
}
}
@ -416,6 +424,12 @@ pub enum ErrKind {
ExpectedConstTuple,
ExpectedConstStruct,
TupleIndexOutOfBounds,
IndexedNonVec,
IndexNegative,
IndexNotInt,
IndexOutOfBounds,
RepeatCountNotNatural,
RepeatCountNotInt,
MiscBinaryOp,
MiscCatchAll,
@ -454,6 +468,12 @@ impl ConstEvalErr {
ExpectedConstTuple => "expected constant tuple".into_cow(),
ExpectedConstStruct => "expected constant struct".into_cow(),
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
IndexNegative => "indices must be non-negative integers".into_cow(),
IndexNotInt => "indices must be integers".into_cow(),
IndexOutOfBounds => "array index out of bounds".into_cow(),
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
RepeatCountNotInt => "repeat count must be integers".into_cow(),
MiscBinaryOp => "bad operands for binary".into_cow(),
MiscCatchAll => "unsupported constant expr".into_cow(),
@ -1111,11 +1131,72 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
hir::ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
None => Int(0)
None => unreachable!(),
}
}
hir::ExprTup(_) => Tuple(e.id),
hir::ExprStruct(..) => Struct(e.id),
hir::ExprIndex(ref arr, ref idx) => {
let arr_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked
} else {
UncheckedExprNoHint
};
let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
let idx_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked
} else {
UncheckedExprHint(tcx.types.usize)
};
let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
Int(i) if i >= 0 => i as u64,
Int(_) => signal!(idx, IndexNegative),
Uint(i) => i,
_ => signal!(idx, IndexNotInt),
};
match arr {
Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
try!(eval_const_expr_partial(tcx, &*v[idx as usize], ty_hint, fn_args))
} else {
unreachable!()
},
Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
Repeat(elem, _) => try!(eval_const_expr_partial(
tcx,
&*tcx.map.expect_expr(elem),
ty_hint,
fn_args,
)),
ByteStr(ref data) if idx as usize >= data.len()
=> signal!(e, IndexOutOfBounds),
ByteStr(data) => Uint(data[idx as usize] as u64),
Str(ref s) if idx as usize >= s.len()
=> signal!(e, IndexOutOfBounds),
Str(_) => unimplemented!(), // there's no const_char type
_ => signal!(e, IndexedNonVec),
}
}
hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
hir::ExprRepeat(_, ref n) => {
let len_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked
} else {
UncheckedExprHint(tcx.types.usize)
};
Repeat(
e.id,
match try!(eval_const_expr_partial(tcx, &**n, len_hint, fn_args)) {
Int(i) if i >= 0 => i as u64,
Int(_) => signal!(e, RepeatCountNotNatural),
Uint(i) => i,
_ => signal!(e, RepeatCountNotInt),
},
)
},
hir::ExprTupField(ref base, index) => {
let base_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked

View File

@ -62,6 +62,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
ConstVal::Function(_) => {
unimplemented!()
}
ConstVal::Array(..) => {
unimplemented!()
}
ConstVal::Repeat(..) => {
unimplemented!()
}
};
OperandRef {
ty: ty,

View File

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
static A: &'static [i32] = &[];
static B: i32 = (&A)[1]; //~ ERROR: const index-expr is out of bounds
fn main() {
let _ = B;
}

View File

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
const A: [i32; 0] = [];
const B: i32 = A[1]; //~ ERROR: const index-expr is out of bounds
fn main() {
let _ = B;
}

View File

@ -0,0 +1,20 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
const IDX: usize = 3;
const VAL: i32 = ARR[IDX];
const BONG: [i32; (ARR[0] - 41) as usize] = [5];
const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; //~ ERROR: mismatched types
const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; //~ ERROR: mismatched types
fn main() {
let _ = VAL;
}

View File

@ -9,7 +9,10 @@
// except according to those terms.
const FOO: [u32; 3] = [1, 2, 3];
const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
//~^ ERROR array length constant evaluation error: array index out of bounds [E0250]
fn main() {
let _ = BAR;

View File

@ -0,0 +1,17 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
const IDX: usize = 3;
const VAL: i32 = ARR[IDX];
const BLUB: [i32; (ARR[0] - 41) as usize] = [5];
}

View File

@ -12,30 +12,33 @@
// and unsized) work properly.
const aa: [isize; 3] = [1, 2, 3];
const ab: &'static [isize; 3] = &aa;
const ac: &'static [isize] = ab;
const ad: &'static [isize] = &aa;
const ae: &'static [isize; 3] = &[1, 2, 3];
const af: &'static [isize] = &[1, 2, 3];
const AA: [isize; 3] = [1, 2, 3];
const AB: &'static [isize; 3] = &AA;
const AC: &'static [isize] = AB;
const AD: &'static [isize] = &AA;
const AE: &'static [isize; 3] = &[1, 2, 3];
const AF: &'static [isize] = &[1, 2, 3];
static ca: isize = aa[0];
static cb: isize = ab[1];
static cc: isize = ac[2];
static cd: isize = ad[0];
static ce: isize = ae[1];
static cf: isize = af[2];
static CA: isize = AA[0];
static CB: isize = AB[1];
static CC: isize = AC[2];
static CD: isize = AD[0];
static CE: isize = AE[1];
static CF: isize = AF[2];
static AG: &'static isize = &AA[2];
fn main () {
let b: &[isize] = &[1, 2, 3];
assert_eq!(ac, b);
assert_eq!(ad, b);
assert_eq!(af, b);
assert_eq!(AC, b);
assert_eq!(AD, b);
assert_eq!(AF, b);
assert_eq!(*AG, 3);
assert_eq!(ca, 1);
assert_eq!(cb, 2);
assert_eq!(cc, 3);
assert_eq!(cd, 1);
assert_eq!(ce, 2);
assert_eq!(cf, 3);
assert_eq!(CA, 1);
assert_eq!(CB, 2);
assert_eq!(CC, 3);
assert_eq!(CD, 1);
assert_eq!(CE, 2);
assert_eq!(CF, 3);
}

View File

@ -8,14 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum E { V1(isize), V0 }
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
static C0: E = C[0];
static C1: E = C[1];
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEADBEE)];
static D0: E = C[0];
static D1: E = C[1];
const D: &'static [E; 2] = &[E::V0, E::V1(0xDEAFBEE)];
static D0: E = D[0];
static D1: E = D[1];
pub fn main() {
match C0 {
@ -32,7 +31,7 @@ pub fn main() {
_ => panic!()
}
match D1 {
E::V1(n) => assert_eq!(n, 0xDEADBEE),
E::V1(n) => assert_eq!(n, 0xDEAFBEE),
_ => panic!()
}
}

View File

@ -18,6 +18,7 @@ const C: *const u8 = B as *const u8;
pub fn main() {
unsafe {
let foo = &A as *const u8;
assert_eq!(foo, C);
assert_eq!(str::from_utf8_unchecked(&A), "hi");
assert_eq!(*C, A[0]);
assert_eq!(*(&B[0] as *const u8), A[0]);