From a8840d70a517d29183f2c6e4d9da4920541700d7 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 29 Jul 2013 15:15:33 -0700 Subject: [PATCH 1/6] syntax: add 'in' keyword --- src/libsyntax/parse/token.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 52b6d4459bf..66735a3cef0 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -474,6 +474,7 @@ fn mk_fresh_ident_interner() -> @ident_interner { "while", // 64 "be", // 65 + "in", // 66 ]; @ident_interner { @@ -572,6 +573,7 @@ pub mod keywords { For, If, Impl, + In, Let, __Log, Loop, @@ -614,6 +616,7 @@ pub mod keywords { For => ident { name: 42, ctxt: 0 }, If => ident { name: 43, ctxt: 0 }, Impl => ident { name: 44, ctxt: 0 }, + In => ident { name: 66, ctxt: 0 }, Let => ident { name: 45, ctxt: 0 }, __Log => ident { name: 46, ctxt: 0 }, Loop => ident { name: 47, ctxt: 0 }, From 9a2d183d6ae83a0119f5cce1f95e3770ddf5d689 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 29 Jul 2013 15:20:40 -0700 Subject: [PATCH 2/6] syntax: add temporary 'foreach' keyword. --- src/libsyntax/parse/token.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 66735a3cef0..a9f0db32d3e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -475,6 +475,7 @@ fn mk_fresh_ident_interner() -> @ident_interner { "be", // 65 "in", // 66 + "foreach", // 67 ]; @ident_interner { @@ -571,6 +572,7 @@ pub mod keywords { False, Fn, For, + ForEach, If, Impl, In, @@ -614,6 +616,7 @@ pub mod keywords { False => ident { name: 40, ctxt: 0 }, Fn => ident { name: 41, ctxt: 0 }, For => ident { name: 42, ctxt: 0 }, + ForEach => ident { name: 67, ctxt: 0 }, If => ident { name: 43, ctxt: 0 }, Impl => ident { name: 44, ctxt: 0 }, In => ident { name: 66, ctxt: 0 }, From c29e9fb60b46a66bd55643981edbec881c5def82 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 29 Jul 2013 17:25:00 -0700 Subject: [PATCH 3/6] syntax: implement foreach .. in .. { .. } via desugaring. --- src/librustc/middle/cfg/construct.rs | 2 + src/librustc/middle/dataflow.rs | 2 + src/librustc/middle/liveness.rs | 4 + src/librustc/middle/mem_categorization.rs | 2 + src/librustc/middle/moves.rs | 2 + src/librustc/middle/resolve.rs | 2 + src/librustc/middle/trans/type_use.rs | 4 +- src/librustc/middle/ty.rs | 2 + src/librustc/middle/typeck/check/mod.rs | 2 + src/librustc/middle/typeck/check/regionck.rs | 1 + src/libsyntax/ast.rs | 1 + src/libsyntax/ext/expand.rs | 156 ++++++++++++++++++- src/libsyntax/fold.rs | 5 + src/libsyntax/parse/classify.rs | 1 + src/libsyntax/parse/parser.rs | 19 ++- src/libsyntax/print/pprust.rs | 8 + src/libsyntax/visit.rs | 5 + 17 files changed, 215 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 97fc49b23d0..a262aa5445e 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -239,6 +239,8 @@ impl CFGBuilder { expr_exit } + ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + ast::expr_loop(ref body, _) => { // // [pred] diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 1da3b31c936..8bc2c145eb3 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -583,6 +583,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { copy_bits(new_loop_scope.break_bits, in_out); } + ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + ast::expr_loop(ref blk, _) => { // // (expr) <--+ diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 385f23a73d6..e595e7c0694 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -503,6 +503,7 @@ fn visit_expr(expr: @expr, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) { this.add_live_node_for_node(expr.id, ExprNode(expr.span)); visit::visit_expr(expr, (this, vt)); } + expr_for_loop(*) => fail!("non-desugared expr_for_loop"), expr_binary(_, op, _, _) if ast_util::lazy_binop(op) => { this.add_live_node_for_node(expr.id, ExprNode(expr.span)); visit::visit_expr(expr, (this, vt)); @@ -1057,6 +1058,8 @@ impl Liveness { self.propagate_through_loop(expr, Some(cond), blk, succ) } + expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + // Note that labels have been resolved, so we don't need to look // at the label ident expr_loop(ref blk, _) => { @@ -1487,6 +1490,7 @@ fn check_expr(expr: @expr, (this, vt): (@Liveness, vt<@Liveness>)) { expr_paren(*) | expr_fn_block(*) | expr_path(*) | expr_self(*) => { visit::visit_expr(expr, (this, vt)); } + expr_for_loop(*) => fail!("non-desugared expr_for_loop") } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 1c5f3b9bfdf..a875381cc43 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -435,6 +435,8 @@ impl mem_categorization_ctxt { ast::expr_inline_asm(*) => { return self.cat_rvalue_node(expr, expr_ty); } + + ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop") } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 1cf0162d784..eaa7970cfe4 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -487,6 +487,8 @@ impl VisitContext { self.consume_block(blk, visitor); } + expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + expr_unary(_, _, lhs) => { if !self.use_overloaded_operator( expr, lhs, [], visitor) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 4f7a2f67b3c..ba11476204a 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -5016,6 +5016,8 @@ impl Resolver { } } + expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + expr_break(Some(label)) | expr_again(Some(label)) => { match self.search_ribs(self.label_ribs, label, expr.span, DontAllowCapturingSelf) { diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 3df91844dda..a599c7c798e 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -401,7 +401,9 @@ pub fn mark_for_expr(cx: &Context, e: &expr) { expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) | expr_break(_) | expr_again(_) | expr_unary(*) | expr_lit(_) | expr_mac(_) | expr_addr_of(*) | expr_ret(_) | expr_loop(*) | - expr_loop_body(_) | expr_do_body(_) => () + expr_loop_body(_) | expr_do_body(_) => (), + + expr_for_loop(*) => fail!("non-desugared expr_for_loop") } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 050b6d3fdde..3ec66aff176 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3240,6 +3240,8 @@ pub fn expr_kind(tcx: ctxt, RvalueStmtExpr } + ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"), + ast::expr_lit(_) | // Note: lit_str is carved out above ast::expr_unary(*) | ast::expr_addr_of(*) | diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 97469937340..4a3f72a2276 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2559,6 +2559,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_nil(id); } } + ast::expr_for_loop(*) => + fail!("non-desugared expr_for_loop"), ast::expr_loop(ref body, _) => { check_block_no_value(fcx, (body)); if !may_break(tcx, expr.id, body) { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 1f4c37a783f..422f59c14ea 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1041,6 +1041,7 @@ pub mod guarantor { rcx.fcx.tcx(), rcx.fcx.inh.method_map, expr)); None } + ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 97e69cd6918..d6bee4fe19f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -465,6 +465,7 @@ pub enum expr_ { expr_cast(@expr, Ty), expr_if(@expr, Block, Option<@expr>), expr_while(@expr, Block), + expr_for_loop(@pat, @expr, Block), /* Conditionless loop (can be exited with break, cont, or ret) Same semantics as while(true) { body }, but typestate knows that the (implicit) condition is always true. */ diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index af05f726860..72bbc4a96c5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -16,11 +16,12 @@ use ast_util::{new_rename, new_mark, resolve}; use attr; use attr::AttrMetaMethods; use codemap; -use codemap::{span, ExpnInfo, NameAndSpan}; +use codemap::{span, spanned, ExpnInfo, NameAndSpan}; use ext::base::*; use fold::*; use parse; use parse::{parse_item_from_source_str}; +use parse::token; use parse::token::{ident_to_str, intern}; use visit; use visit::Visitor; @@ -99,6 +100,159 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, } } } + + // Desugar expr_for_loop + // From: `foreach in ` + ast::expr_for_loop(src_pat, src_expr, ref src_loop_block) => { + let src_pat = src_pat.clone(); + let src_expr = src_expr.clone(); + + // Expand any interior macros etc. + // NB: we don't fold pats yet. Curious. + let src_expr = fld.fold_expr(src_expr).clone(); + let src_loop_block = fld.fold_block(src_loop_block).clone(); + + let span = s; + let lo = s.lo; + let hi = s.hi; + + pub fn mk_expr(cx: @ExtCtxt, span: span, + node: expr_) -> @ast::expr { + @ast::expr { + id: cx.next_id(), + node: node, + span: span, + } + } + + fn mk_block(cx: @ExtCtxt, + stmts: &[@ast::stmt], + expr: Option<@ast::expr>, + span: span) -> ast::Block { + ast::Block { + view_items: ~[], + stmts: stmts.to_owned(), + expr: expr, + id: cx.next_id(), + rules: ast::DefaultBlock, + span: span, + } + } + + fn mk_simple_path(ident: ast::ident, span: span) -> ast::Path { + ast::Path { + span: span, + global: false, + idents: ~[ident], + rp: None, + types: ~[] + } + } + + // to: + // + // { + // let _i = &mut ; + // loop { + // match i.next() { + // None => break, + // Some() => + // } + // } + // } + + let local_ident = token::gensym_ident("i"); + let some_ident = token::str_to_ident("Some"); + let none_ident = token::str_to_ident("None"); + let next_ident = token::str_to_ident("next"); + + let local_path_1 = mk_simple_path(local_ident, span); + let local_path_2 = mk_simple_path(local_ident, span); + let some_path = mk_simple_path(some_ident, span); + let none_path = mk_simple_path(none_ident, span); + + // `let i = &mut ` + let iter_decl_stmt = { + let ty = ast::Ty { + id: cx.next_id(), + node: ast::ty_infer, + span: span + }; + let local = @ast::Local { + is_mutbl: false, + ty: ty, + pat: @ast::pat { + id: cx.next_id(), + node: ast::pat_ident(ast::bind_infer, local_path_1, None), + span: src_expr.span + }, + init: Some(mk_expr(cx, src_expr.span, + ast::expr_addr_of(ast::m_mutbl, src_expr))), + id: cx.next_id(), + span: src_expr.span, + }; + let e = @spanned(src_expr.span.lo, + src_expr.span.hi, + ast::decl_local(local)); + @spanned(lo, hi, ast::stmt_decl(e, cx.next_id())) + }; + + // `None => break;` + let none_arm = { + let break_expr = mk_expr(cx, span, ast::expr_break(None)); + let break_stmt = @spanned(lo, hi, ast::stmt_expr(break_expr, cx.next_id())); + let none_block = mk_block(cx, [break_stmt], None, span); + let none_pat = @ast::pat { + id: cx.next_id(), + node: ast::pat_ident(ast::bind_infer, none_path, None), + span: span + }; + ast::arm { + pats: ~[none_pat], + guard: None, + body: none_block + } + }; + + // `Some() => ` + let some_arm = { + let pat = @ast::pat { + id: cx.next_id(), + node: ast::pat_enum(some_path, Some(~[src_pat])), + span: src_pat.span + }; + ast::arm { + pats: ~[pat], + guard: None, + body: src_loop_block + } + }; + + // `match i.next() { ... }` + let match_stmt = { + let local_expr = mk_expr(cx, span, ast::expr_path(local_path_2)); + let next_call_expr = mk_expr(cx, span, + ast::expr_method_call(cx.next_id(), + local_expr, next_ident, + ~[], ~[], ast::NoSugar)); + let match_expr = mk_expr(cx, span, ast::expr_match(next_call_expr, + ~[none_arm, some_arm])); + @spanned(lo, hi, ast::stmt_expr(match_expr, cx.next_id())) + }; + + // `loop { ... }` + let loop_block = { + let loop_body_block = mk_block(cx, [match_stmt], None, span); + let loop_body_expr = mk_expr(cx, span, ast::expr_loop(loop_body_block, None)); + let loop_body_stmt = @spanned(lo, hi, ast::stmt_expr(loop_body_expr, cx.next_id())); + mk_block(cx, [iter_decl_stmt, + loop_body_stmt], + None, span) + }; + + (ast::expr_block(loop_block), span) + } + _ => orig(e, s, fld) } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 51475528174..3016ee660dc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -559,6 +559,11 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_while(cond, ref body) => { expr_while(fld.fold_expr(cond), fld.fold_block(body)) } + expr_for_loop(pat, iter, ref body) => { + expr_for_loop(fld.fold_pat(pat), + fld.fold_expr(iter), + fld.fold_block(body)) + } expr_loop(ref body, opt_ident) => { expr_loop( fld.fold_block(body), diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index c7c556c9728..0bf87f10597 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool { | ast::expr_block(_) | ast::expr_while(*) | ast::expr_loop(*) + | ast::expr_for_loop(*) | ast::expr_call(_, _, ast::DoSugar) | ast::expr_call(_, _, ast::ForSugar) | ast::expr_method_call(_, _, _, _, _, ast::DoSugar) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 61dc6f47549..6ff4b91ec97 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -29,7 +29,7 @@ use ast::{expr_method_call, expr_paren, expr_path, expr_repeat}; use ast::{expr_ret, expr_self, expr_struct, expr_tup, expr_unary}; use ast::{expr_vec, expr_vstore, expr_vstore_mut_box}; use ast::{expr_vstore_slice, expr_vstore_box}; -use ast::{expr_vstore_mut_slice, expr_while, extern_fn, Field, fn_decl}; +use ast::{expr_vstore_mut_slice, expr_while, expr_for_loop, extern_fn, Field, fn_decl}; use ast::{expr_vstore_uniq, Onceness, Once, Many}; use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod}; use ast::{ident, impure_fn, inherited, item, item_, item_static}; @@ -1622,6 +1622,8 @@ impl Parser { hi = self.span.hi; } else if self.eat_keyword(keywords::If) { return self.parse_if_expr(); + } else if self.eat_keyword(keywords::ForEach) { + return self.parse_for_expr(); } else if self.eat_keyword(keywords::For) { return self.parse_sugary_call_expr(lo, ~"for", ForSugar, expr_loop_body); @@ -2323,6 +2325,21 @@ impl Parser { } } + // parse a 'foreach' .. 'in' expression ('foreach' token already eaten) + pub fn parse_for_expr(&self) -> @expr { + // Parse: `foreach in ` + + let lo = self.last_span.lo; + let pat = self.parse_pat(); + self.expect_keyword(keywords::In); + let expr = self.parse_expr(); + let loop_block = self.parse_block(); + let hi = self.span.hi; + + self.mk_expr(lo, hi, expr_for_loop(pat, expr, loop_block)) + } + + // parse a 'for' or 'do'. // the 'for' and 'do' expressions parse as calls, but look like // function calls followed by a closure expression. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7083d6655f1..a0e5192ab3a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1228,6 +1228,14 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { space(s.s); print_block(s, blk); } + ast::expr_for_loop(pat, iter, ref blk) => { + head(s, "foreach"); + print_pat(s, pat); + word_space(s, "in"); + print_expr(s, iter); + space(s.s); + print_block(s, blk); + } ast::expr_loop(ref blk, opt_ident) => { for opt_ident.iter().advance |ident| { word(s.s, "'"); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1d264bcc20e..990aaa99b78 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -512,6 +512,11 @@ pub fn visit_expr(ex: @expr, (e, v): (E, vt)) { (v.visit_expr)(x, (e.clone(), v)); (v.visit_block)(b, (e.clone(), v)); } + expr_for_loop(pat, iter, ref b) => { + (v.visit_pat)(pat, (e.clone(), v)); + (v.visit_expr)(iter, (e.clone(), v)); + (v.visit_block)(b, (e.clone(), v)); + } expr_loop(ref b, _) => (v.visit_block)(b, (e.clone(), v)), expr_match(x, ref arms) => { (v.visit_expr)(x, (e.clone(), v)); From e5b0f1d132173dcd43d2896645ee27fc0cab86a2 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 30 Jul 2013 16:04:04 -0700 Subject: [PATCH 4/6] rustc: fix a pp bug. --- src/libsyntax/print/pprust.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a0e5192ab3a..4fab3c5779e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1231,6 +1231,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { ast::expr_for_loop(pat, iter, ref blk) => { head(s, "foreach"); print_pat(s, pat); + space(s.s); word_space(s, "in"); print_expr(s, iter); space(s.s); From 62b6fa094378340574bf40543cdcd477f4dd1169 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 30 Jul 2013 16:05:00 -0700 Subject: [PATCH 5/6] rustc: silence unused-var warning. --- src/librustc/middle/trans/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 7d7f78379a4..42221cb08b6 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2266,7 +2266,7 @@ pub fn register_fn_fuller(ccx: @mut CrateContext, sp: span, sym: ~str, node_id: ast::NodeId, - node_type: ty::t, + _node_type: ty::t, cc: lib::llvm::CallConv, fn_ty: Type) -> ValueRef { From a696f0fecb9d11204f64d310eb66e095f64bd04a Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 30 Jul 2013 18:46:40 -0700 Subject: [PATCH 6/6] test: add testcases for external iterators using foreach. --- .../foreach-external-iterators-break.rs | 21 ++++++++++ ...xternal-iterators-hashmap-break-restart.rs | 41 +++++++++++++++++++ .../foreach-external-iterators-hashmap.rs | 27 ++++++++++++ .../foreach-external-iterators-loop.rs | 21 ++++++++++ .../foreach-external-iterators-nested.rs | 23 +++++++++++ .../run-pass/foreach-external-iterators.rs | 18 ++++++++ 6 files changed, 151 insertions(+) create mode 100644 src/test/run-pass/foreach-external-iterators-break.rs create mode 100644 src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs create mode 100644 src/test/run-pass/foreach-external-iterators-hashmap.rs create mode 100644 src/test/run-pass/foreach-external-iterators-loop.rs create mode 100644 src/test/run-pass/foreach-external-iterators-nested.rs create mode 100644 src/test/run-pass/foreach-external-iterators.rs diff --git a/src/test/run-pass/foreach-external-iterators-break.rs b/src/test/run-pass/foreach-external-iterators-break.rs new file mode 100644 index 00000000000..74ff344b735 --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators-break.rs @@ -0,0 +1,21 @@ +// Copyright 2012 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. + +fn main() { + let x = [1,..100]; + let mut y = 0; + foreach i in x.iter() { + if y > 10 { + break; + } + y += *i; + } + assert!(y == 11); +} diff --git a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs new file mode 100644 index 00000000000..4b6421cb0d3 --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs @@ -0,0 +1,41 @@ +// Copyright 2012 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. + +use std::hashmap::HashMap; + +// This is a fancy one: it uses an external iterator established +// outside the loop, breaks, then _picks back up_ and continues +// iterating with it. + +fn main() { + let mut h = HashMap::new(); + let kvs = [(1, 10), (2, 20), (3, 30)]; + foreach &(k,v) in kvs.iter() { + h.insert(k,v); + } + let mut x = 0; + let mut y = 0; + + let mut i = h.iter(); + + foreach (&k,&v) in i { + x += k; + y += v; + break; + } + + foreach (&k,&v) in i { + x += k; + y += v; + } + + assert_eq!(x, 6); + assert_eq!(y, 60); +} \ No newline at end of file diff --git a/src/test/run-pass/foreach-external-iterators-hashmap.rs b/src/test/run-pass/foreach-external-iterators-hashmap.rs new file mode 100644 index 00000000000..bc6508c4a5f --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators-hashmap.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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. + +use std::hashmap::HashMap; + +fn main() { + let mut h = HashMap::new(); + let kvs = [(1, 10), (2, 20), (3, 30)]; + foreach &(k,v) in kvs.iter() { + h.insert(k,v); + } + let mut x = 0; + let mut y = 0; + foreach (&k,&v) in h.iter() { + x += k; + y += v; + } + assert_eq!(x, 6); + assert_eq!(y, 60); +} \ No newline at end of file diff --git a/src/test/run-pass/foreach-external-iterators-loop.rs b/src/test/run-pass/foreach-external-iterators-loop.rs new file mode 100644 index 00000000000..8db6b50f8cd --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators-loop.rs @@ -0,0 +1,21 @@ +// Copyright 2012 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. + +fn main() { + let x = [1,..100]; + let mut y = 0; + foreach (n,i) in x.iter().enumerate() { + if n < 10 { + loop; + } + y += *i; + } + assert_eq!(y, 90); +} diff --git a/src/test/run-pass/foreach-external-iterators-nested.rs b/src/test/run-pass/foreach-external-iterators-nested.rs new file mode 100644 index 00000000000..ffc01ebff19 --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators-nested.rs @@ -0,0 +1,23 @@ +// Copyright 2012 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. + +fn main() { + let x = [1,..100]; + let y = [2,..100]; + let mut p = 0; + let mut q = 0; + foreach i in x.iter() { + foreach j in y.iter() { + p += *j; + } + q += *i + p; + } + assert!(q == 1010100); +} diff --git a/src/test/run-pass/foreach-external-iterators.rs b/src/test/run-pass/foreach-external-iterators.rs new file mode 100644 index 00000000000..55884cee4ec --- /dev/null +++ b/src/test/run-pass/foreach-external-iterators.rs @@ -0,0 +1,18 @@ +// Copyright 2012 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. + +fn main() { + let x = [1,..100]; + let mut y = 0; + foreach i in x.iter() { + y += *i + } + assert!(y == 100); +} \ No newline at end of file