@@ -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<Expr>),
/// 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<Gc<Expr>>,
kind: LoopKind,
body: &Block,
succ: LiveNode)
-> LiveNode {
@@ -1309,26 +1339,35 @@ 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)
});

// 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")
}
}

@@ -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));
}
@@ -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 {
@@ -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);
}
@@ -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);
@@ -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 <pat> in <expr> { ... }`.
pub fn store_for_loop_binding<'a>(
bcx: &'a Block<'a>,
pat: Gc<ast::Pat>,
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,
@@ -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<ast::Pat>,
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)
@@ -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(_) => {
@@ -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)
}
@@ -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(..) |
@@ -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),
@@ -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<A>` that the method returns.
fn lookup_method_for_for_loop(fcx: &FnCtxt,
iterator_expr: Gc<ast::Expr>,
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()) {
@@ -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, ());
}
@@ -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 {}",
@@ -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);
}
}

@@ -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, ())
}
}
@@ -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!(),
}
}
@@ -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 {
@@ -62,108 +62,18 @@ fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
}
}

// Desugar expr_for_loop
// From: `['<ident>:] for <src_pat> in <src_expr> <src_loop_block>`
// FIXME #6993: change type of opt_ident to Option<Name>
ast::ExprForLoop(src_pat, src_expr, src_loop_block, opt_ident) => {

let span = e.span;

// to:
//
// match &mut <src_expr> {
// i => {
// ['<ident>:] loop {
// match i.next() {
// None => break ['<ident>],
// Some(mut value) => {
// let <src_pat> = value;
// <src_loop_block>
// }
// }
// }
// }
// }
//
// (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 ['<ident>],`
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 <src_pat> = 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 ...; <src_loop_block> }
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 <src_expr> { 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);
@@ -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
@@ -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<Vec<Vec<u64>>>) -> 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);
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct MyStruct {
x: int,
y: int,
}

impl MyStruct {
fn next(&mut self) -> Option<int> {
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);
}
}

@@ -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`
}
}
@@ -9,9 +9,9 @@
// except according to those terms.

fn main() {
let mut xs = vec!(1i, 2, 3, 4);
let mut xs: Vec<int> = vec!();

for x in xs.mut_iter() {
xs.push(1) //~ ERROR cannot borrow `xs`
xs.push(1i) //~ ERROR cannot borrow `xs`
}
}
@@ -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

@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum BogusOption<T> {
None,
Some(T),
}

type Iterator = int;

pub fn main() {
let x = [ 3i, 3, 3 ];
for i in x.iter() {
assert_eq!(*i, 3);
}
}