Skip to content

Commit d2cc076

Browse files
committed
aggregate constants store their interior values instead of an expression id
1 parent c7ab884 commit d2cc076

File tree

9 files changed

+293
-128
lines changed

9 files changed

+293
-128
lines changed

src/librustc/middle/const_val.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@ use std::mem::transmute;
1717
use rustc_const_math::*;
1818
use self::ConstVal::*;
1919

20+
use std::collections::BTreeMap;
21+
2022
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
2123
pub enum ConstVal {
2224
Float(f64),
2325
Integral(ConstInt),
2426
Str(InternedString),
2527
ByteStr(Rc<Vec<u8>>),
2628
Bool(bool),
27-
Struct(ast::NodeId),
28-
Tuple(ast::NodeId),
29+
Struct(DefId, BTreeMap<ast::Name, ConstVal>),
30+
Tuple(Option<DefId>, Vec<ConstVal>),
2931
Function(DefId),
30-
Array(ast::NodeId, u64),
31-
Repeat(ast::NodeId, u64),
32+
Array(Vec<ConstVal>),
33+
Repeat(Box<ConstVal>, u64),
3234
Char(char),
3335
/// A value that only occurs in case `eval_const_expr` reported an error. You should never
3436
/// handle this case. Its sole purpose is to allow more errors to be reported instead of
@@ -44,11 +46,26 @@ impl hash::Hash for ConstVal {
4446
Str(ref a) => a.hash(state),
4547
ByteStr(ref a) => a.hash(state),
4648
Bool(a) => a.hash(state),
47-
Struct(a) => a.hash(state),
48-
Tuple(a) => a.hash(state),
49+
Struct(did, ref tree) => {
50+
did.hash(state);
51+
for (name, val) in tree {
52+
name.hash(state);
53+
val.hash(state);
54+
}
55+
},
56+
Tuple(did, ref v) => {
57+
did.hash(state);
58+
for elem in v {
59+
elem.hash(state);
60+
}
61+
},
4962
Function(a) => a.hash(state),
50-
Array(a, n) => { a.hash(state); n.hash(state) },
51-
Repeat(a, n) => { a.hash(state); n.hash(state) },
63+
Array(ref v) => {
64+
for elem in v {
65+
elem.hash(state);
66+
}
67+
}
68+
Repeat(ref a, n) => { a.hash(state); n.hash(state) },
5269
Char(c) => c.hash(state),
5370
Dummy => ().hash(state),
5471
}
@@ -67,11 +84,11 @@ impl PartialEq for ConstVal {
6784
(&Str(ref a), &Str(ref b)) => a == b,
6885
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
6986
(&Bool(a), &Bool(b)) => a == b,
70-
(&Struct(a), &Struct(b)) => a == b,
71-
(&Tuple(a), &Tuple(b)) => a == b,
87+
(&Struct(a_did, ref a), &Struct(b_did, ref b)) => (a == b) && (a_did == b_did),
88+
(&Tuple(ref a_did, ref a), &Tuple(ref b_did, ref b)) => (a == b) && (a_did == b_did),
7289
(&Function(a), &Function(b)) => a == b,
73-
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
74-
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
90+
(&Array(ref a), &Array(ref b)) => a == b,
91+
(&Repeat(ref a, an), &Repeat(ref b, bn)) => (a == b) && (an == bn),
7592
(&Char(a), &Char(b)) => a == b,
7693
(&Dummy, &Dummy) => true, // FIXME: should this be false?
7794
_ => false,
@@ -89,8 +106,8 @@ impl ConstVal {
89106
Str(_) => "string literal",
90107
ByteStr(_) => "byte string literal",
91108
Bool(_) => "boolean",
92-
Struct(_) => "struct",
93-
Tuple(_) => "tuple",
109+
Struct(..) => "struct",
110+
Tuple(..) => "tuple",
94111
Function(_) => "function definition",
95112
Array(..) => "array",
96113
Repeat(..) => "repeat",

src/librustc/mir/repr.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::borrow::{Cow};
2222
use std::fmt::{self, Debug, Formatter, Write};
2323
use std::{iter, u32};
2424
use std::ops::{Index, IndexMut};
25-
use syntax::ast::{self, Name};
25+
use syntax::ast::Name;
2626
use syntax::codemap::Span;
2727

2828
/// Lowered representation of a single function.
@@ -1039,17 +1039,48 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
10391039
}
10401040
Bool(b) => write!(fmt, "{:?}", b),
10411041
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
1042-
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
1043-
write!(fmt, "{}", node_to_string(node_id)),
1042+
Struct(def_id, ref tree) => {
1043+
write!(fmt, "{}", item_path_str(def_id))?;
1044+
if !tree.is_empty() {
1045+
write!(fmt, "{{")?;
1046+
for (name, val) in tree {
1047+
write!(fmt, "{}:", name)?;
1048+
fmt_const_val(fmt, val)?;
1049+
write!(fmt, ",")?;
1050+
}
1051+
write!(fmt, "}}")?;
1052+
}
1053+
Ok(())
1054+
},
1055+
Tuple(def_id, ref v) => {
1056+
if let Some(def_id) = def_id {
1057+
write!(fmt, "{}", item_path_str(def_id))?;
1058+
}
1059+
write!(fmt, "(")?;
1060+
for val in v {
1061+
fmt_const_val(fmt, val)?;
1062+
write!(fmt, ",")?;
1063+
}
1064+
write!(fmt, ")")
1065+
},
1066+
Array(ref v) => {
1067+
write!(fmt, "[")?;
1068+
for val in v {
1069+
fmt_const_val(fmt, val)?;
1070+
write!(fmt, ",")?;
1071+
}
1072+
write!(fmt, "]")
1073+
},
1074+
Repeat(ref v, n) => {
1075+
write!(fmt, "[")?;
1076+
fmt_const_val(fmt, v)?;
1077+
write!(fmt, ";{}]", n)
1078+
},
10441079
Char(c) => write!(fmt, "{:?}", c),
10451080
Dummy => bug!(),
10461081
}
10471082
}
10481083

