Skip to content

Labelled for & for-desugaring clean up #9054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2064,7 +2064,7 @@ fn populate_scope_map(cx: &mut CrateContext,
}
}

ast::ExprForLoop(_, _, _) => {
ast::ExprForLoop(_, _, _, _) => {
cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \
Found unexpanded for-loop.");
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ pub enum Expr_ {
ExprCast(@Expr, Ty),
ExprIf(@Expr, Block, Option<@Expr>),
ExprWhile(@Expr, Block),
ExprForLoop(@Pat, @Expr, Block),
ExprForLoop(@Pat, @Expr, Block, Option<Ident>),
/* 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. */
Expand Down
170 changes: 39 additions & 131 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{token_tree};
use ast;
use ast_util::{mtwt_outer_mark, new_rename, new_mark};
use ext::build::AstBuilder;
use attr;
use attr::AttrMetaMethods;
use codemap;
use codemap::{Span, Spanned, spanned, ExpnInfo, NameAndSpan};
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
use ext::base::*;
use fold::*;
use opt_vec;
use parse;
use parse::{parse_item_from_source_str};
use parse::token;
Expand All @@ -33,7 +33,7 @@ use std::vec;
pub fn expand_expr(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
e: &Expr_,
s: Span,
span: Span,
fld: @ast_fold,
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
-> (Expr_, Span) {
Expand Down Expand Up @@ -66,7 +66,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
}
Some(@SE(NormalTT(expandfun, exp_span))) => {
cx.bt_push(ExpnInfo {
call_site: s,
call_site: span,
callee: NameAndSpan {
name: extnamestr,
span: exp_span,
Expand Down Expand Up @@ -98,7 +98,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
fld.fold_expr(marked_after).node.clone();
cx.bt_pop();

(fully_expanded, s)
(fully_expanded, span)
}
_ => {
cx.span_fatal(
Expand All @@ -112,62 +112,18 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
}

// Desugar expr_for_loop
// From: `for <src_pat> in <src_expr> <src_loop_block>`
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block) => {
let src_pat = src_pat.clone();
let src_expr = src_expr.clone();

// From: `['<ident>:] for <src_pat> in <src_expr> <src_loop_block>`
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
// 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,
segments: ~[
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
let src_expr = fld.fold_expr(src_expr);
let src_loop_block = fld.fold_block(src_loop_block);

// to:
//
// {
// let _i = &mut <src_expr>;
// loop {
// ['<ident>:] loop {
// match i.next() {
// None => break,
// Some(<src_pat>) => <src_loop_block>
Expand All @@ -176,98 +132,50 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
// }

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 next_ident = cx.ident_of("next");
let none_ident = cx.ident_of("None");

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 local_path = cx.path_ident(span, local_ident);
let some_path = cx.path_ident(span, cx.ident_of("Some"));

// `let i = &mut <src_expr>`
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::PatIdent(ast::BindInfer, local_path_1, None),
span: src_expr.span
},
init: Some(mk_expr(cx, src_expr.span,
ast::ExprAddrOf(ast::MutMutable, src_expr))),
id: cx.next_id(),
span: src_expr.span,
};
let e = @spanned(src_expr.span.lo,
src_expr.span.hi,
ast::DeclLocal(local));
@spanned(lo, hi, ast::StmtDecl(e, cx.next_id()))
};
let iter_decl_stmt = cx.stmt_let(span, false, local_ident,
cx.expr_mut_addr_of(span, src_expr));

// `None => break;`
// `None => break ['<ident>];`
let none_arm = {
let break_expr = mk_expr(cx, span, ast::ExprBreak(None));
let break_stmt = @spanned(lo, hi, ast::StmtExpr(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::PatIdent(ast::BindInfer, none_path, None),
span: span
};
ast::Arm {
pats: ~[none_pat],
guard: None,
body: none_block
}
let break_expr = cx.expr(span, ast::ExprBreak(opt_ident));
let none_pat = cx.pat_ident(span, none_ident);
cx.arm(span, ~[none_pat], break_expr)
};

// `Some(<src_pat>) => <src_loop_block>`
let some_arm = {
let pat = @ast::Pat {
id: cx.next_id(),
node: ast::PatEnum(some_path, Some(~[src_pat])),
span: src_pat.span
};
ast::Arm {
pats: ~[pat],
guard: None,
body: src_loop_block
}
};
let some_arm =
cx.arm(span,
~[cx.pat_enum(span, some_path, ~[src_pat])],
cx.expr_block(src_loop_block));

// `match i.next() { ... }`
let match_stmt = {
let local_expr = mk_expr(cx, span, ast::ExprPath(local_path_2));
let next_call_expr = mk_expr(cx, span,
ast::ExprMethodCall(cx.next_id(),
local_expr, next_ident,
~[], ~[], ast::NoSugar));
let match_expr = mk_expr(cx, span, ast::ExprMatch(next_call_expr,
~[none_arm, some_arm]));
@spanned(lo, hi, ast::StmtExpr(match_expr, cx.next_id()))
};
let match_expr = {
let next_call_expr =
cx.expr_method_call(span, cx.expr_path(local_path), next_ident, ~[]);

// `loop { ... }`
let loop_block = {
let loop_body_block = mk_block(cx, [match_stmt], None, span);
let loop_body_expr = mk_expr(cx, span, ast::ExprLoop(loop_body_block, None));
let loop_body_stmt = @spanned(lo, hi, ast::StmtExpr(loop_body_expr, cx.next_id()));
mk_block(cx, [iter_decl_stmt,
loop_body_stmt],
None, span)
cx.expr_match(span, next_call_expr, ~[none_arm, some_arm])
};

(ast::ExprBlock(loop_block), span)
// ['ident:] loop { ... }
let loop_expr = cx.expr(span,
ast::ExprLoop(cx.block_expr(match_expr), opt_ident));

// `{ let ... ; loop { ... } }`
let block = cx.block(span,
~[iter_decl_stmt],
Some(loop_expr));

(ast::ExprBlock(block), span)
}

_ => orig(e, s, fld)
_ => orig(e, span, fld)
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,11 @@ pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ {
ExprWhile(cond, ref body) => {
ExprWhile(fld.fold_expr(cond), fld.fold_block(body))
}
ExprForLoop(pat, iter, ref body) => {
ExprForLoop(pat, iter, ref body, opt_ident) => {
ExprForLoop(fld.fold_pat(pat),
fld.fold_expr(iter),
fld.fold_block(body))
fld.fold_expr(iter),
fld.fold_block(body),
opt_ident.map_move(|x| fld.fold_ident(x)))
}
ExprLoop(ref body, opt_ident) => {
ExprLoop(
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/oldvisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ pub fn visit_expr<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
(v.visit_expr)(x, (e.clone(), v));
(v.visit_block)(b, (e.clone(), v));
}
ExprForLoop(pattern, subexpression, ref block) => {
ExprForLoop(pattern, subexpression, ref block, _) => {
(v.visit_pat)(pattern, (e.clone(), v));
(v.visit_expr)(subexpression, (e.clone(), v));
(v.visit_block)(block, (e.clone(), v))
Expand Down
15 changes: 10 additions & 5 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1771,7 +1771,7 @@ impl Parser {
} else if self.eat_keyword(keywords::If) {
return self.parse_if_expr();
} else if self.eat_keyword(keywords::For) {
return self.parse_for_expr();
return self.parse_for_expr(None);
} else if self.eat_keyword(keywords::Do) {
return self.parse_sugary_call_expr(lo, ~"do", DoSugar,
ExprDoBody);
Expand All @@ -1781,8 +1781,13 @@ impl Parser {
let lifetime = self.get_lifetime(&*self.token);
self.bump();
self.expect(&token::COLON);
self.expect_keyword(keywords::Loop);
return self.parse_loop_expr(Some(lifetime));
if self.eat_keyword(keywords::For) {
return self.parse_for_expr(Some(lifetime))
} else if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(lifetime))
} else {
self.fatal("expected `for` or `loop` after a label")
}
} else if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(None);
} else if self.eat_keyword(keywords::Match) {
Expand Down Expand Up @@ -2467,7 +2472,7 @@ impl Parser {
}

// parse a 'for' .. 'in' expression ('for' token already eaten)
pub fn parse_for_expr(&self) -> @Expr {
pub fn parse_for_expr(&self, opt_ident: Option<ast::Ident>) -> @Expr {
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`

let lo = self.last_span.lo;
Expand All @@ -2477,7 +2482,7 @@ impl Parser {
let loop_block = self.parse_block();
let hi = self.span.hi;

self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block))
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
}


Expand Down
7 changes: 6 additions & 1 deletion src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,12 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
space(s.s);
print_block(s, blk);
}
ast::ExprForLoop(pat, iter, ref blk) => {
ast::ExprForLoop(pat, iter, ref blk, opt_ident) => {
for ident in opt_ident.iter() {
word(s.s, "'");
print_ident(s, *ident);
word_space(s, ":");
}
head(s, "for");
print_pat(s, pat);
space(s.s);
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ pub fn walk_expr<E:Clone, V:Visitor<E>>(visitor: &mut V, expression: @Expr, env:
visitor.visit_expr(subexpression, env.clone());
visitor.visit_block(block, env.clone())
}
ExprForLoop(pattern, subexpression, ref block) => {
ExprForLoop(pattern, subexpression, ref block, _) => {
visitor.visit_pat(pattern, env.clone());
visitor.visit_expr(subexpression, env.clone());
visitor.visit_block(block, env.clone())
Expand Down Expand Up @@ -812,4 +812,3 @@ impl Visitor<()> for SimpleVisitorVisitor {
walk_struct_field(self, struct_field, env)
}
}

6 changes: 6 additions & 0 deletions src/test/run-pass/labeled-break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ pub fn main() {
break 'foo;
}
}

'bar: for _ in range(0, 100) {
loop {
break 'bar;
}
}
}