From 71147024962318033ade76ba741d1ecc1dfae3ce Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Oct 2011 14:11:24 +0200 Subject: [PATCH] Change the way block calls are parsed, mark them as block-calls. This makes it possible to omit the semicolon after the block, and will cause the pretty-printer to properly print such calls (if pretty-printing of blocks wasn't so broken). Block calls (with the block outside of the parentheses) can now only occur at statement level, and their value can not be used. When calling a block-style function that returns a useful value, the block must be put insde the parentheses. Issue #1054 --- src/comp/front/test.rs | 6 ++-- src/comp/middle/alias.rs | 4 +-- src/comp/middle/fn_usage.rs | 2 +- src/comp/middle/kind.rs | 4 +-- src/comp/middle/mut.rs | 2 +- src/comp/middle/trans.rs | 6 ++-- src/comp/middle/tstate/auxiliary.rs | 2 +- src/comp/middle/tstate/collect_locals.rs | 2 +- src/comp/middle/tstate/pre_post_conditions.rs | 2 +- src/comp/middle/tstate/states.rs | 2 +- src/comp/middle/typeck.rs | 6 ++-- src/comp/syntax/ast.rs | 2 +- src/comp/syntax/ast_util.rs | 2 +- src/comp/syntax/ext/fmt.rs | 2 +- src/comp/syntax/fold.rs | 5 +-- src/comp/syntax/parse/parser.rs | 35 ++++++++++--------- src/comp/syntax/print/pprust.rs | 16 ++++++--- src/comp/syntax/visit.rs | 2 +- 18 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs index fa48c9fbfb88..0def09799285 100644 --- a/src/comp/front/test.rs +++ b/src/comp/front/test.rs @@ -302,7 +302,7 @@ fn mk_test_wrapper(cx: test_ctxt, span: span) -> @ast::expr { let call_expr: ast::expr = { id: cx.next_node_id(), - node: ast::expr_call(@fn_path_expr, []), + node: ast::expr_call(@fn_path_expr, [], false), span: span }; @@ -401,7 +401,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr { let test_path_expr: ast::expr = {id: cx.next_node_id(), node: test_path_expr_, span: dummy_sp()}; - let test_call_expr_: ast::expr_ = ast::expr_call(@test_path_expr, []); + let test_call_expr_ = ast::expr_call(@test_path_expr, [], false); let test_call_expr: ast::expr = {id: cx.next_node_id(), node: test_call_expr_, span: dummy_sp()}; @@ -419,7 +419,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr { let test_main_call_expr_: ast::expr_ = ast::expr_call(@test_main_path_expr, - [@args_path_expr, @test_call_expr]); + [@args_path_expr, @test_call_expr], false); let test_main_call_expr: ast::expr = {id: cx.next_node_id(), node: test_main_call_expr_, span: dummy_sp()}; diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 36f6d0f0017e..5b96bddfe3f3 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -93,7 +93,7 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span, fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt) { let handled = true; alt ex.node { - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { check_call(*cx, f, args); handled = false; } @@ -667,7 +667,7 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) } if is_none(path_def_id(cx, base_root.ex)) { alt base_root.ex.node { - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { let fty = ty::expr_ty(cx.tcx, f); alt ty::ty_fn_ret_style(cx.tcx, fty) { ast::return_ref(mut, arg_n) { diff --git a/src/comp/middle/fn_usage.rs b/src/comp/middle/fn_usage.rs index 3f6b2908c201..e7c3033ce1f2 100644 --- a/src/comp/middle/fn_usage.rs +++ b/src/comp/middle/fn_usage.rs @@ -42,7 +42,7 @@ fn fn_usage_expr(expr: @ast::expr, } } - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { let f_ctx = {unsafe_fn_legal: true, generic_bare_fn_legal: true with ctx}; v.visit_expr(f, f_ctx, v); diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index da908f55429b..81032c6a91f4 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -174,7 +174,7 @@ fn need_shared_or_pinned_ctor(tcx: ty::ctxt, a: @ast::expr, descr: str) { fn pinned_ctor(a: @ast::expr) -> bool { // FIXME: Technically a lambda block is also a pinned ctor alt a.node { - ast::expr_call(cexpr, _) { + ast::expr_call(cexpr, _, _) { // Assuming that if it's a call that it's safe to move in, mostly // because I don't know offhand how to ensure that it's a call // specifically to a resource constructor @@ -224,7 +224,7 @@ fn check_expr(tcx: ty::ctxt, e: @ast::expr) { ast::expr_fail(option::some(a)) { need_expr_kind(tcx, a, ast::kind_shared, "'fail' operand"); } - ast::expr_call(callee, _) { + ast::expr_call(callee, _, _) { let tpt = ty::expr_ty_params_and_ty(tcx, callee); // If we have typarams, we're calling an item; we need to check diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs index 9dfddd2ae977..4c286e6cab43 100644 --- a/src/comp/middle/mut.rs +++ b/src/comp/middle/mut.rs @@ -150,7 +150,7 @@ fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) { fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) { alt ex.node { - expr_call(f, args) { check_call(cx, f, args); } + expr_call(f, args, _) { check_call(cx, f, args); } expr_swap(lhs, rhs) { check_lval(cx, lhs, msg_assign); check_lval(cx, rhs, msg_assign); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6f9456dea2aa..d47ee4873416 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3147,7 +3147,7 @@ fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool { ty::ty_rec(_) { true } } } - ast::expr_call(f, _) { + ast::expr_call(f, _, _) { let fty = ty::expr_ty(tcx, f); ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fty)) } @@ -3198,7 +3198,7 @@ fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result { ret lval_owned(sub.bcx, val); } // This is a by-ref returning call. Regular calls are not lval - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { let cell = empty_dest_cell(); let bcx = trans_call(cx, f, args, e.id, by_val(cell)); ret lval_owned(bcx, *cell); @@ -4175,7 +4175,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { ast::expr_anon_obj(anon_obj) { ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest); } - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { ret trans_call(bcx, f, args, e.id, dest); } ast::expr_field(_, _) { diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 6ffd10c02bdf..b8544e2b5add 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -607,7 +607,7 @@ fn exprs_to_constr_args(tcx: ty::ctxt, args: [@expr]) -> [@constr_arg_use] { fn expr_to_constr(tcx: ty::ctxt, e: @expr) -> sp_constr { alt e.node { - expr_call(operator, args) { + expr_call(operator, args, _) { alt operator.node { expr_path(p) { ret respan(e.span, diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index 28d9c288aa7b..b3c8d71a3bf7 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -32,7 +32,7 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt) { // If it's a call, generate appropriate instances of the // call's constraints. - expr_call(operator, operands) { + expr_call(operator, operands, _) { for c: @ty::constr in constraints_expr(cx.tcx, operator) { let ct: sp_constr = respan(c.span, diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index dee66e6df4dc..d0832142d3e7 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -309,7 +309,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { alt e.node { - expr_call(operator, operands) { + expr_call(operator, operands, _) { /* copy */ let args = operands; diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 39f87f0f1145..2af37f22867a 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -335,7 +335,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { vec::len(elts)), elts, return_val); } - expr_call(operator, operands) { + expr_call(operator, operands, _) { ret find_pre_post_state_call(fcx, pres, operator, e.id, callee_arg_init_ops(fcx, operator.id), operands, diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 7e4c80d5a279..a20ab23f9f61 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2072,7 +2072,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, out_args, rt, cf, constrs); write::ty_only_fixup(fcx, id, ft); } - ast::expr_call(f, args) { + ast::expr_call(f, args, _) { bot = check_call_full(fcx, expr.span, f, args, expr.id); } ast::expr_self_method(ident) { @@ -2535,7 +2535,7 @@ fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { /* e must be a call expr where all arguments are either literals or slots */ alt e.node { - ast::expr_call(operator, operands) { + ast::expr_call(operator, operands, _) { if !ty::is_pred_ty(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, operator)) { fcx.ccx.tcx.sess.span_err (operator.span, @@ -2632,7 +2632,7 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { let call_expr_id = fcx.ccx.tcx.sess.next_node_id(); let call_expr = @{id: call_expr_id, - node: ast::expr_call(oper, c_args), + node: ast::expr_call(oper, c_args, false), span: c.span}; check_pred_expr(fcx, call_expr); } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index a971653c5f11..9abab5533310 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -184,7 +184,7 @@ type expr = {id: node_id, node: expr_, span: span}; tag expr_ { expr_vec([@expr], mutability); expr_rec([field], option::t<@expr>); - expr_call(@expr, [@expr]); + expr_call(@expr, [@expr], bool); expr_tup([@expr]); expr_self_method(ident); expr_bind(@expr, [option::t<@expr>]); diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 3d4fe27d9807..b10ce87a6979 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -163,7 +163,7 @@ fn is_exported(i: ident, m: _mod) -> bool { } pure fn is_call_expr(e: @expr) -> bool { - alt e.node { expr_call(_, _) { true } _ { false } } + alt e.node { expr_call(_, _, _) { true } _ { false } } } fn is_constraint_arg(e: @expr) -> bool { diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs index b51db707daf5..f3fb25acaf90 100644 --- a/src/comp/syntax/ext/fmt.rs +++ b/src/comp/syntax/ext/fmt.rs @@ -79,7 +79,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr]) fn make_call(cx: ext_ctxt, sp: span, fn_path: [ast::ident], args: [@ast::expr]) -> @ast::expr { let pathexpr = make_path_expr(cx, sp, fn_path); - let callexpr = ast::expr_call(pathexpr, args); + let callexpr = ast::expr_call(pathexpr, args, false); ret @{id: cx.next_id(), node: callexpr, span: sp}; } fn make_rec_expr(cx: ext_ctxt, sp: span, diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 276967b792b6..e79ca1adf981 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -348,8 +348,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { option::map(fld.fold_expr, maybe_expr)) } expr_tup(elts) { expr_tup(vec::map(fld.fold_expr, elts)) } - expr_call(f, args) { - expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args)) + expr_call(f, args, blk) { + expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args), + blk) } expr_self_method(id) { expr_self_method(fld.fold_ident(id)) } expr_bind(f, args) { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 1a29a033f562..8f632165772b 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -977,7 +977,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_expr, p); hi = es.span.hi; - ex = ast::expr_call(f, es.node); + ex = ast::expr_call(f, es.node, false); } else if p.peek() == token::MOD_SEP || is_ident(p.peek()) && !is_word(p, "true") && !is_word(p, "false") { @@ -1051,7 +1051,7 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr { let es = parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_expr, p); hi = es.span.hi; - let nd = ast::expr_call(e, es.node); + let nd = ast::expr_call(e, es.node, false); e = mk_expr(p, lo, hi, nd); } } @@ -1073,19 +1073,6 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr { t { unexpected(p, t); } } } - token::LBRACE. when is_bar(p.look_ahead(1u)) { - p.bump(); - let blk = parse_fn_block_expr(p); - alt e.node { - ast::expr_call(f, args) { - e = @{node: ast::expr_call(f, args + [blk]) with *e}; - } - _ { - e = mk_expr(p, lo, p.get_last_hi_pos(), - ast::expr_call(e, [blk])); - } - } - } _ { ret e; } } } @@ -1569,7 +1556,6 @@ fn parse_source_stmt(p: parser) -> @ast::stmt { let decl = parse_let(p); ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id())); } else { - let item_attrs; alt parse_outer_attrs_or_ext(p) { none. { item_attrs = []; } @@ -1589,7 +1575,6 @@ fn parse_source_stmt(p: parser) -> @ast::stmt { } } - alt maybe_item { some(i) { let hi = i.span.hi; @@ -1599,6 +1584,21 @@ fn parse_source_stmt(p: parser) -> @ast::stmt { none. { // Remainder are line-expr stmts. let e = parse_expr(p); + // See if it is a block call + if p.peek() == token::LBRACE && is_bar(p.look_ahead(1u)) { + p.bump(); + let blk = parse_fn_block_expr(p); + alt e.node { + ast::expr_call(f, args, false) { + e = @{node: ast::expr_call(f, args + [blk], true) + with *e}; + } + _ { + e = mk_expr(p, lo, p.get_last_hi_pos(), + ast::expr_call(e, [blk], true)); + } + } + } ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_id())); } _ { p.fatal("expected statement"); } @@ -1624,6 +1624,7 @@ fn expr_has_value(e: @ast::expr) -> bool { ast::expr_for(_, _, blk) | ast::expr_do_while(blk, _) { !option::is_none(blk.node.expr) } + ast::expr_call(_, _, true) { false } _ { true } } } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 9a7944f47c83..91e3f2ffb599 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -727,11 +727,19 @@ fn print_expr(s: ps, &&expr: @ast::expr) { commasep_exprs(s, inconsistent, exprs); pclose(s); } - ast::expr_call(func, args) { + ast::expr_call(func, args, has_block) { print_expr_parens_if_not_bot(s, func); - popen(s); - commasep_exprs(s, inconsistent, args); - pclose(s); + let base_args = args, blk = none; + if has_block { blk = some(vec::pop(base_args)); } + if !has_block || vec::len(base_args) > 0u { + popen(s); + commasep_exprs(s, inconsistent, base_args); + pclose(s); + } + if has_block { + nbsp(s); + print_expr(s, option::get(blk)); + } } ast::expr_self_method(ident) { word(s.s, "self."); diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 3cd44fe10da3..0725611eb04d 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -245,7 +245,7 @@ fn visit_expr(ex: @expr, e: E, v: vt) { visit_expr_opt(base, e, v); } expr_tup(elts) { for el in elts { v.visit_expr(el, e, v); } } - expr_call(callee, args) { + expr_call(callee, args, _) { visit_exprs(args, e, v); v.visit_expr(callee, e, v); }