1049-
fn node_to_string(node_id: ast::NodeId) -> String {
1050-
ty::tls::with(|tcx| tcx.map.node_to_user_string(node_id))
1051-
}
1052-
10531084
fn item_path_str(def_id: DefId) -> String {
10541085
ty::tls::with(|tcx| tcx.item_path_str(def_id))
10551086
}

src/librustc_const_eval/eval.rs

Lines changed: 75 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ pub enum ErrKind {
413413
BadType(ConstVal),
414414
ErroneousReferencedConstant(Box<ConstEvalErr>),
415415
CharCast(ConstInt),
416+
Aggregate(Vec<ConstEvalErr>),
416417
}
417418

418419
impl From<ConstMathErr> for ErrKind {
@@ -476,6 +477,7 @@ impl ConstEvalErr {
476477
CharCast(ref got) => {
477478
format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
478479
},
480+
Aggregate(ref v) => format!("evaluation of {} fields failed", v.len()).into_cow(),
479481
}
480482
}
481483
}
@@ -771,9 +773,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
771773
signal!(e, UnimplementedConstVal("enum variants"));
772774
}
773775
}
774-
Def::Struct(..) => {
775-
ConstVal::Struct(e.id)
776-
}
776+
Def::Struct(did) => Struct(did, BTreeMap::new()),
777777
Def::Local(_, id) => {
778778
debug!("Def::Local({:?}): {:?}", id, fn_args);
779779
if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
@@ -791,7 +791,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
791791
let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
792792
let did = match callee_val {
793793
Function(did) => did,
794-
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
794+
Struct(..) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
795795
callee => signal!(e, CallOn(callee)),
796796
};
797797
let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
@@ -829,8 +829,42 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
829829
}
830830
}
831831
hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?,
832-
hir::ExprTup(_) => Tuple(e.id),
833-
hir::ExprStruct(..) => Struct(e.id),
832+
hir::ExprTup(ref v) => {
833+
let mut fields = Vec::with_capacity(v.len());
834+
let mut errors = Vec::new();
835+
for field in v {
836+
match eval_const_expr_partial(tcx, field, ty_hint.erase_hint(), fn_args) {
837+
Ok(v) => fields.push(v),
838+
Err(e) => errors.push(e),
839+
}
840+
}
841+
if !errors.is_empty() {
842+
signal!(e, Aggregate(errors));
843+
}
844+
assert_eq!(fields.len(), v.len());
845+
Tuple(None, fields)
846+
},
847+
hir::ExprStruct(_, _, Some(_)) => signal!(e, UnimplementedConstVal("struct base")),
848+
hir::ExprStruct(_, ref fields, None) => {
849+
let def_id = match tcx.def_map.borrow().get(&e.id).map(|def| def.full_def()) {
850+
Some(Def::Struct(def_id)) => def_id,
851+
Some(Def::Variant(..)) => signal!(e, UnimplementedConstVal("enums")),
852+
_ => signal!(e, NonConstPath),
853+
};
854+
let mut new_fields = BTreeMap::new();
855+
let mut errors = Vec::new();
856+
for field in fields {
857+
match eval_const_expr_partial(tcx, &field.expr, ty_hint.erase_hint(), fn_args) {
858+
Ok(f_val) => assert!(new_fields.insert(field.name.node, f_val).is_none()),
859+
Err(e) => errors.push(e),
860+
}
861+
}
862+
if !errors.is_empty() {
863+
signal!(e, Aggregate(errors));
864+
}
865+
assert_eq!(new_fields.len(), fields.len());
866+
Struct(def_id, new_fields)
867+
},
834868
hir::ExprIndex(ref arr, ref idx) => {
835869
if !tcx.sess.features.borrow().const_indexing {
836870
signal!(e, IndexOpFeatureGated);
@@ -845,21 +879,11 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
845879
};
846880
assert_eq!(idx as usize as u64, idx);
847881
match arr {
848-
Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
849-
Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
850-
assert_eq!(n as usize as u64, n);
851-
eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
852-
} else {
853-
bug!()
854-
},
882+
Array(ref v) if idx as usize >= v.len() => signal!(e, IndexOutOfBounds),
883+
Array(ref v) => v[idx as usize].clone(),
855884

856885
Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
857-
Repeat(elem, _) => eval_const_expr_partial(
858-
tcx,
859-
&tcx.map.expect_expr(elem),
860-
ty_hint,
861-
fn_args,
862-
)?,
886+
Repeat(elem, _) => *elem,
863887

864888
ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
865889
ByteStr(data) => {
@@ -872,11 +896,30 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
872896
_ => signal!(e, IndexedNonVec),
873897
}
874898
}
875-
hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
876-
hir::ExprRepeat(_, ref n) => {
899+
hir::ExprVec(ref v) => {
900+
let mut elems = Vec::with_capacity(v.len());
901+
let mut errors = Vec::new();
902+
for elem in v {
903+
match eval_const_expr_partial(tcx, elem, ty_hint.erase_hint(), fn_args) {
904+
Ok(elem) => elems.push(elem),
905+
Err(e) => errors.push(e),
906+
}
907+
}
908+
if !errors.is_empty() {
909+
signal!(e, Aggregate(errors));
910+
}
911+
assert_eq!(elems.len(), v.len());
912+
Array(elems)
913+
},
914+
hir::ExprRepeat(ref elem, ref n) => {
877915
let len_hint = ty_hint.checked_or(tcx.types.usize);
916+
let val_hint = match ty_hint {
917+
ExprTypeChecked => ExprTypeChecked,
918+
UncheckedExprNoHint => UncheckedExprNoHint,
919+
UncheckedExprHint(ty) => UncheckedExprHint(ty.sequence_element_type(tcx)),
920+
};
878921
Repeat(
879-
e.id,
922+
box eval_const_expr_partial(tcx, elem, val_hint, fn_args)?,
880923
match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
881924
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
882925
Integral(_) => signal!(e, RepeatCountNotNatural),
@@ -886,40 +929,24 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
886929
},
887930
hir::ExprTupField(ref base, index) => {
888931
let base_hint = ty_hint.erase_hint();
889-
let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
890-
if let Tuple(tup_id) = c {
891-
if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
892-
if index.node < fields.len() {
893-
eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)?
894-
} else {
895-
signal!(e, TupleIndexOutOfBounds);
896-
}
897-
} else {
898-
bug!()
899-
}
900-
} else {
901-
signal!(base, ExpectedConstTuple);
932+
match eval_const_expr_partial(tcx, base, base_hint, fn_args)? {
933+
Tuple(_, ref v) if index.node >= v.len() => signal!(e, TupleIndexOutOfBounds),
934+
Tuple(_, v) => v[index.node as usize].clone(),
935+
_ => signal!(base, ExpectedConstTuple),
902936
}
903937
}
904938
hir::ExprField(ref base, field_name) => {
905939
let base_hint = ty_hint.erase_hint();
906940
// Get the base expression if it is a struct and it is constant
907-
let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
908-
if let Struct(struct_id) = c {
909-
if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
910-
// Check that the given field exists and evaluate it
911-
// if the idents are compared run-pass/issue-19244 fails
912-
if let Some(f) = fields.iter().find(|f| f.name.node
913-
== field_name.node) {
914-
eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)?
941+
match eval_const_expr_partial(tcx, base, base_hint, fn_args)? {
942+
Struct(_, fields) => {
943+
if let Some(f) = fields.get(&field_name.node) {
944+
f.clone()
915945
} else {
916946
signal!(e, MissingStructField);
917947
}
918-
} else {
919-
bug!()
920-
}
921-
} else {
922-
signal!(base, ExpectedConstStruct);
948+
},
949+
_ => signal!(base, ExpectedConstStruct),
923950
}
924951
}
925952
hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),

0 commit comments

Comments
 (0)