auto merge of #8444 : erickt/rust/rollup, r=cmr

This merges these PR together:

#8430: r=thestinger 
#8370: r=thestinger
#8386: r=bstrie
#8388: r=thestinger
#8390: r=graydon
#8394: r=graydon
#8402: r=thestinger
#8403: r=catamorphism
This commit is contained in:
bors 2013-08-10 16:32:18 -07:00
commit bf809768ee
28 changed files with 594 additions and 171 deletions

View File

@ -1305,7 +1305,7 @@ match crayons[0] {
A vector can be destructured using pattern matching:
~~~~
let numbers: [int, ..3] = [1, 2, 3];
let numbers: &[int] = &[1, 2, 3];
let score = match numbers {
[] => 0,
[a] => a * 10,
@ -2195,7 +2195,7 @@ use std::float::consts::pi;
# impl Shape for CircleStruct { fn area(&self) -> float { pi * square(self.radius) } }
let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f};
let mycircle: Circle = concrete as @Circle;
let mycircle: @Circle = concrete as @Circle;
let nonsense = mycircle.radius() * mycircle.area();
~~~

View File

@ -29,6 +29,11 @@
table))
(defcustom rust-indent-offset default-tab-width
"*Indent Rust code by this number of spaces.
The initializer is `DEFAULT-TAB-WIDTH'.")
(defun rust-paren-level () (nth 0 (syntax-ppss)))
(defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss)))
(defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss))))
@ -49,10 +54,10 @@
(let ((level (rust-paren-level)))
(cond
;; A function return type is 1 level indented
((looking-at "->") (* default-tab-width (+ level 1)))
((looking-at "->") (* rust-indent-offset (+ level 1)))
;; A closing brace is 1 level unindended
((looking-at "}") (* default-tab-width (- level 1)))
((looking-at "}") (* rust-indent-offset (- level 1)))
;; If we're in any other token-tree / sexp, then:
;; - [ or ( means line up with the opening token
@ -70,18 +75,18 @@
(goto-char pt)
(back-to-indentation)
(if (looking-at "\\<else\\>")
(* default-tab-width (+ 1 level))
(* rust-indent-offset (+ 1 level))
(progn
(goto-char pt)
(beginning-of-line)
(rust-rewind-irrelevant)
(end-of-line)
(if (looking-back "[{};,]")
(* default-tab-width level)
(* rust-indent-offset level)
(back-to-indentation)
(if (looking-at "#")
(* default-tab-width level)
(* default-tab-width (+ 1 level))))))))))
(* rust-indent-offset level)
(* rust-indent-offset (+ 1 level))))))))))
;; Otherwise we're in a column-zero definition
(t 0))))))

View File

@ -255,6 +255,9 @@ pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful {
}
not_useful
}
ty::ty_evec(_, ty::vstore_fixed(n)) => {
is_useful_specialized(cx, m, v, vec(n), n, left_ty)
}
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
let max_len = do m.rev_iter().fold(0) |max_len, r| {
match r[0].node {
@ -409,6 +412,29 @@ pub fn missing_ctor(cx: &MatchCheckCtxt,
else if true_found { Some(val(const_bool(false))) }
else { Some(val(const_bool(true))) }
}
ty::ty_evec(_, ty::vstore_fixed(n)) => {
let mut missing = true;
let mut wrong = false;
for r in m.iter() {
match r[0].node {
pat_vec(ref before, ref slice, ref after) => {
let count = before.len() + after.len();
if (count < n && slice.is_none()) || count > n {
wrong = true;
}
if count == n || (count < n && slice.is_some()) {
missing = false;
}
}
_ => {}
}
}
match (wrong, missing) {
(true, _) => Some(vec(n)), // should be compile-time error
(_, true) => Some(vec(n)),
_ => None
}
}
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
// Find the lengths and slices of all vector patterns.

View File

@ -403,6 +403,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt,
// Ditto
match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
base))).sty {
ty_enum(id, _) |
ty_struct(id, _)
if id.crate != LOCAL_CRATE ||
!privileged_items.iter().any(|x| x == &(id.node)) => {

View File

@ -145,6 +145,51 @@
* - `store_non_ref_bindings()`
* - `insert_lllocals()`
*
*
* ## Notes on vector pattern matching.
*
* Vector pattern matching is surprisingly tricky. The problem is that
* the structure of the vector isn't fully known, and slice matches
* can be done on subparts of it.
*
* The way that vector pattern matches are dealt with, then, is as
* follows. First, we make the actual condition associated with a
* vector pattern simply a vector length comparison. So the pattern
* [1, .. x] gets the condition "vec len >= 1", and the pattern
* [.. x] gets the condition "vec len >= 0". The problem here is that
* having the condition "vec len >= 1" hold clearly does not mean that
* only a pattern that has exactly that condition will match. This
* means that it may well be the case that a condition holds, but none
* of the patterns matching that condition match; to deal with this,
* when doing vector length matches, we have match failures proceed to
* the next condition to check.
*
* There are a couple more subtleties to deal with. While the "actual"
* condition associated with vector length tests is simply a test on
* the vector length, the actual vec_len Opt entry contains more
* information used to restrict which matches are associated with it.
* So that all matches in a submatch are matching against the same
* values from inside the vector, they are split up by how many
* elements they match at the front and at the back of the vector. In
* order to make sure that arms are properly checked in order, even
* with the overmatching conditions, each vec_len Opt entry is
* associated with a range of matches.
* Consider the following:
*
* match &[1, 2, 3] {
* [1, 1, .. _] => 0,
* [1, 2, 2, .. _] => 1,
* [1, 2, 3, .. _] => 2,
* [1, 2, .. _] => 3,
* _ => 4
* }
* The proper arm to match is arm 2, but arms 0 and 3 both have the
* condition "len >= 2". If arm 3 was lumped in with arm 0, then the
* wrong branch would be taken. Instead, vec_len Opts are associated
* with a contiguous range of matches that have the same "shape".
* This is sort of ugly and requires a bunch of special handling of
* vec_len options.
*
*/
@ -189,14 +234,19 @@ enum Lit {
ConstLit(ast::def_id), // the def ID of the constant
}
#[deriving(Eq)]
pub enum VecLenOpt {
vec_len_eq,
vec_len_ge(/* length of prefix */uint)
}
// An option identifying a branch (either a literal, a enum variant or a
// range)
enum Opt {
lit(Lit),
var(/* disr val */ uint, @adt::Repr),
range(@ast::expr, @ast::expr),
vec_len_eq(uint),
vec_len_ge(uint, /* slice */uint)
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
@ -247,9 +297,9 @@ fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
}
}
(&var(a, _), &var(b, _)) => a == b,
(&vec_len_eq(a), &vec_len_eq(b)) => a == b,
(&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b,
_ => false
(&vec_len(a1, a2, _), &vec_len(b1, b2, _)) =>
a1 == b1 && a2 == b2,
_ => false
}
}
@ -283,10 +333,10 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
rslt(bcx, consts::const_expr(ccx, l2)));
}
vec_len_eq(n) => {
vec_len(n, vec_len_eq, _) => {
return single_result(rslt(bcx, C_int(ccx, n as int)));
}
vec_len_ge(n, _) => {
vec_len(n, vec_len_ge(_), _) => {
return lower_bound(rslt(bcx, C_int(ccx, n as int)));
}
}
@ -471,10 +521,11 @@ fn enter_match<'r>(bcx: @mut Block,
}
fn enter_default<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
val: ValueRef)
dm: DefMap,
m: &[Match<'r>],
col: uint,
val: ValueRef,
chk: Option<mk_fail>)
-> ~[Match<'r>] {
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
@ -483,13 +534,36 @@ fn enter_default<'r>(bcx: @mut Block,
bcx.val_to_str(val));
let _indenter = indenter();
do enter_match(bcx, dm, m, col, val) |p| {
// Collect all of the matches that can match against anything.
let matches = do enter_match(bcx, dm, m, col, val) |p| {
match p.node {
ast::pat_wild | ast::pat_tup(_) => Some(~[]),
ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]),
_ => None
}
}
};
// Ok, now, this is pretty subtle. A "default" match is a match
// that needs to be considered if none of the actual checks on the
// value being considered succeed. The subtlety lies in that sometimes
// identifier/wildcard matches are *not* default matches. Consider:
// "match x { _ if something => foo, true => bar, false => baz }".
// There is a wildcard match, but it is *not* a default case. The boolean
// case on the value being considered is exhaustive. If the case is
// exhaustive, then there are no defaults.
//
// We detect whether the case is exhaustive in the following
// somewhat kludgy way: if the last wildcard/binding match has a
// guard, then by non-redundancy, we know that there aren't any
// non guarded matches, and thus by exhaustiveness, we know that
// we don't need any default cases. If the check *isn't* nonexhaustive
// (because chk is Some), then we need the defaults anyways.
let is_exhaustive = match matches.last_opt() {
Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true,
_ => false
};
if is_exhaustive { ~[] } else { matches }
}
// <pcwalton> nmatsakis: what does enter_opt do?
@ -523,17 +597,19 @@ fn enter_opt<'r>(bcx: @mut Block,
variant_size: uint,
val: ValueRef)
-> ~[Match<'r>] {
debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)",
debug!("enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)",
bcx.to_str(),
m.repr(bcx.tcx()),
*opt,
col,
bcx.val_to_str(val));
let _indenter = indenter();
let tcx = bcx.tcx();
let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()};
let mut i = 0;
do enter_match(bcx, tcx.def_map, m, col, val) |p| {
match p.node {
let answer = match p.node {
ast::pat_enum(*) |
ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => {
let const_def = tcx.def_map.get_copy(&p.id);
@ -599,32 +675,53 @@ fn enter_opt<'r>(bcx: @mut Block,
}
}
ast::pat_vec(ref before, slice, ref after) => {
let (lo, hi) = match *opt {
vec_len(_, _, (lo, hi)) => (lo, hi),
_ => tcx.sess.span_bug(p.span,
"vec pattern but not vec opt")
};
match slice {
Some(slice) => {
Some(slice) if i >= lo && i <= hi => {
let n = before.len() + after.len();
let i = before.len();
if opt_eq(tcx, &vec_len_ge(n, i), opt) {
let this_opt = vec_len(n, vec_len_ge(before.len()),
(lo, hi));
if opt_eq(tcx, &this_opt, opt) {
Some(vec::append_one((*before).clone(), slice) +
*after)
} else {
None
}
}
None => {
None if i >= lo && i <= hi => {
let n = before.len();
if opt_eq(tcx, &vec_len_eq(n), opt) {
if opt_eq(tcx, &vec_len(n, vec_len_eq, (lo,hi)), opt) {
Some((*before).clone())
} else {
None
}
}
_ => None
}
}
_ => {
assert_is_binding_or_wild(bcx, p);
Some(vec::from_elem(variant_size, dummy))
// In most cases, a binding/wildcard match be
// considered to match against any Opt. However, when
// doing vector pattern matching, submatches are
// considered even if the eventual match might be from
// a different submatch. Thus, when a submatch fails
// when doing a vector match, we proceed to the next
// submatch. Thus, including a default match would
// cause the default match to fire spuriously.
match *opt {
vec_len(*) => None,
_ => Some(vec::from_elem(variant_size, dummy))
}
}
}
};
i += 1;
answer
}
}
@ -805,9 +902,25 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;}
set.push(val);
}
// Vector comparisions are special in that since the actual
// conditions over-match, we need to be careful about them. This
// means that in order to properly handle things in order, we need
// to not always merge conditions.
fn add_veclen_to_set(set: &mut ~[Opt], i: uint,
len: uint, vlo: VecLenOpt) {
match set.last_opt() {
// If the last condition in the list matches the one we want
// to add, then extend its range. Otherwise, make a new
// vec_len with a range just covering the new entry.
Some(&vec_len(len2, vlo2, (start, end)))
if len == len2 && vlo == vlo2 =>
set[set.len() - 1] = vec_len(len, vlo, (start, end+1)),
_ => set.push(vec_len(len, vlo, (i, i)))
}
}
let mut found = ~[];
for br in m.iter() {
for (i, br) in m.iter().enumerate() {
let cur = br.pats[col];
match cur.node {
ast::pat_lit(l) => {
@ -852,12 +965,12 @@ fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
add_to_set(ccx.tcx, &mut found, range(l1, l2));
}
ast::pat_vec(ref before, slice, ref after) => {
let opt = match slice {
None => vec_len_eq(before.len()),
Some(_) => vec_len_ge(before.len() + after.len(),
before.len())
let (len, vec_opt) = match slice {
None => (before.len(), vec_len_eq),
Some(_) => (before.len() + after.len(),
vec_len_ge(before.len()))
};
add_to_set(ccx.tcx, &mut found, opt);
add_veclen_to_set(&mut found, i, len, vec_opt);
}
_ => {}
}
@ -1075,13 +1188,13 @@ fn pick_col(m: &[Match]) -> uint {
}
let mut scores = vec::from_elem(m[0].pats.len(), 0u);
for br in m.iter() {
let mut i = 0u;
for p in br.pats.iter() { scores[i] += score(*p); i += 1u; }
for (i, p) in br.pats.iter().enumerate() {
scores[i] += score(*p);
}
}
let mut max_score = 0u;
let mut best_col = 0u;
let mut i = 0u;
for score in scores.iter() {
for (i, score) in scores.iter().enumerate() {
let score = *score;
// Irrefutable columns always go first, they'd only be duplicated in
@ -1090,7 +1203,6 @@ fn pick_col(m: &[Match]) -> uint {
// If no irrefutable ones are found, we pick the one with the biggest
// branching factor.
if score > max_score { max_score = score; best_col = i; }
i += 1u;
}
return best_col;
}
@ -1460,7 +1572,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
test_val = Load(bcx, val);
kind = compare;
},
vec_len_eq(*) | vec_len_ge(*) => {
vec_len(*) => {
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
let (_, len) = tvec::get_base_and_len(
@ -1487,16 +1599,19 @@ fn compile_submatch_continue(mut bcx: @mut Block,
C_int(ccx, 0) // Placeholder for when not using a switch
};
let defaults = enter_default(else_cx, dm, m, col, val);
let defaults = enter_default(else_cx, dm, m, col, val, chk);
let exhaustive = chk.is_none() && defaults.len() == 0u;
let len = opts.len();
let mut i = 0u;
// Compile subtrees for each option
for opt in opts.iter() {
i += 1u;
for (i, opt) in opts.iter().enumerate() {
// In some cases in vector pattern matching, we need to override
// the failure case so that instead of failing, it proceeds to
// try more matching. branch_chk, then, is the proper failure case
// for the current conditional branch.
let mut branch_chk = chk;
let mut opt_cx = else_cx;
if !exhaustive || i < len {
if !exhaustive || i+1 < len {
opt_cx = sub_block(bcx, "match_case");
match kind {
single => Br(bcx, opt_cx.llbb),
@ -1586,6 +1701,10 @@ fn compile_submatch_continue(mut bcx: @mut Block,
}
};
bcx = sub_block(after_cx, "compare_vec_len_next");
// If none of these subcases match, move on to the
// next condition.
branch_chk = Some::<mk_fail>(|| bcx.llbb);
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
}
_ => ()
@ -1604,17 +1723,13 @@ fn compile_submatch_continue(mut bcx: @mut Block,
unpacked = argvals;
opt_cx = new_bcx;
}
vec_len_eq(n) | vec_len_ge(n, _) => {
let n = match *opt {
vec_len_ge(*) => n + 1u,
_ => n
vec_len(n, vt, _) => {
let (n, slice) = match vt {
vec_len_ge(i) => (n + 1u, Some(i)),
vec_len_eq => (n, None)
};
let slice = match *opt {
vec_len_ge(_, i) => Some(i),
_ => None
};
let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice,
val, test_val);
let args = extract_vec_elems(opt_cx, pat_span, pat_id, n,
slice, val, test_val);
size = args.vals.len();
unpacked = args.vals.clone();
opt_cx = args.bcx;
@ -1623,7 +1738,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
}
let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
let opt_vals = vec::append(unpacked, vals_left);
compile_submatch(opt_cx, opt_ms, opt_vals, chk);
compile_submatch(opt_cx, opt_ms, opt_vals, branch_chk);
}
// Compile the fall-through case, if any

View File

@ -156,6 +156,53 @@ impl<T> TrieMap<T> {
remaining_max: self.length
}
}
// If `upper` is true then returns upper_bound else returns lower_bound.
#[inline]
fn bound_iter<'a>(&'a self, key: uint, upper: bool) -> TrieMapIterator<'a, T> {
let mut node: &'a TrieNode<T> = &self.root;
let mut idx = 0;
let mut it = TrieMapIterator {
stack: ~[],
remaining_min: 0,
remaining_max: self.length
};
loop {
let children = &node.children;
let child_id = chunk(key, idx);
match children[child_id] {
Internal(ref n) => {
node = &**n;
it.stack.push(children.slice_from(child_id + 1).iter());
}
External(stored, _) => {
if stored < key || (upper && stored == key) {
it.stack.push(children.slice_from(child_id + 1).iter());
} else {
it.stack.push(children.slice_from(child_id).iter());
}
return it;
}
Nothing => {
it.stack.push(children.slice_from(child_id + 1).iter());
return it
}
}
idx += 1;
}
}
/// Get an iterator pointing to the first key-value pair whose key is not less than `key`.
/// If all keys in the map are less than `key` an empty iterator is returned.
pub fn lower_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> {
self.bound_iter(key, false)
}
/// Get an iterator pointing to the first key-value pair whose key is greater than `key`.
/// If all keys in the map are not greater than `key` an empty iterator is returned.
pub fn upper_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> {
self.bound_iter(key, true)
}
}
impl<T, Iter: Iterator<(uint, T)>> FromIterator<(uint, T), Iter> for TrieMap<T> {
@ -233,6 +280,18 @@ impl TrieSet {
pub fn iter<'a>(&'a self) -> TrieSetIterator<'a> {
TrieSetIterator{iter: self.map.iter()}
}
/// Get an iterator pointing to the first value that is not less than `val`.
/// If all values in the set are less than `val` an empty iterator is returned.
pub fn lower_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> {
TrieSetIterator{iter: self.map.lower_bound_iter(val)}
}
/// Get an iterator pointing to the first value that key is greater than `val`.
/// If all values in the set are not greater than `val` an empty iterator is returned.
pub fn upper_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> {
TrieSetIterator{iter: self.map.upper_bound_iter(val)}
}
}
impl<Iter: Iterator<uint>> FromIterator<uint, Iter> for TrieSet {
@ -645,6 +704,49 @@ mod test_map {
}
assert_eq!(i, last - first);
}
#[test]
fn test_bound_iter() {
let empty_map : TrieMap<uint> = TrieMap::new();
assert_eq!(empty_map.lower_bound_iter(0).next(), None);
assert_eq!(empty_map.upper_bound_iter(0).next(), None);
let last = 999u;
let step = 3u;
let value = 42u;
let mut map : TrieMap<uint> = TrieMap::new();
do uint::range_step(0u, last, step as int) |x| {
assert!(x % step == 0);
map.insert(x, value);
true
};
for i in range(0u, last - step) {
let mut lb = map.lower_bound_iter(i);
let mut ub = map.upper_bound_iter(i);
let next_key = i - i % step + step;
let next_pair = (next_key, &value);
if (i % step == 0) {
assert_eq!(lb.next(), Some((i, &value)));
} else {
assert_eq!(lb.next(), Some(next_pair));
}
assert_eq!(ub.next(), Some(next_pair));
}
let mut lb = map.lower_bound_iter(last - step);
assert_eq!(lb.next(), Some((last - step, &value)));
let mut ub = map.upper_bound_iter(last - step);
assert_eq!(ub.next(), None);
for i in range(last - step + 1, last) {
let mut lb = map.lower_bound_iter(i);
assert_eq!(lb.next(), None);
let mut ub = map.upper_bound_iter(i);
assert_eq!(ub.next(), None);
}
}
}
#[cfg(test)]

View File

@ -421,12 +421,12 @@ pub enum MapChain<K,V> {
// get the map from an env frame
impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// Constructor. I don't think we need a zero-arg one.
fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
pub fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
@mut BaseMapChain(init)
}
// add a new frame to the environment (functionally)
fn push_frame (@mut self) -> @mut MapChain<K,V> {
pub fn push_frame (@mut self) -> @mut MapChain<K,V> {
@mut ConsMapChain(~HashMap::new() ,self)
}
@ -436,7 +436,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// ugh: can't get this to compile with mut because of the
// lack of flow sensitivity.
fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
pub fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
match *self {
BaseMapChain (~ref map) => map,
ConsMapChain (~ref map,_) => map
@ -446,7 +446,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// traits just don't work anywhere...?
//impl Map<Name,SyntaxExtension> for MapChain {
fn contains_key (&self, key: &K) -> bool {
pub fn contains_key (&self, key: &K) -> bool {
match *self {
BaseMapChain (ref map) => map.contains_key(key),
ConsMapChain (ref map,ref rest) =>
@ -457,17 +457,17 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// should each_key and each_value operate on shadowed
// names? I think not.
// delaying implementing this....
fn each_key (&self, _f: &fn (&K)->bool) {
pub fn each_key (&self, _f: &fn (&K)->bool) {
fail!("unimplemented 2013-02-15T10:01");
}
fn each_value (&self, _f: &fn (&V) -> bool) {
pub fn each_value (&self, _f: &fn (&V) -> bool) {
fail!("unimplemented 2013-02-15T10:02");
}
// Returns a copy of the value that the name maps to.
// Goes down the chain 'til it finds one (or bottom out).
fn find (&self, key: &K) -> Option<@V> {
pub fn find (&self, key: &K) -> Option<@V> {
match self.get_map().find (key) {
Some(ref v) => Some(**v),
None => match *self {
@ -477,7 +477,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
}
}
fn find_in_topmost_frame(&self, key: &K) -> Option<@V> {
pub fn find_in_topmost_frame(&self, key: &K) -> Option<@V> {
let map = match *self {
BaseMapChain(ref map) => map,
ConsMapChain(ref map,_) => map
@ -487,7 +487,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
}
// insert the binding into the top-level map
fn insert (&mut self, key: K, ext: @V) -> bool {
pub fn insert (&mut self, key: K, ext: @V) -> bool {
// can't abstract over get_map because of flow sensitivity...
match *self {
BaseMapChain (~ref mut map) => map.insert(key, ext),
@ -499,7 +499,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// ... there are definitely some opportunities for abstraction
// here that I'm ignoring. (e.g., manufacturing a predicate on
// the maps in the chain, and using an abstract "find".
fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) {
pub fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) {
match *self {
BaseMapChain (~ref mut map) => {
if satisfies_pred(map,&n,pred) {

View File

@ -17,6 +17,7 @@ use codemap;
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
use parse::parser::Parser;
use parse::attr::parser_attr;
use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
use parse::token;
@ -430,6 +431,7 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal {
+ token::to_str(get_ident_interner(), p.token))
},
"path" => token::nt_path(p.parse_path_with_tps(false)),
"attr" => token::nt_attr(@p.parse_attribute(false)),
"tt" => {
*p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
let res = token::nt_tt(@p.parse_token_tree());

View File

@ -36,7 +36,7 @@ pub fn from<T>(t: ~[T]) -> OptVec<T> {
}
impl<T> OptVec<T> {
fn push(&mut self, t: T) {
pub fn push(&mut self, t: T) {
match *self {
Vec(ref mut v) => {
v.push(t);
@ -50,32 +50,32 @@ impl<T> OptVec<T> {
*self = Vec(~[t]);
}
fn map<U>(&self, op: &fn(&T) -> U) -> OptVec<U> {
pub fn map<U>(&self, op: &fn(&T) -> U) -> OptVec<U> {
match *self {
Empty => Empty,
Vec(ref v) => Vec(v.map(op))
}
}
fn map_move<U>(self, op: &fn(T) -> U) -> OptVec<U> {
pub fn map_move<U>(self, op: &fn(T) -> U) -> OptVec<U> {
match self {
Empty => Empty,
Vec(v) => Vec(v.move_iter().map(op).collect())
}
}
fn get<'a>(&'a self, i: uint) -> &'a T {
pub fn get<'a>(&'a self, i: uint) -> &'a T {
match *self {
Empty => fail!("Invalid index %u", i),
Vec(ref v) => &v[i]
}
}
fn is_empty(&self) -> bool {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
fn len(&self) -> uint {
pub fn len(&self) -> uint {
match *self {
Empty => 0,
Vec(ref v) => v.len()
@ -83,7 +83,7 @@ impl<T> OptVec<T> {
}
#[inline]
fn iter<'r>(&'r self) -> OptVecIterator<'r, T> {
pub fn iter<'r>(&'r self) -> OptVecIterator<'r, T> {
match *self {
Empty => OptVecIterator{iter: None},
Vec(ref v) => OptVecIterator{iter: Some(v.iter())}
@ -91,11 +91,11 @@ impl<T> OptVec<T> {
}
#[inline]
fn map_to_vec<B>(&self, op: &fn(&T) -> B) -> ~[B] {
pub fn map_to_vec<B>(&self, op: &fn(&T) -> B) -> ~[B] {
self.iter().map(op).collect()
}
fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] {
pub fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] {
let mut index = 0;
self.map_to_vec(|a| {
let i = index;
@ -113,7 +113,7 @@ pub fn take_vec<T>(v: OptVec<T>) -> ~[T] {
}
impl<T:Clone> OptVec<T> {
fn prepend(&self, t: T) -> OptVec<T> {
pub fn prepend(&self, t: T) -> OptVec<T> {
let mut v0 = ~[t];
match *self {
Empty => {}
@ -124,7 +124,7 @@ impl<T:Clone> OptVec<T> {
}
impl<A:Eq> Eq for OptVec<A> {
fn eq(&self, other: &OptVec<A>) -> bool {
pub fn eq(&self, other: &OptVec<A>) -> bool {
// Note: cannot use #[deriving(Eq)] here because
// (Empty, Vec(~[])) ought to be equal.
match (self, other) {
@ -135,7 +135,7 @@ impl<A:Eq> Eq for OptVec<A> {
}
}
fn ne(&self, other: &OptVec<A>) -> bool {
pub fn ne(&self, other: &OptVec<A>) -> bool {
!self.eq(other)
}
}

View File

@ -9,21 +9,17 @@
// except according to those terms.
use ast;
use codemap::spanned;
use codemap::{spanned, mk_sp};
use codemap::BytePos;
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
use parse::token::INTERPOLATED;
// a parser that can parse attributes.
pub trait parser_attr {
fn parse_outer_attributes(&self) -> ~[ast::Attribute];
fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute;
fn parse_attribute_naked(
&self,
style: ast::AttrStyle,
lo: BytePos
) -> ast::Attribute;
fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute;
fn parse_inner_attrs_and_next(&self) ->
(~[ast::Attribute], ~[ast::Attribute]);
fn parse_meta_item(&self) -> @ast::MetaItem;
@ -37,12 +33,17 @@ impl parser_attr for Parser {
fn parse_outer_attributes(&self) -> ~[ast::Attribute] {
let mut attrs: ~[ast::Attribute] = ~[];
loop {
debug!("parse_outer_attributes: self.token=%?",
self.token);
match *self.token {
token::INTERPOLATED(token::nt_attr(*)) => {
attrs.push(self.parse_attribute(false));
}
token::POUND => {
if self.look_ahead(1, |t| *t != token::LBRACKET) {
break;
}
attrs.push(self.parse_attribute(ast::AttrOuter));
attrs.push(self.parse_attribute(false));
}
token::DOC_COMMENT(s) => {
let attr = ::attr::mk_sugared_doc_attr(
@ -62,23 +63,49 @@ impl parser_attr for Parser {
return attrs;
}
// matches attribute = # attribute_naked
fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute {
let lo = self.span.lo;
self.expect(&token::POUND);
return self.parse_attribute_naked(style, lo);
// matches attribute = # [ meta_item ]
//
// if permit_inner is true, then a trailing `;` indicates an inner
// attribute
fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute {
debug!("parse_attributes: permit_inner=%? self.token=%?",
permit_inner, self.token);
let (span, value) = match *self.token {
INTERPOLATED(token::nt_attr(attr)) => {
assert!(attr.node.style == ast::AttrOuter);
self.bump();
(attr.span, attr.node.value)
}
token::POUND => {
let lo = self.span.lo;
self.bump();
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
self.expect(&token::RBRACKET);
let hi = self.span.hi;
(mk_sp(lo, hi), meta_item)
}
_ => {
self.fatal(fmt!("expected `#` but found `%s`",
self.this_token_to_str()));
}
};
let style = if permit_inner && *self.token == token::SEMI {
self.bump();
ast::AttrInner
} else {
ast::AttrOuter
};
return spanned {
span: span,
node: ast::Attribute_ {
style: style,
value: value,
is_sugared_doc: false
}
};
}
// matches attribute_naked = [ meta_item ]
fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) ->
ast::Attribute {
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
self.expect(&token::RBRACKET);
let hi = self.span.hi;
return spanned(lo, hi, ast::Attribute_ { style: style,
value: meta_item, is_sugared_doc: false }); }
// Parse attributes that appear after the opening of an item, each
// terminated by a semicolon. In addition to a vector of inner attributes,
// this function also returns a vector that may contain the first outer
@ -89,47 +116,37 @@ impl parser_attr for Parser {
// matches inner_attrs* outer_attr?
// you can make the 'next' field an Option, but the result is going to be
// more useful as a vector.
fn parse_inner_attrs_and_next(&self) ->
(~[ast::Attribute], ~[ast::Attribute]) {
fn parse_inner_attrs_and_next(&self)
-> (~[ast::Attribute], ~[ast::Attribute]) {
let mut inner_attrs: ~[ast::Attribute] = ~[];
let mut next_outer_attrs: ~[ast::Attribute] = ~[];
loop {
match *self.token {
token::POUND => {
if self.look_ahead(1, |t| *t != token::LBRACKET) {
// This is an extension
break;
let attr = match *self.token {
token::INTERPOLATED(token::nt_attr(*)) => {
self.parse_attribute(true)
}
let attr = self.parse_attribute(ast::AttrInner);
if *self.token == token::SEMI {
token::POUND => {
if self.look_ahead(1, |t| *t != token::LBRACKET) {
// This is an extension
break;
}
self.parse_attribute(true)
}
token::DOC_COMMENT(s) => {
self.bump();
inner_attrs.push(attr);
} else {
// It's not really an inner attribute
let outer_attr =
spanned(attr.span.lo, attr.span.hi,
ast::Attribute_ { style: ast::AttrOuter,
value: attr.node.value,
is_sugared_doc: false });
next_outer_attrs.push(outer_attr);
::attr::mk_sugared_doc_attr(self.id_to_str(s),
self.span.lo,
self.span.hi)
}
_ => {
break;
}
}
token::DOC_COMMENT(s) => {
let attr = ::attr::mk_sugared_doc_attr(
self.id_to_str(s),
self.span.lo,
self.span.hi
);
self.bump();
if attr.node.style == ast::AttrInner {
inner_attrs.push(attr);
} else {
next_outer_attrs.push(attr);
break;
}
}
_ => break
};
if attr.node.style == ast::AttrInner {
inner_attrs.push(attr);
} else {
next_outer_attrs.push(attr);
break;
}
}
(inner_attrs, next_outer_attrs)

View File

@ -129,7 +129,11 @@ impl reader for StringReader {
impl reader for TtReader {
fn is_eof(@mut self) -> bool { self.cur_tok == token::EOF }
fn next_token(@mut self) -> TokenAndSpan { tt_next_token(self) }
fn next_token(@mut self) -> TokenAndSpan {
let r = tt_next_token(self);
debug!("TtReader: r=%?", r);
return r;
}
fn fatal(@mut self, m: ~str) -> ! {
self.sp_diag.span_fatal(self.cur_span, m);
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_escape];
use abi;
use abi::AbiSet;
use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil};
@ -4460,7 +4462,17 @@ impl Parser {
attrs: ~[Attribute],
macros_allowed: bool)
-> item_or_view_item {
maybe_whole!(iovi self, nt_item);
match *self.token {
INTERPOLATED(token::nt_item(item)) => {
self.bump();
let new_attrs = vec::append(attrs, item.attrs);
return iovi_item(@ast::item {
attrs: new_attrs,
..(*item).clone()});
}
_ => {}
}
let lo = self.span.lo;
let visibility = self.parse_non_priv_visibility();

View File

@ -105,6 +105,7 @@ pub enum nonterminal {
nt_expr(@ast::expr),
nt_ty( ast::Ty),
nt_ident(ast::ident, bool),
nt_attr(@ast::Attribute), // #[foo]
nt_path( ast::Path),
nt_tt( @ast::token_tree), //needs @ed to break a circularity
nt_matchers(~[ast::matcher])
@ -205,6 +206,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str {
INTERPOLATED(ref nt) => {
match nt {
&nt_expr(e) => ::print::pprust::expr_to_str(e, input),
&nt_attr(e) => ::print::pprust::attribute_to_str(e, input),
_ => {
~"an interpolated " +
match (*nt) {
@ -212,6 +214,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str {
nt_block(*) => ~"block",
nt_stmt(*) => ~"statement",
nt_pat(*) => ~"pattern",
nt_attr(*) => fail!("should have been handled"),
nt_expr(*) => fail!("should have been handled above"),
nt_ty(*) => ~"type",
nt_ident(*) => ~"identifier",

View File

@ -1,9 +1,33 @@
#[crate_type="lib"];
pub struct Foo {
pub struct Struct {
x: int
}
impl Foo {
fn new() -> Foo { Foo { x: 1 } }
impl Struct {
fn static_meth_struct() -> Struct {
Struct { x: 1 }
}
fn meth_struct(&self) -> int {
self.x
}
}
pub enum Enum {
Variant1(int),
Variant2(int)
}
impl Enum {
fn static_meth_enum() -> Enum {
Variant2(10)
}
fn meth_enum(&self) -> int {
match *self {
Variant1(x) |
Variant2(x) => x
}
}
}

View File

@ -6,7 +6,7 @@ struct Foo {
}
pub fn main() {
let x = [
let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }

View File

@ -1,5 +1,5 @@
fn a() -> &[int] {
let vec = [1, 2, 3, 4];
let vec = ~[1, 2, 3, 4];
let tail = match vec {
[_, ..tail] => tail, //~ ERROR does not live long enough
_ => fail!("a")
@ -8,7 +8,7 @@ fn a() -> &[int] {
}
fn b() -> &[int] {
let vec = [1, 2, 3, 4];
let vec = ~[1, 2, 3, 4];
let init = match vec {
[..init, _] => init, //~ ERROR does not live long enough
_ => fail!("b")
@ -17,7 +17,7 @@ fn b() -> &[int] {
}
fn c() -> &[int] {
let vec = [1, 2, 3, 4];
let vec = ~[1, 2, 3, 4];
let slice = match vec {
[_, ..slice, _] => slice, //~ ERROR does not live long enough
_ => fail!("c")

View File

@ -1,24 +1,24 @@
fn a() {
let mut vec = [~1, ~2, ~3];
let mut vec = ~[~1, ~2, ~3];
match vec {
[~ref _a] => {
vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed
vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed
}
_ => fail!("foo")
}
}
fn b() {
let mut vec = [~1, ~2, ~3];
let mut vec = ~[~1, ~2, ~3];
match vec {
[.._b] => {
vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed
vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed
}
}
}
fn c() {
let mut vec = [~1, ~2, ~3];
let mut vec = ~[~1, ~2, ~3];
match vec {
[_a, .._b] => {
//~^ ERROR cannot move out
@ -35,7 +35,7 @@ fn c() {
}
fn d() {
let mut vec = [~1, ~2, ~3];
let mut vec = ~[~1, ~2, ~3];
match vec {
[.._a, _b] => {
//~^ ERROR cannot move out
@ -46,7 +46,7 @@ fn d() {
}
fn e() {
let mut vec = [~1, ~2, ~3];
let mut vec = ~[~1, ~2, ~3];
match vec {
[_a, _b, _c] => {}
_ => {}

View File

@ -1,5 +1,5 @@
fn a() -> &int {
let vec = [1, 2, 3, 4];
let vec = ~[1, 2, 3, 4];
let tail = match vec {
[_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough
_ => fail!("foo")

View File

@ -0,0 +1,21 @@
macro_rules! test ( ($nm:ident,
$a:attr,
$i:item) => (mod $nm { $a; $i }); )
test!(a,
#[cfg(qux)],
pub fn bar() { })
test!(b,
#[cfg(not(qux))],
pub fn bar() { })
#[qux]
fn main() {
a::bar();
//~^ ERROR use of undeclared module `a`
//~^^ ERROR unresolved name
//~^^^ ERROR unresolved name `a::bar`
b::bar();
}

View File

@ -0,0 +1,19 @@
macro_rules! test ( ($nm:ident,
$a:attr,
$i:item) => (mod $nm { $a $i }); )
test!(a,
#[cfg(qux)],
pub fn bar() { })
test!(b,
#[cfg(not(qux))],
pub fn bar() { })
// test1!(#[bar])
#[qux]
fn main() {
a::bar(); //~ ERROR unresolved name `a::bar`
b::bar();
}

View File

@ -0,0 +1,16 @@
fn a() {
let v = [1, 2, 3];
match v {
[_, _, _] => {}
[_, _, _] => {} //~ ERROR unreachable pattern
}
match v {
[_, 1, _] => {}
[_, 1, _] => {} //~ ERROR unreachable pattern
_ => {}
}
}
fn main() {
a();
}

View File

@ -6,13 +6,13 @@ fn main() {
_ => ()
}
match [~"foo", ~"bar", ~"baz"] {
match ~[~"foo", ~"bar", ~"baz"] {
[a, _, _, .._] => { println(a); }
[~"foo", ~"bar", ~"baz", ~"foo", ~"bar"] => { } //~ ERROR unreachable pattern
_ => { }
}
match ['a', 'b', 'c'] {
match ~['a', 'b', 'c'] {
['a', 'b', 'c', .._tail] => {}
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
_ => {}

View File

@ -4,5 +4,13 @@
extern mod xc_private_method_lib;
fn main() {
let _ = xc_private_method_lib::Foo::new(); //~ ERROR function `new` is private
// normal method on struct
let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private
// static method on struct
let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR function `static_meth_struct` is private
// normal method on enum
let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private
// static method on enum
let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR function `static_meth_enum` is private
}

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-test
enum side { mayo, catsup, vinegar }
enum order { hamburger, fries(side), shake }
enum meal { to_go(order), for_here(order) }

View File

@ -1,22 +1,22 @@
pub fn main() {
let x = @[1, 2, 3];
match x {
[2, .._] => ::std::util::unreachable(),
[2, .._] => fail!(),
[1, ..tail] => {
assert_eq!(tail, [2, 3]);
}
[_] => ::std::util::unreachable(),
[] => ::std::util::unreachable()
[_] => fail!(),
[] => fail!()
}
let y = (~[(1, true), (2, false)], 0.5);
match y {
([_, _, _], 0.5) => ::std::util::unreachable(),
([_, _, _], 0.5) => fail!(),
([(1, a), (b, false), ..tail], _) => {
assert_eq!(a, true);
assert_eq!(b, 2);
assert!(tail.is_empty());
}
([..tail], _) => ::std::util::unreachable()
([..tail], _) => fail!()
}
}

View File

@ -0,0 +1,28 @@
fn a() {
let x = [1, 2, 3];
match x {
[1, 2, 4] => ::std::util::unreachable(),
[0, 2, 3, .._] => ::std::util::unreachable(),
[0, .._, 3] => ::std::util::unreachable(),
[0, .._] => ::std::util::unreachable(),
[1, 2, 3] => (),
[_, _, _] => ::std::util::unreachable(),
}
match x {
[.._] => (),
}
match x {
[_, _, _, .._] => (),
}
match x {
[a, b, c] => {
assert_eq!(1, a);
assert_eq!(2, b);
assert_eq!(3, c);
}
}
}
pub fn main() {
a();
}

View File

@ -1,19 +1,19 @@
fn a() {
let x = [1];
let x = ~[1];
match x {
[_, _, _, _, _, .._] => ::std::util::unreachable(),
[.._, _, _, _, _] => ::std::util::unreachable(),
[_, .._, _, _] => ::std::util::unreachable(),
[_, _] => ::std::util::unreachable(),
[_, _, _, _, _, .._] => fail!(),
[.._, _, _, _, _] => fail!(),
[_, .._, _, _] => fail!(),
[_, _] => fail!(),
[a] => {
assert_eq!(a, 1);
}
[] => ::std::util::unreachable()
[] => fail!()
}
}
fn b() {
let x = [1, 2, 3];
let x = ~[1, 2, 3];
match x {
[a, b, ..c] => {
assert_eq!(a, 1);
@ -48,7 +48,28 @@ fn b() {
}
}
fn c() {
let x = [1];
match x {
[2, .. _] => fail!(),
[.. _] => ()
}
}
fn d() {
let x = [1, 2, 3];
let branch = match x {
[1, 1, .. _] => 0,
[1, 2, 3, .. _] => 1,
[1, 2, .. _] => 2,
_ => 3
};
assert_eq!(branch, 1);
}
pub fn main() {
a();
b();
c();
d();
}

View File

@ -3,7 +3,7 @@ struct Foo {
}
pub fn main() {
let x = [
let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }