Skip to content
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

Allow statement-generating braced macro invocations at the end of blocks #34436

Merged
merged 5 commits into from
Jun 28, 2016
Merged
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
17 changes: 15 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,10 +587,23 @@ impl<'a> LoweringContext<'a> {
}

fn lower_block(&mut self, b: &Block) -> P<hir::Block> {
let mut stmts = Vec::new();
let mut expr = None;

if let Some((last, rest)) = b.stmts.split_last() {
stmts = rest.iter().map(|s| self.lower_stmt(s)).collect::<Vec<_>>();
let last = self.lower_stmt(last);
if let hir::StmtExpr(e, _) = last.node {
expr = Some(e);
} else {
stmts.push(last);
}
}

P(hir::Block {
id: b.id,
stmts: b.stmts.iter().map(|s| self.lower_stmt(s)).collect(),
expr: b.expr.as_ref().map(|ref x| self.lower_expr(x)),
stmts: stmts.into(),
expr: expr,
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
})
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,10 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
}

pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
use syntax::codemap::Spanned;
use syntax::ptr::P;
use syntax::util::move_map::MoveMap;

struct NodeIdAssigner<'a> {
sess: &'a Session,
}
Expand All @@ -772,6 +776,27 @@ pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
self.sess.next_node_id()
}

fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
block.map(|mut block| {
block.id = self.new_id(block.id);

let stmt = block.stmts.pop();
block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter());
if let Some(Spanned { node: ast::StmtKind::Expr(expr, _), span }) = stmt {
let expr = self.fold_expr(expr);
let id = expr.id;
block.stmts.push(Spanned {
span: span,
node: ast::StmtKind::Expr(expr, id)
});
} else if let Some(stmt) = stmt {
block.stmts.extend(self.fold_stmt(stmt));
}

block
})
}
}

let krate = time(sess.time_passes(),
Expand Down
6 changes: 4 additions & 2 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,10 @@ impl fold::Folder for ReplaceBodyWithLoop {
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> {
P(ast::Block {
expr: e,
stmts: vec![],
stmts: e.map(|e| codemap::Spanned {
span: e.span,
node: ast::StmtKind::Expr(e, ast::DUMMY_NODE_ID),
}).into_iter().collect(),
rules: rules,
id: ast::DUMMY_NODE_ID,
span: codemap::DUMMY_SP,
Expand Down
5 changes: 1 addition & 4 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,9 +528,6 @@ impl PartialEq for MetaItemKind {
pub struct Block {
/// Statements in a block
pub stmts: Vec<Stmt>,
/// An expression at the end of the block
/// without a semicolon, if any
pub expr: Option<P<Expr>>,
pub id: NodeId,
/// Distinguishes between `unsafe { ... }` and `{ ... }`
pub rules: BlockCheckMode,
Expand Down Expand Up @@ -803,7 +800,7 @@ pub enum StmtKind {
/// Could be an item or a local (let) binding:
Decl(P<Decl>, NodeId),

/// Expr without trailing semi-colon (must have unit type):
/// Expr without trailing semi-colon
Expr(P<Expr>, NodeId),

/// Expr with trailing semi-colon (may have any type):
Expand Down
47 changes: 21 additions & 26 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub trait AstBuilder {

// statements
fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt;
fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P<ast::Expr>) -> ast::Stmt;
fn stmt_let_typed(&self,
sp: Span,
Expand All @@ -98,12 +99,8 @@ pub trait AstBuilder {
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;

// blocks
fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block>;
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
fn block_all(&self, span: Span,
stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block>;

// expressions
fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr>;
Expand Down Expand Up @@ -508,6 +505,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}

fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
respan(expr.span, ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID))
}

fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt {
respan(expr.span, ast::StmtKind::Semi(expr, ast::DUMMY_NODE_ID))
}

Expand Down Expand Up @@ -556,30 +557,24 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
P(respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID)))
}

fn block(&self, span: Span, stmts: Vec<ast::Stmt>,
expr: Option<P<Expr>>) -> P<ast::Block> {
self.block_all(span, stmts, expr)
}

fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
let decl = respan(sp, ast::DeclKind::Item(item));
respan(sp, ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID))
}

fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
self.block_all(expr.span, Vec::new(), Some(expr))
}
fn block_all(&self,
span: Span,
stmts: Vec<ast::Stmt>,
expr: Option<P<ast::Expr>>) -> P<ast::Block> {
P(ast::Block {
stmts: stmts,
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span: span,
})
self.block(expr.span, vec![Spanned {
span: expr.span,
node: ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID),
}])
}
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
P(ast::Block {
stmts: stmts,
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span: span,
})
}

fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr> {
Expand Down Expand Up @@ -948,14 +943,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ids: Vec<ast::Ident>,
stmts: Vec<ast::Stmt>)
-> P<ast::Expr> {
self.lambda(span, ids, self.block(span, stmts, None))
self.lambda(span, ids, self.block(span, stmts))
}
fn lambda_stmts_0(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Expr> {
self.lambda0(span, self.block(span, stmts, None))
self.lambda0(span, self.block(span, stmts))
}
fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
ident: ast::Ident) -> P<ast::Expr> {
self.lambda1(span, self.block(span, stmts, None), ident)
self.lambda1(span, self.block(span, stmts), ident)
}

fn arg(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Arg {
Expand Down
11 changes: 1 addition & 10 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,23 +636,14 @@ pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {

// expand the elements of a block.
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| {
b.map(|Block {id, stmts, rules, span}| {
let new_stmts = stmts.into_iter().flat_map(|x| {
// perform pending renames and expand macros in the statement
fld.fold_stmt(x).into_iter()
}).collect();
let new_expr = expr.map(|x| {
let expr = {
let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
let mut rename_fld = IdentRenamer{renames:pending_renames};
rename_fld.fold_expr(x)
};
fld.fold_expr(expr)
});
Block {
id: fld.new_id(id),
stmts: new_stmts,
expr: new_expr,
rules: rules,
span: span
}
Expand Down
24 changes: 11 additions & 13 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,8 @@ pub fn expand_quote_matcher(cx: &mut ExtCtxt,
let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
let mut vector = mk_stmts_let(cx, sp);
vector.extend(statements_mk_tts(cx, &tts[..], true));
let block = cx.expr_block(
cx.block_all(sp,
vector,
Some(cx.expr_ident(sp, id_ext("tt")))));
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let block = cx.expr_block(cx.block(sp, vector));

let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
base::MacEager::expr(expanded)
Expand Down Expand Up @@ -765,8 +763,9 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
let mut tts_stmts = vec![stmt_let_tt];
tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
Some(cx.expr_ident(sp, id_ext("tt")))));
tts_stmts.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let e_tts = cx.expr_block(cx.block(sp, tts_stmts));

let e_separator = match seq.separator {
Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
None => cx.expr_none(sp),
Expand Down Expand Up @@ -884,10 +883,8 @@ fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])

let mut vector = mk_stmts_let(cx, sp);
vector.extend(statements_mk_tts(cx, &tts[..], false));
let block = cx.expr_block(
cx.block_all(sp,
vector,
Some(cx.expr_ident(sp, id_ext("tt")))));
vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
let block = cx.expr_block(cx.block(sp, vector));

(cx_expr, block)
}
Expand All @@ -901,13 +898,14 @@ fn expand_wrapper(cx: &ExtCtxt,
let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);

let stmts = imports.iter().map(|path| {
let mut stmts = imports.iter().map(|path| {
// make item: `use ...;`
let path = path.iter().map(|s| s.to_string()).collect();
cx.stmt_item(sp, cx.item_use_glob(sp, ast::Visibility::Inherited, ids_ext(path)))
}).chain(Some(stmt_let_ext_cx)).collect();
}).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
stmts.push(cx.stmt_expr(expr));

cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
cx.expr_block(cx.block(sp, stmts))
}

fn expand_parse_call(cx: &ExtCtxt,
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,10 +845,9 @@ fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
}

pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| Block {
b.map(|Block {id, stmts, rules, span}| Block {
id: folder.new_id(id),
stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
expr: expr.and_then(|x| folder.fold_opt_expr(x)),
rules: rules,
span: folder.new_span(span),
})
Expand Down
1 change: 0 additions & 1 deletion src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,6 @@ mod tests {
attrs: None,}),
ast::DUMMY_NODE_ID),
span: sp(17,19)}),
expr: None,
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default, // no idea
span: sp(15,21),
Expand Down
30 changes: 8 additions & 22 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3217,9 +3217,11 @@ impl<'a> Parser<'a> {
let body_expr = self.parse_expr()?;
P(ast::Block {
id: ast::DUMMY_NODE_ID,
stmts: vec![],
span: body_expr.span,
expr: Some(body_expr),
stmts: vec![Spanned {
span: body_expr.span,
node: StmtKind::Expr(body_expr, ast::DUMMY_NODE_ID),
}],
rules: BlockCheckMode::Default,
})
}
Expand Down Expand Up @@ -4082,7 +4084,6 @@ impl<'a> Parser<'a> {
/// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> {
let mut stmts = vec![];
let mut expr = None;

while !self.eat(&token::CloseDelim(token::Brace)) {
let Spanned {node, span} = if let Some(s) = self.parse_stmt_() {
Expand All @@ -4095,11 +4096,10 @@ impl<'a> Parser<'a> {
};
match node {
StmtKind::Expr(e, _) => {
self.handle_expression_like_statement(e, span, &mut stmts, &mut expr)?;
self.handle_expression_like_statement(e, span, &mut stmts)?;
}
StmtKind::Mac(mac, MacStmtStyle::NoBraces, attrs) => {
// statement macro without braces; might be an
// expr depending on whether a semicolon follows
// statement macro without braces
match self.token {
token::Semi => {
stmts.push(Spanned {
Expand All @@ -4115,11 +4115,7 @@ impl<'a> Parser<'a> {
let lo = e.span.lo;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
self.handle_expression_like_statement(
e,
span,
&mut stmts,
&mut expr)?;
self.handle_expression_like_statement(e, span, &mut stmts)?;
}
}
}
Expand All @@ -4133,13 +4129,6 @@ impl<'a> Parser<'a> {
});
self.bump();
}
token::CloseDelim(token::Brace) => {
// if a block ends in `m!(arg)` without
// a `;`, it must be an expr
expr = Some(self.mk_mac_expr(span.lo, span.hi,
m.and_then(|x| x.node),
attrs));
}
_ => {
stmts.push(Spanned {
node: StmtKind::Mac(m, style, attrs),
Expand All @@ -4165,7 +4154,6 @@ impl<'a> Parser<'a> {

Ok(P(ast::Block {
stmts: stmts,
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: s,
span: mk_sp(lo, self.last_span.hi),
Expand All @@ -4175,8 +4163,7 @@ impl<'a> Parser<'a> {
fn handle_expression_like_statement(&mut self,
e: P<Expr>,
span: Span,
stmts: &mut Vec<Stmt>,
last_block_expr: &mut Option<P<Expr>>)
stmts: &mut Vec<Stmt>)
-> PResult<'a, ()> {
// expression without semicolon
if classify::expr_requires_semi_to_be_stmt(&e) {
Expand All @@ -4202,7 +4189,6 @@ impl<'a> Parser<'a> {
span: span_with_semi,
});
}
token::CloseDelim(token::Brace) => *last_block_expr = Some(e),
_ => {
stmts.push(Spanned {
node: StmtKind::Expr(e, ast::DUMMY_NODE_ID),
Expand Down
Loading