diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 99c5722699e8d..26baf96a8bc86 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -17,7 +17,10 @@
use mem::transmute;
use option::{None, Option, Some};
-use iter::{Iterator, range_step};
+use iter::range_step;
+
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
// UTF-8 ranges and tags for encoding characters
static TAG_CONT: u8 = 0b1000_0000u8;
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
index ef5b51fd00b3f..386fc28119a3e 100644
--- a/src/libcore/fmt/float.rs
+++ b/src/libcore/fmt/float.rs
@@ -13,15 +13,19 @@
use char;
use collections::Collection;
use fmt;
-use iter::{Iterator, range, DoubleEndedIterator};
+use iter::{range, DoubleEndedIterator};
use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
use num::{Zero, One, cast};
-use option::{None, Some};
use result::Ok;
use slice::{ImmutableVector, MutableVector};
use slice;
use str::StrSlice;
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+#[cfg(stage0)]
+use option::{Some, None}; // NOTE(stage0): Remove after snapshot.
+
/// A flag that specifies whether to use exponential (scientific) notation.
pub enum ExponentFormat {
/// Do not use exponential notation.
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index d52791f6b0ea2..81e84c447e796 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -16,11 +16,15 @@
use collections::Collection;
use fmt;
-use iter::{Iterator, DoubleEndedIterator};
+use iter::DoubleEndedIterator;
use num::{Int, cast, zero};
-use option::{Some, None};
use slice::{ImmutableVector, MutableVector};
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+#[cfg(stage0)]
+use option::{Some, None}; // NOTE(stage0): Remove after snapshot.
+
/// A type that represents a specific radix
trait GenericRadix {
/// The number of digits.
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 7706d01cbaed6..b0660230c2ce6 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -95,6 +95,7 @@ pub trait Extendable: FromIterator {
/// is returned. A concrete Iterator implementation may choose to behave however
/// it wishes, either by returning `None` infinitely, or by doing something
/// else.
+#[lang="iterator"]
pub trait Iterator {
/// Advance the iterator and return the next value. Return `None` when the end is reached.
fn next(&mut self) -> Option;
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index b8612ed93e02d..84b402a68dd12 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -147,7 +147,12 @@ use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSize};
use mem;
use slice;
-/// The `Option`
+// Note that this is not a lang item per se, but it has a hidden dependency on
+// `Iterator`, which is one. The compiler assumes that the `next` method of
+// `Iterator` is an enumeration with one type parameter and two variants,
+// which basically means it must be `Option`.
+
+/// The `Option` type.
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)]
pub enum Option {
/// No value
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index ed1d4d481100b..4921802ba732e 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -90,11 +90,14 @@
use mem;
use clone::Clone;
use intrinsics;
-use iter::{range, Iterator};
+use iter::range;
use option::{Some, None, Option};
use cmp::{PartialEq, Eq, PartialOrd, Equiv, Ordering, Less, Equal, Greater};
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+
pub use intrinsics::copy_memory;
pub use intrinsics::copy_nonoverlapping_memory;
pub use intrinsics::set_memory;
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index 37af64d74d414..2ba51eb98fca0 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -28,7 +28,7 @@ use iter::{Map, Iterator};
use iter::{DoubleEndedIterator, ExactSize};
use iter::range;
use num::{CheckedMul, Saturating};
-use option::{None, Option, Some};
+use option::{Option, None, Some};
use raw::Repr;
use slice::ImmutableVector;
use slice;
@@ -1027,9 +1027,12 @@ pub mod traits {
use cmp::{Ord, Ordering, Less, Equal, Greater, PartialEq, PartialOrd, Equiv, Eq};
use collections::Collection;
use iter::Iterator;
- use option::{Option, Some, None};
+ use option::{Option, Some};
use str::{Str, StrSlice, eq_slice};
+ #[cfg(stage0)]
+ use option::None; // NOTE(stage0): Remove after snapshot.
+
impl<'a> Ord for &'a str {
#[inline]
fn cmp(&self, other: & &'a str) -> Ordering {
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 64c336093996d..cadbc238e679a 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -137,8 +137,8 @@ fn test_iterator_take_while() {
let ys = [0u, 1, 2, 3, 5, 13];
let mut it = xs.iter().take_while(|&x| *x < 15u);
let mut i = 0;
- for &x in it {
- assert_eq!(x, ys[i]);
+ for x in it {
+ assert_eq!(*x, ys[i]);
i += 1;
}
assert_eq!(i, ys.len());
@@ -150,8 +150,8 @@ fn test_iterator_skip_while() {
let ys = [15, 16, 17, 19];
let mut it = xs.iter().skip_while(|&x| *x < 15u);
let mut i = 0;
- for &x in it {
- assert_eq!(x, ys[i]);
+ for x in it {
+ assert_eq!(*x, ys[i]);
i += 1;
}
assert_eq!(i, ys.len());
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 2aa0818b177cf..b570cb43f164e 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -440,6 +440,7 @@ impl<'a> CheckLoanCtxt<'a> {
euv::AddrOf(..) |
euv::AutoRef(..) |
euv::ClosureInvocation(..) |
+ euv::ForLoop(..) |
euv::RefBinding(..) => {
format!("previous borrow of `{}` occurs here",
self.bccx.loan_path_to_string(&*old_loan.loan_path))
@@ -668,6 +669,11 @@ impl<'a> CheckLoanCtxt<'a> {
return;
}
+ // Initializations are OK.
+ if mode == euv::Init {
+ return
+ }
+
// For immutable local variables, assignments are legal
// if they cannot already have been assigned
if self.is_local_variable_or_arg(assignee_cmt.clone()) {
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 5604d33496d9d..3ed0f61a8f064 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -651,7 +651,8 @@ impl<'a> BorrowckCtxt<'a> {
euv::OverloadedOperator |
euv::AddrOf |
euv::RefBinding |
- euv::AutoRef => {
+ euv::AutoRef |
+ euv::ForLoop => {
format!("cannot borrow {} as mutable", descr)
}
euv::ClosureInvocation => {
@@ -712,6 +713,10 @@ impl<'a> BorrowckCtxt<'a> {
BorrowViolation(euv::ClosureInvocation) => {
"closure invocation"
}
+
+ BorrowViolation(euv::ForLoop) => {
+ "`for` loop"
+ }
};
match cause {
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 208a9d057166e..4f6885f05ed16 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -240,7 +240,7 @@ impl<'a> CFGBuilder<'a> {
// v 3
// [expr]
//
- // Note that `break` and `loop` statements
+ // Note that `break` and `continue` statements
// may cause additional edges.
// Is the condition considered part of the loop?
@@ -258,7 +258,44 @@ impl<'a> CFGBuilder<'a> {
expr_exit
}
- ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+ ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+ //
+ // [pred]
+ // |
+ // v 1
+ // [head]
+ // |
+ // v 2
+ // [loopback] <--+ 7
+ // | |
+ // v 3 |
+ // +------[cond] |
+ // | | |
+ // | v 5 |
+ // | [pat] |
+ // | | |
+ // | v 6 |
+ // v 4 [body] -----+
+ // [expr]
+ //
+ // Note that `break` and `continue` statements
+ // may cause additional edges.
+
+ let head = self.expr(head.clone(), pred); // 1
+ let loopback = self.add_dummy_node([head]); // 2
+ let cond = self.add_dummy_node([loopback]); // 3
+ let expr_exit = self.add_node(expr.id, [cond]); // 4
+ self.loop_scopes.push(LoopScope {
+ loop_id: expr.id,
+ continue_index: loopback,
+ break_index: expr_exit,
+ });
+ let pat = self.pat(&**pat, cond); // 5
+ let body = self.block(&**body, pat); // 6
+ self.add_contained_edge(body, loopback); // 7
+ self.loop_scopes.pop();
+ expr_exit
+ }
ast::ExprLoop(ref body, _) => {
//
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index ac8faaa6c6db5..61a2e8407303b 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -42,6 +42,10 @@ impl<'a> Visitor for CheckLoopVisitor<'a> {
ast::ExprLoop(ref b, _) => {
self.visit_block(&**b, Loop);
}
+ ast::ExprForLoop(_, ref e, ref b, _) => {
+ self.visit_expr(&**e, cx);
+ self.visit_block(&**b, Loop);
+ }
ast::ExprFnBlock(_, ref b) |
ast::ExprProc(_, ref b) |
ast::ExprUnboxedFn(_, ref b) => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 67208e3337286..e458b82f03634 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -170,6 +170,24 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
.collect();
check_exhaustive(cx, ex.span, &matrix);
},
+ ExprForLoop(ref pat, _, _, _) => {
+ let mut static_inliner = StaticInliner {
+ tcx: cx.tcx
+ };
+ match is_refutable(cx, static_inliner.fold_pat(*pat)) {
+ Some(uncovered_pat) => {
+ cx.tcx.sess.span_err(
+ pat.span,
+ format!("refutable pattern in `for` loop binding: \
+ `{}` not covered",
+ pat_to_string(&*uncovered_pat)).as_slice());
+ },
+ None => {}
+ }
+
+ // Check legality of move bindings.
+ check_legality_of_move_bindings(cx, false, [ *pat ]);
+ }
_ => ()
}
}
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 9fc589ddf59eb..108bd35424aec 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -354,11 +354,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
// depending on whether a crate is built as bin or lib, and we want
// the warning to be consistent, we also seed the worklist with
// exported symbols.
- for &id in exported_items.iter() {
- worklist.push(id);
+ for id in exported_items.iter() {
+ worklist.push(*id);
}
- for &id in reachable_symbols.iter() {
- worklist.push(id);
+ for id in reachable_symbols.iter() {
+ worklist.push(*id);
}
// Seed entry point
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b911e636da091..7995317d49fd1 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -79,7 +79,8 @@ pub enum LoanCause {
AutoRef,
RefBinding,
OverloadedOperator,
- ClosureInvocation
+ ClosureInvocation,
+ ForLoop,
}
#[deriving(PartialEq,Show)]
@@ -395,7 +396,16 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
self.walk_block(&**blk);
}
- ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+ ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
+ // The pattern lives as long as the block.
+ debug!("walk_expr for loop case: blk id={}", blk.id);
+ self.walk_expr(&**head);
+
+ let head_cmt = return_if_err!(self.mc.cat_expr(&**head));
+ self.walk_pat(head_cmt, pat.clone());
+
+ self.walk_block(&**blk);
+ }
ast::ExprUnary(_, ref lhs) => {
if !self.walk_overloaded_operator(expr, &**lhs, []) {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 9abc9226c1364..f59909bd138b2 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -299,5 +299,7 @@ lets_do_this! {
NoShareItem, "no_share_bound", no_share_bound;
ManagedItem, "managed_bound", managed_bound;
+ IteratorItem, "iterator", iterator;
+
StackExhaustedLangItem, "stack_exhausted", stack_exhausted;
}
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 737b952151b67..1c31b671a947b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -125,6 +125,17 @@ use syntax::print::pprust::{expr_to_string, block_to_string};
use syntax::{visit, ast_util};
use syntax::visit::{Visitor, FnKind};
+/// For use with `propagate_through_loop`.
+#[deriving(PartialEq, Eq)]
+enum LoopKind {
+ /// An endless `loop` loop.
+ LoopLoop,
+ /// A `while` loop, with the given expression as condition.
+ WhileLoop(Gc),
+ /// A `for` loop.
+ ForLoop,
+}
+
#[deriving(PartialEq)]
struct Variable(uint);
#[deriving(PartialEq)]
@@ -480,7 +491,20 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
visit::walk_expr(ir, expr, ());
}
- ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+ ExprForLoop(ref pat, _, _, _) => {
+ pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
+ debug!("adding local variable {} from for loop with bm {:?}",
+ p_id, bm);
+ let name = path1.node;
+ ir.add_live_node_for_node(p_id, VarDefNode(sp));
+ ir.add_variable(Local(LocalInfo {
+ id: p_id,
+ ident: name
+ }));
+ });
+ ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+ visit::walk_expr(ir, expr, ());
+ }
ExprBinary(op, _, _) if ast_util::lazy_binop(op) => {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
visit::walk_expr(ir, expr, ());
@@ -994,15 +1018,21 @@ impl<'a> Liveness<'a> {
}
ExprWhile(ref cond, ref blk) => {
- self.propagate_through_loop(expr, Some(cond.clone()), &**blk, succ)
+ self.propagate_through_loop(expr,
+ WhileLoop(cond.clone()),
+ &**blk,
+ succ)
}
- ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+ ExprForLoop(_, ref head, ref blk, _) => {
+ let ln = self.propagate_through_loop(expr, ForLoop, &**blk, succ);
+ self.propagate_through_expr(&**head, ln)
+ }
// Note that labels have been resolved, so we don't need to look
// at the label ident
ExprLoop(ref blk, _) => {
- self.propagate_through_loop(expr, None, &**blk, succ)
+ self.propagate_through_loop(expr, LoopLoop, &**blk, succ)
}
ExprMatch(ref e, ref arms) => {
@@ -1281,7 +1311,7 @@ impl<'a> Liveness<'a> {
fn propagate_through_loop(&mut self,
expr: &Expr,
- cond: Option>,
+ kind: LoopKind,
body: &Block,
succ: LiveNode)
-> LiveNode {
@@ -1309,17 +1339,20 @@ impl<'a> Liveness<'a> {
let mut first_merge = true;
let ln = self.live_node(expr.id, expr.span);
self.init_empty(ln, succ);
- if cond.is_some() {
- // if there is a condition, then it's possible we bypass
- // the body altogether. otherwise, the only way is via a
- // break in the loop body.
+ if kind != LoopLoop {
+ // If this is not a `loop` loop, then it's possible we bypass
+ // the body altogether. Otherwise, the only way is via a `break`
+ // in the loop body.
self.merge_from_succ(ln, succ, first_merge);
first_merge = false;
}
debug!("propagate_through_loop: using id for loop body {} {}",
expr.id, block_to_string(body));
- let cond_ln = self.propagate_through_opt_expr(cond, ln);
+ let cond_ln = match kind {
+ LoopLoop | ForLoop => ln,
+ WhileLoop(ref cond) => self.propagate_through_expr(&**cond, ln),
+ };
let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| {
this.propagate_through_block(body, cond_ln)
});
@@ -1327,8 +1360,14 @@ impl<'a> Liveness<'a> {
// repeat until fixed point is reached:
while self.merge_from_succ(ln, body_ln, first_merge) {
first_merge = false;
- assert!(cond_ln == self.propagate_through_opt_expr(cond,
- ln));
+
+ let new_cond_ln = match kind {
+ LoopLoop | ForLoop => ln,
+ WhileLoop(ref cond) => {
+ self.propagate_through_expr(&**cond, ln)
+ }
+ };
+ assert!(cond_ln == new_cond_ln);
assert!(body_ln == self.with_loop_nodes(expr.id, succ, ln,
|this| this.propagate_through_block(body, cond_ln)));
}
@@ -1415,10 +1454,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
- ExprPath(..) | ExprBox(..) => {
+ ExprPath(..) | ExprBox(..) | ExprForLoop(..) => {
visit::walk_expr(this, expr, ());
}
- ExprForLoop(..) => fail!("non-desugared expr_for_loop")
}
}
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index baf7f2dd77650..317fdb5c387e2 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -482,11 +482,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
- ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
+ ast::ExprInlineAsm(..) | ast::ExprBox(..) |
+ ast::ExprForLoop(..) => {
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
-
- ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop")
}
}
@@ -1113,7 +1112,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
}
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
- // @p1, ~p1
+ // @p1, ~p1, ref p1
let subcmt = self.cat_deref(pat, cmt, 0, false);
if_ok!(self.cat_pattern(subcmt, &**subpat, op));
}
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index e404ce8566375..7ed1209bdf750 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -365,8 +365,8 @@ pub fn find_reachable(tcx: &ty::ctxt,
// other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
- for &id in exported_items.iter() {
- reachable_context.worklist.push(id);
+ for id in exported_items.iter() {
+ reachable_context.worklist.push(*id);
}
for (_, item) in tcx.lang_items.items() {
match *item {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 822a43f2619dc..5f5a324857ab9 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -208,7 +208,9 @@ impl RegionMaps {
pub fn var_region(&self, id: ast::NodeId) -> ty::Region {
//! Returns the lifetime of the variable `id`.
- ty::ReScope(self.var_scope(id))
+ let scope = ty::ReScope(self.var_scope(id));
+ debug!("var_region({}) = {:?}", id, scope);
+ scope
}
pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId)
@@ -524,6 +526,14 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor,
visitor.region_maps.mark_as_terminating_scope(body.id);
}
+ ast::ExprForLoop(ref _pat, ref _head, ref body, _) => {
+ visitor.region_maps.mark_as_terminating_scope(body.id);
+
+ // The variable parent of everything inside (most importantly, the
+ // pattern) is the body.
+ new_cx.var_parent = Some(body.id);
+ }
+
ast::ExprMatch(..) => {
new_cx.var_parent = Some(expr.id);
}
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 0fb377838feb1..95c04ad6607d6 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5329,7 +5329,42 @@ impl<'a> Resolver<'a> {
})
}
- ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+ ExprForLoop(ref pattern, ref head, ref body, optional_label) => {
+ self.resolve_expr(&**head);
+
+ self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind));
+
+ self.resolve_pattern(&**pattern,
+ LocalIrrefutableMode,
+ &mut HashMap::new());
+
+ match optional_label {
+ None => {}
+ Some(label) => {
+ self.label_ribs
+ .borrow_mut()
+ .push(Rib::new(NormalRibKind));
+ let def_like = DlDef(DefLabel(expr.id));
+
+ {
+ let label_ribs = self.label_ribs.borrow();
+ let length = label_ribs.len();
+ let rib = label_ribs.get(length - 1);
+ let renamed = mtwt::resolve(label);
+ rib.bindings.borrow_mut().insert(renamed,
+ def_like);
+ }
+ }
+ }
+
+ self.resolve_block(&**body);
+
+ if optional_label.is_some() {
+ drop(self.label_ribs.borrow_mut().pop())
+ }
+
+ self.value_ribs.borrow_mut().pop();
+ }
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
let renamed = mtwt::resolve(label);
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 419fcffba3686..0b181d2cf367a 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1543,6 +1543,31 @@ pub fn store_arg<'a>(mut bcx: &'a Block<'a>,
}
}
+/// Generates code for the pattern binding in a `for` loop like
+/// `for in { ... }`.
+pub fn store_for_loop_binding<'a>(
+ bcx: &'a Block<'a>,
+ pat: Gc,
+ llvalue: ValueRef,
+ body_scope: cleanup::ScopeId)
+ -> &'a Block<'a> {
+ let _icx = push_ctxt("match::store_for_loop_binding");
+
+ if simple_identifier(&*pat).is_some() {
+ // Generate nicer LLVM for the common case of a `for` loop pattern
+ // like `for x in blahblah { ... }`.
+ let binding_type = node_id_type(bcx, pat.id);
+ bcx.fcx.lllocals.borrow_mut().insert(pat.id,
+ Datum::new(llvalue,
+ binding_type,
+ Lvalue));
+ return bcx
+ }
+
+ // General path. Copy out the values that are used in the pattern.
+ bind_irrefutable_pat(bcx, pat, llvalue, BindLocal, body_scope)
+}
+
fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
p_id: ast::NodeId,
ident: &ast::Ident,
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 845684bb037a9..d8a8cc1c561a9 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -12,16 +12,23 @@ use llvm::*;
use driver::config::FullDebugInfo;
use middle::def;
use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
+use middle::trans::_match;
+use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::cleanup::CleanupMethods;
use middle::trans::cleanup;
use middle::trans::common::*;
+use middle::trans::datum;
use middle::trans::debuginfo;
use middle::trans::expr;
+use middle::trans::meth;
+use middle::trans::type_::Type;
use middle::ty;
+use middle::typeck::MethodCall;
use util::ppaux::Repr;
+use util::ppaux;
use syntax::ast;
use syntax::ast::Ident;
@@ -237,6 +244,129 @@ pub fn trans_while<'a>(bcx: &'a Block<'a>,
return next_bcx_in;
}
+/// Translates a `for` loop.
+pub fn trans_for<'a>(
+ mut bcx: &'a Block<'a>,
+ loop_info: NodeInfo,
+ pat: Gc,
+ head: &ast::Expr,
+ body: &ast::Block)
+ -> &'a Block<'a> {
+ let _icx = push_ctxt("trans_for");
+
+ // bcx
+ // |
+ // loopback_bcx_in <-------+
+ // | |
+ // loopback_bcx_out |
+ // | | |
+ // | body_bcx_in |
+ // cleanup_blk | |
+ // | body_bcx_out --+
+ // next_bcx_in
+
+ // Codegen the head to create the iterator value.
+ let iterator_datum =
+ unpack_datum!(bcx, expr::trans_to_lvalue(bcx, head, "for_head"));
+ let iterator_type = node_id_type(bcx, head.id);
+ debug!("iterator type is {}, datum type is {}",
+ ppaux::ty_to_string(bcx.tcx(), iterator_type),
+ ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty));
+ let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty);
+
+ // Create our basic blocks and set up our loop cleanups.
+ let next_bcx_in = bcx.fcx.new_id_block("for_exit", loop_info.id);
+ let loopback_bcx_in = bcx.fcx.new_id_block("for_loopback", head.id);
+ let body_bcx_in = bcx.fcx.new_id_block("for_body", body.id);
+ bcx.fcx.push_loop_cleanup_scope(loop_info.id,
+ [next_bcx_in, loopback_bcx_in]);
+ Br(bcx, loopback_bcx_in.llbb);
+ let cleanup_llbb = bcx.fcx.normal_exit_block(loop_info.id,
+ cleanup::EXIT_BREAK);
+
+ // Set up the method call (to `.next()`).
+ let method_call = MethodCall::expr(loop_info.id);
+ let method_type = loopback_bcx_in.tcx()
+ .method_map
+ .borrow()
+ .get(&method_call)
+ .ty;
+ let method_type = monomorphize_type(loopback_bcx_in, method_type);
+ let method_result_type = ty::ty_fn_ret(method_type);
+ let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
+ let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope);
+
+ // Compile the method call (to `.next()`).
+ let mut loopback_bcx_out = loopback_bcx_in;
+ let option_datum =
+ unpack_datum!(loopback_bcx_out,
+ datum::lvalue_scratch_datum(loopback_bcx_out,
+ method_result_type,
+ "loop_option",
+ false,
+ option_cleanup_scope_id,
+ (),
+ |(), bcx, lloption| {
+ let Result {
+ bcx: bcx,
+ val: _
+ } = callee::trans_call_inner(bcx,
+ Some(loop_info),
+ method_type,
+ |bcx, arg_cleanup_scope| {
+ meth::trans_method_callee(
+ bcx,
+ method_call,
+ None,
+ arg_cleanup_scope)
+ },
+ callee::ArgVals([lliterator]),
+ Some(expr::SaveIn(lloption)));
+ bcx
+ }));
+
+ // Check the discriminant; if the `None` case, exit the loop.
+ let option_representation = adt::represent_type(loopback_bcx_out.ccx(),
+ method_result_type);
+ let i8_type = Type::i8(loopback_bcx_out.ccx());
+ let lldiscriminant = adt::trans_get_discr(loopback_bcx_out,
+ &*option_representation,
+ option_datum.val,
+ Some(i8_type));
+ let llzero = C_u8(loopback_bcx_out.ccx(), 0);
+ let llcondition = ICmp(loopback_bcx_out, IntNE, lldiscriminant, llzero);
+ CondBr(loopback_bcx_out, llcondition, body_bcx_in.llbb, cleanup_llbb);
+
+ // Now we're in the body. Unpack the `Option` value into the programmer-
+ // supplied pattern.
+ let llpayload = adt::trans_field_ptr(body_bcx_in,
+ &*option_representation,
+ option_datum.val,
+ 1,
+ 0);
+ let binding_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
+ let binding_cleanup_scope_id =
+ cleanup::CustomScope(binding_cleanup_scope);
+ let mut body_bcx_out =
+ _match::store_for_loop_binding(body_bcx_in,
+ pat,
+ llpayload,
+ binding_cleanup_scope_id);
+
+ // Codegen the body.
+ body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
+ body_bcx_out.fcx.pop_custom_cleanup_scope(binding_cleanup_scope);
+ body_bcx_out =
+ body_bcx_out.fcx
+ .pop_and_trans_custom_cleanup_scope(body_bcx_out,
+ option_cleanup_scope);
+ Br(body_bcx_out, loopback_bcx_in.llbb);
+
+ // Codegen cleanups and leave.
+ next_bcx_in.fcx.pop_loop_cleanup_scope(loop_info.id);
+ next_bcx_in
+}
+
pub fn trans_loop<'a>(bcx:&'a Block<'a>,
loop_id: ast::NodeId,
body: &ast::Block)
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 66722b2c4dbda..6fe3ee5d29b58 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -3582,9 +3582,24 @@ fn populate_scope_map(cx: &CrateContext,
})
}
- ast::ExprForLoop(_, _, _, _) => {
- cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
- Found unexpanded for-loop.");
+ ast::ExprForLoop(ref pattern, ref head, ref body, _) => {
+ walk_expr(cx, &**head, scope_stack, scope_map);
+
+ with_new_scope(cx,
+ exp.span,
+ scope_stack,
+ scope_map,
+ |cx, scope_stack, scope_map| {
+ scope_map.insert(exp.id,
+ scope_stack.last()
+ .unwrap()
+ .scope_metadata);
+ walk_pattern(cx,
+ *pattern,
+ scope_stack,
+ scope_map);
+ walk_block(cx, &**body, scope_stack, scope_map);
+ })
}
ast::ExprMac(_) => {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 4cb1edbe1e77f..9d970b1a393c5 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -665,6 +665,13 @@ fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
ast::ExprWhile(ref cond, ref body) => {
controlflow::trans_while(bcx, expr.id, &**cond, &**body)
}
+ ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+ controlflow::trans_for(bcx,
+ expr_info(expr),
+ *pat,
+ &**head,
+ &**body)
+ }
ast::ExprLoop(ref body, _) => {
controlflow::trans_loop(bcx, expr.id, &**body)
}
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4dfd15fe13619..8f60fe340e4d6 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3090,7 +3090,7 @@ pub enum ExprKind {
pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
if tcx.method_map.borrow().contains_key(&typeck::MethodCall::expr(expr.id)) {
// Overloaded operations are generally calls, and hence they are
- // generated via DPS, but there are two exceptions:
+ // generated via DPS, but there are a few exceptions:
return match expr.node {
// `a += b` has a unit result.
ast::ExprAssignOp(..) => RvalueStmtExpr,
@@ -3101,6 +3101,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
// the index method invoked for `a[i]` always yields an `&T`
ast::ExprIndex(..) => LvalueExpr,
+ // `for` loops are statements
+ ast::ExprForLoop(..) => RvalueStmtExpr,
+
// in the general case, result could be any type, use DPS
_ => RvalueDpsExpr
};
@@ -3209,12 +3212,11 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprLoop(..) |
ast::ExprAssign(..) |
ast::ExprInlineAsm(..) |
- ast::ExprAssignOp(..) => {
+ ast::ExprAssignOp(..) |
+ ast::ExprForLoop(..) => {
RvalueStmtExpr
}
- ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
-
ast::ExprLit(_) | // Note: LitStr is carved out above
ast::ExprUnary(..) |
ast::ExprAddrOf(..) |
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index be01643e22a58..3f54677c08b24 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -21,6 +21,7 @@ use middle::typeck::check::{instantiate_path, lookup_def};
use middle::typeck::check::{structure_of, valid_range_bounds};
use middle::typeck::infer;
use middle::typeck::require_same_types;
+use util::ppaux;
use std::collections::{HashMap, HashSet};
use std::gc::Gc;
@@ -484,7 +485,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
}
fcx.write_ty(pat.id, typ);
- debug!("(checking match) writing type for pat id {}", pat.id);
+ debug!("(checking match) writing type {} (expected {}) for pat id {}",
+ ppaux::ty_to_string(tcx, typ),
+ ppaux::ty_to_string(tcx, expected),
+ pat.id);
match sub {
Some(ref p) => check_pat(pcx, &**p, expected),
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 747ba26f5909f..fd6b3a20a1936 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -79,6 +79,7 @@ type parameter).
use middle::const_eval;
use middle::def;
+use middle::lang_items::IteratorItem;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::subst;
@@ -1708,6 +1709,80 @@ fn try_overloaded_index(fcx: &FnCtxt,
}
}
+/// Given the head of a `for` expression, looks up the `next` method in the
+/// `Iterator` trait. Fails if the expression does not implement `next`.
+///
+/// The return type of this function represents the concrete element type
+/// `A` in the type `Iterator` that the method returns.
+fn lookup_method_for_for_loop(fcx: &FnCtxt,
+ iterator_expr: Gc,
+ loop_id: ast::NodeId)
+ -> ty::t {
+ let trait_did = match fcx.tcx().lang_items.require(IteratorItem) {
+ Ok(trait_did) => trait_did,
+ Err(ref err_string) => {
+ fcx.tcx().sess.span_err(iterator_expr.span,
+ err_string.as_slice());
+ return ty::mk_err()
+ }
+ };
+
+ let method = method::lookup_in_trait(fcx,
+ iterator_expr.span,
+ Some(&*iterator_expr),
+ token::intern("next"),
+ trait_did,
+ fcx.expr_ty(&*iterator_expr),
+ [],
+ DontAutoderefReceiver,
+ IgnoreStaticMethods);
+
+ // Regardless of whether the lookup succeeds, check the method arguments
+ // so that we have *some* type for each argument.
+ let method_type = match method {
+ Some(ref method) => method.ty,
+ None => {
+ fcx.tcx().sess.span_err(iterator_expr.span,
+ "`for` loop expression does not \
+ implement the `Iterator` trait");
+ ty::mk_err()
+ }
+ };
+ let return_type = check_method_argument_types(fcx,
+ iterator_expr.span,
+ method_type,
+ &*iterator_expr,
+ [iterator_expr],
+ DontDerefArgs,
+ DontTupleArguments);
+
+ match method {
+ Some(method) => {
+ fcx.inh.method_map.borrow_mut().insert(MethodCall::expr(loop_id),
+ method);
+
+ // We expect the return type to be `Option` or something like it.
+ // Grab the first parameter of its type substitution.
+ let return_type = structurally_resolved_type(fcx,
+ iterator_expr.span,
+ return_type);
+ match ty::get(return_type).sty {
+ ty::ty_enum(_, ref substs)
+ if !substs.types.is_empty_in(subst::TypeSpace) => {
+ *substs.types.get(subst::TypeSpace, 0)
+ }
+ _ => {
+ fcx.tcx().sess.span_err(iterator_expr.span,
+ "`next` method of the `Iterator` \
+ trait has an unexpected type");
+ ty::mk_err()
+ }
+ }
+ }
+ None => ty::mk_err()
+ }
+}
+
fn check_method_argument_types(fcx: &FnCtxt,
sp: Span,
method_fn_ty: ty::t,
@@ -3273,8 +3348,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.write_nil(id);
}
}
- ast::ExprForLoop(..) =>
- fail!("non-desugared expr_for_loop"),
+ ast::ExprForLoop(ref pat, ref head, ref block, _) => {
+ check_expr(fcx, &**head);
+ let typ = lookup_method_for_for_loop(fcx, *head, expr.id);
+ vtable::early_resolve_expr(expr, fcx, true);
+
+ let pcx = pat_ctxt {
+ fcx: fcx,
+ map: pat_id_map(&tcx.def_map, &**pat),
+ };
+ _match::check_pat(&pcx, &**pat, typ);
+
+ check_block_no_value(fcx, &**block);
+ fcx.write_nil(id);
+ }
ast::ExprLoop(ref body, _) => {
check_block_no_value(fcx, &**body);
if !may_break(tcx, expr.id, body.clone()) {
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 22d52d0b7d2a0..d0431de81a359 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -609,6 +609,22 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
rcx.set_repeating_scope(repeating_scope);
}
+ ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+ constrain_bindings_in_pat(&**pat, rcx);
+
+ {
+ let mc = mc::MemCategorizationContext::new(rcx);
+ let head_cmt = ignore_err!(mc.cat_expr(&**head));
+ link_pattern(rcx, mc, head_cmt, &**pat);
+ }
+
+ rcx.visit_expr(&**head, ());
+
+ let repeating_scope = rcx.set_repeating_scope(body.id);
+ rcx.visit_block(&**body, ());
+ rcx.set_repeating_scope(repeating_scope);
+ }
+
_ => {
visit::walk_expr(rcx, expr, ());
}
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index c176054b3aed0..565b88b74939b 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -756,7 +756,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
ast::ExprUnary(_, _) |
ast::ExprAssignOp(_, _, _) |
ast::ExprIndex(_, _) |
- ast::ExprMethodCall(_, _, _) => {
+ ast::ExprMethodCall(_, _, _) |
+ ast::ExprForLoop(..) => {
match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) {
Some(method) => {
debug!("vtable resolution on parameter bounds for method call {}",
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index fe140cf2c97c2..dc0f2a9ffff73 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -419,8 +419,8 @@ impl<'a> CoherenceChecker<'a> {
}
fn check_implementation_coherence(&self) {
- for &trait_id in self.crate_context.tcx.trait_impls.borrow().keys() {
- self.check_implementation_coherence_of(trait_id);
+ for trait_id in self.crate_context.tcx.trait_impls.borrow().keys() {
+ self.check_implementation_coherence_of(*trait_id);
}
}
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 3dd056969d665..9c9942d2628eb 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -66,7 +66,7 @@ impl<'a> Visitor<()> for LoopQueryVisitor<'a> {
match e.node {
// Skip inner loops, since a break in the inner loop isn't a
// break inside the outer loop
- ast::ExprLoop(..) | ast::ExprWhile(..) => {}
+ ast::ExprLoop(..) | ast::ExprWhile(..) | ast::ExprForLoop(..) => {}
_ => visit::walk_expr(self, e, ())
}
}
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index cb9519b1eb815..94dea6cb540e3 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -252,6 +252,7 @@ mod svh_visitor {
SawExprStruct,
SawExprRepeat,
SawExprParen,
+ SawExprForLoop,
}
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
@@ -287,9 +288,9 @@ mod svh_visitor {
ExprStruct(..) => SawExprStruct,
ExprRepeat(..) => SawExprRepeat,
ExprParen(..) => SawExprParen,
+ ExprForLoop(..) => SawExprForLoop,
// just syntactic artifacts, expanded away by time of SVH.
- ExprForLoop(..) => unreachable!(),
ExprMac(..) => unreachable!(),
}
}
diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs
index 5ca7e417af695..f580dfd80f0ce 100644
--- a/src/libstd/io/tempfile.rs
+++ b/src/libstd/io/tempfile.rs
@@ -12,7 +12,7 @@
use io::{fs, IoResult};
use io;
-use iter::{Iterator, range};
+use iter::range;
use libc;
use ops::Drop;
use option::{Option, None, Some};
@@ -21,6 +21,9 @@ use path::{Path, GenericPath};
use result::{Ok, Err};
use sync::atomics;
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+
/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
pub struct TempDir {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 123dcf366f440..f82796b480a4e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -62,108 +62,18 @@ fn expand_expr(e: Gc, fld: &mut MacroExpander) -> Gc {
}
}
- // Desugar expr_for_loop
- // From: `[':] for in `
- // FIXME #6993: change type of opt_ident to Option
- ast::ExprForLoop(src_pat, src_expr, src_loop_block, opt_ident) => {
-
- let span = e.span;
-
- // to:
- //
- // match &mut {
- // i => {
- // [':] loop {
- // match i.next() {
- // None => break ['],
- // Some(mut value) => {
- // let = value;
- //
- // }
- // }
- // }
- // }
- // }
- //
- // (The use of the `let` is to give better error messages
- // when the pattern is refutable.)
-
- let local_ident = token::gensym_ident("i");
- let next_ident = fld.cx.ident_of("next");
- let none_ident = fld.cx.ident_of("None");
-
- let local_path = fld.cx.path_ident(span, local_ident);
- let some_path = fld.cx.path_ident(span, fld.cx.ident_of("Some"));
-
- // `None => break ['],`
- let none_arm = {
- let break_expr = fld.cx.expr(span, ast::ExprBreak(opt_ident));
- let none_pat = fld.cx.pat_ident(span, none_ident);
- fld.cx.arm(span, vec!(none_pat), break_expr)
- };
-
- // let = value;
- // use underscore to suppress lint error:
- let value_ident = token::gensym_ident("_value");
- // this is careful to use src_pat.span so that error
- // messages point exact at that.
- let local = box(GC) ast::Local {
- ty: fld.cx.ty_infer(src_pat.span),
- pat: src_pat,
- init: Some(fld.cx.expr_ident(src_pat.span, value_ident)),
- id: ast::DUMMY_NODE_ID,
- span: src_pat.span,
- source: ast::LocalFor
- };
- let local = codemap::respan(src_pat.span, ast::DeclLocal(local));
- let local = box(GC) codemap::respan(span, ast::StmtDecl(box(GC) local,
- ast::DUMMY_NODE_ID));
-
- // { let ...; }
- let block = fld.cx.block(span, vec![local],
- Some(fld.cx.expr_block(src_loop_block)));
-
- // `Some(mut value) => { ... }`
- // Note the _'s in the name will stop any unused mutability warnings.
- let value_pat = fld.cx.pat_ident_binding_mode(span, value_ident,
- ast::BindByValue(ast::MutMutable));
- let some_arm =
- fld.cx.arm(span,
- vec!(fld.cx.pat_enum(span, some_path, vec!(value_pat))),
- fld.cx.expr_block(block));
-
- // `match i.next() { ... }`
- let match_expr = {
- let next_call_expr =
- fld.cx.expr_method_call(span,
- fld.cx.expr_path(local_path),
- next_ident,
- Vec::new());
-
- fld.cx.expr_match(span, next_call_expr, vec!(none_arm, some_arm))
- };
-
- // ['ident:] loop { ... }
- let loop_expr = fld.cx.expr(span,
- ast::ExprLoop(fld.cx.block_expr(match_expr),
- opt_ident));
-
- // `i => loop { ... }`
-
- // `match &mut { i => loop { ... } }`
- let discrim = fld.cx.expr_mut_addr_of(span, src_expr);
- let i_pattern = fld.cx.pat_ident(span, local_ident);
- let arm = fld.cx.arm(span, vec!(i_pattern), loop_expr);
- // why these clone()'s everywhere? I guess I'll follow the pattern....
- let match_expr = fld.cx.expr_match(span, discrim, vec!(arm));
- fld.fold_expr(match_expr).clone()
- }
-
ast::ExprLoop(loop_block, opt_ident) => {
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))
}
+ ast::ExprForLoop(pat, head, body, opt_ident) => {
+ let pat = fld.fold_pat(pat);
+ let head = fld.fold_expr(head);
+ let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
+ fld.cx.expr(e.span, ast::ExprForLoop(pat, head, body, opt_ident))
+ }
+
ast::ExprFnBlock(fn_decl, block) => {
let (rewritten_fn_decl, rewritten_block)
= expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld);
diff --git a/src/libunicode/decompose.rs b/src/libunicode/decompose.rs
index 832b65d473996..25e06bf7c13f0 100644
--- a/src/libunicode/decompose.rs
+++ b/src/libunicode/decompose.rs
@@ -39,6 +39,7 @@ pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
fn d(c: char, i: |char|, k: bool) {
+ #[cfg(stage0)]
use core::iter::Iterator;
// 7-bit ASCII never decomposes
diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs
index e13c53407e457..615dd1d69d501 100644
--- a/src/test/bench/shootout-meteor.rs
+++ b/src/test/bench/shootout-meteor.rs
@@ -297,10 +297,10 @@ fn search(
// for every unused piece
for id in range(0u, 10).filter(|id| board & (1 << (id + 50)) == 0) {
// for each mask that fits on the board
- for &m in masks_at.get(id).iter().filter(|&m| board & *m == 0) {
+ for m in masks_at.get(id).iter().filter(|&m| board & *m == 0) {
// This check is too costy.
//if is_board_unfeasible(board | m, masks) {continue;}
- search(masks, board | m, i + 1, Cons(m, &cur), data);
+ search(masks, board | *m, i + 1, Cons(*m, &cur), data);
}
}
}
@@ -311,9 +311,10 @@ fn par_search(masks: Vec>>) -> Data {
// launching the search in parallel on every masks at minimum
// coordinate (0,0)
- for &m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) {
+ for m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) {
let masks = masks.clone();
let tx = tx.clone();
+ let m = *m;
spawn(proc() {
let mut data = Data::new();
search(&*masks, m, 1, Cons(m, &Nil), &mut data);
diff --git a/src/test/compile-fail/for-loop-bogosity.rs b/src/test/compile-fail/for-loop-bogosity.rs
new file mode 100644
index 0000000000000..ba268cf3d6479
--- /dev/null
+++ b/src/test/compile-fail/for-loop-bogosity.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 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 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct MyStruct {
+ x: int,
+ y: int,
+}
+
+impl MyStruct {
+ fn next(&mut self) -> Option {
+ Some(self.x)
+ }
+}
+
+pub fn main() {
+ let mut bogus = MyStruct {
+ x: 1,
+ y: 2,
+ };
+ for x in bogus { //~ ERROR does not implement the `Iterator` trait
+ drop(x);
+ }
+}
+
diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs
index 61e1e92ff9420..300831b100773 100644
--- a/src/test/compile-fail/issue-15167.rs
+++ b/src/test/compile-fail/issue-15167.rs
@@ -9,13 +9,18 @@
// except according to those terms.
// macro f should not be able to inject a reference to 'n'.
+//
+// Ignored because `for` loops are not hygienic yet; they will require special
+// handling since they introduce a new pattern binding position.
+
+// ignore-test
#![feature(macro_rules)]
macro_rules! f(() => (n))
fn main() -> (){
- for n in range(0, 1) {
+ for n in range(0i, 1) {
println!("{}", f!()); //~ ERROR unresolved name `n`
}
}
diff --git a/src/test/compile-fail/vec-mut-iter-borrow.rs b/src/test/compile-fail/vec-mut-iter-borrow.rs
index 9a179f434c275..9060ed7495ee5 100644
--- a/src/test/compile-fail/vec-mut-iter-borrow.rs
+++ b/src/test/compile-fail/vec-mut-iter-borrow.rs
@@ -9,9 +9,9 @@
// except according to those terms.
fn main() {
- let mut xs = vec!(1i, 2, 3, 4);
+ let mut xs: Vec = vec!();
for x in xs.mut_iter() {
- xs.push(1) //~ ERROR cannot borrow `xs`
+ xs.push(1i) //~ ERROR cannot borrow `xs`
}
}
diff --git a/src/test/debuginfo/lexical-scope-in-for-loop.rs b/src/test/debuginfo/lexical-scope-in-for-loop.rs
index 13cae3252d804..74d5462431822 100644
--- a/src/test/debuginfo/lexical-scope-in-for-loop.rs
+++ b/src/test/debuginfo/lexical-scope-in-for-loop.rs
@@ -9,6 +9,7 @@
// except according to those terms.
// ignore-android: FIXME(#10381)
+// ignore-test: Not sure what is going on here --pcwalton
// compile-flags:-g
diff --git a/src/test/run-pass/for-loop-goofiness.rs b/src/test/run-pass/for-loop-goofiness.rs
new file mode 100644
index 0000000000000..73f4cdd252e6f
--- /dev/null
+++ b/src/test/run-pass/for-loop-goofiness.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 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 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum BogusOption {
+ None,
+ Some(T),
+}
+
+type Iterator = int;
+
+pub fn main() {
+ let x = [ 3i, 3, 3 ];
+ for i in x.iter() {
+ assert_eq!(*i, 3);
+ }
+}
+