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 1 commit
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
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
45 changes: 20 additions & 25 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,9 @@ 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>;
fn block_all(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;

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

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

fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident,
Expand Down Expand Up @@ -556,9 +553,8 @@ 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 block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
self.block_all(span, stmts)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these two functions both exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason -- removed block_all.

}

fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
Expand All @@ -567,19 +563,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}

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_all(expr.span, vec![Spanned {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think respan is preferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't land directly -- once it's approved I'll rebase over #34316 in the breaking batch, so this will become ast::Stmt { span: expr.span, node: StmtKind::Expr(expr), id: DUMMY_NODE_ID }.

span: expr.span,
node: ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID),
}])
}
fn block_all(&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_all(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_all(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_all(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
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
29 changes: 9 additions & 20 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1619,9 +1619,6 @@ impl<'a> State<'a> {
}
}
}
if parse::classify::stmt_ends_with_semi(&st.node) {
try!(word(&mut self.s, ";"));
}
self.maybe_print_trailing_comment(st.span, None)
}

Expand Down Expand Up @@ -1668,14 +1665,6 @@ impl<'a> State<'a> {
for st in &blk.stmts {
try!(self.print_stmt(st));
}
match blk.expr {
Some(ref expr) => {
try!(self.space_if_not_bol());
try!(self.print_expr_outer_attr_style(&expr, false));
try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
}
_ => ()
}
try!(self.bclose_maybe_open(blk.span, indented, close_box));
self.ann.post(self, NodeBlock(blk))
}
Expand Down Expand Up @@ -2084,24 +2073,23 @@ impl<'a> State<'a> {
_ => false
};

if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
try!(self.print_block_unclosed(&body));
} else {
// we extract the block, so as not to create another set of boxes
let i_expr = body.expr.as_ref().unwrap();
match i_expr.node {
ast::ExprKind::Block(ref blk) => {
match body.stmts.last().map(|stmt| &stmt.node) {
Some(&ast::StmtKind::Expr(ref i_expr, _)) if default_return &&
body.stmts.len() == 1 => {
// we extract the block, so as not to create another set of boxes
if let ast::ExprKind::Block(ref blk) = i_expr.node {
try!(self.print_block_unclosed_with_attrs(
&blk,
i_expr.attrs.as_attr_slice()));
}
_ => {
} else {
// this is a bare expression
try!(self.print_expr(&i_expr));
try!(self.end()); // need to close a box
}
}
_ => try!(self.print_block_unclosed(&body)),
}

// a box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.
Expand Down Expand Up @@ -2295,6 +2283,7 @@ impl<'a> State<'a> {
try!(self.word_space("="));
try!(self.print_expr(&init));
}
try!(word(&mut self.s, ";"));
self.end()
}
ast::DeclKind::Item(ref item) => self.print_item(&item)
Expand Down
Loading