diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index b66c286f32596..b99aec9659620 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -245,11 +245,13 @@ tag expr_ { expr_alt(@expr, vec[arm], ann); expr_fn(_fn, ann); expr_block(block, ann); - expr_move(@expr, /* TODO: @expr|is_lval */@expr, ann); - expr_assign(@expr, /* TODO: @expr|is_lval */@expr, ann); - expr_assign_op(binop, @expr, /* TODO: @expr|is_lval */@expr, ann); - expr_send(@expr, /* TODO: @expr|is_lval */@expr, ann); - expr_recv(@expr, /* TODO: @expr|is_lval */@expr, ann); + expr_move(@expr /* TODO: @expr|is_lval */, @expr, ann); + expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann); + expr_swap(@expr /* TODO: @expr|is_lval */, + @expr /* TODO: @expr|is_lval */, ann); + expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann); + expr_send(@expr /* TODO: @expr|is_lval */, @expr, ann); + expr_recv(@expr /* TODO: @expr|is_lval */, @expr, ann); expr_field(@expr, ident, ann); expr_index(@expr, @expr, ann); expr_path(path, ann); diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs index 7f013f7c6148e..89b7d76e08b50 100644 --- a/src/comp/front/lexer.rs +++ b/src/comp/front/lexer.rs @@ -389,8 +389,14 @@ fn next_token(&reader rdr) -> token::token { alt (rdr.curr()) { case ('=') { rdr.bump(); ret token::LE; } case ('<') { ret binop(rdr, token::LSL); } - case ('-') { rdr.bump(); ret token::LARROW; } case ('|') { rdr.bump(); ret token::SEND; } + case ('-') { + rdr.bump(); + alt (rdr.curr()) { + case ('>') { rdr.bump(); ret token::DARROW; } + case (_) { ret token::LARROW; } + } + } case (_) { ret token::LT; } } } diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 88d8516043baf..869aeb2b09277 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1161,6 +1161,12 @@ fn parse_assign_expr(&parser p) -> @ast::expr { ret @spanned(lo, rhs.span.hi, ast::expr_recv(rhs, lhs, p.get_ann())); } + case (token::DARROW) { + p.bump(); + auto rhs = parse_expr(p); + ret @spanned(lo, rhs.span.hi, + ast::expr_swap(lhs, rhs, p.get_ann())); + } case (_) {/* fall through */ } } ret lhs; @@ -1509,7 +1515,9 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool { case (ast::expr_alt(_, _, _)) { ret false; } case (ast::expr_fn(_, _)) { ret false; } case (ast::expr_block(_, _)) { ret false; } + case (ast::expr_move(_, _, _)) { ret true; } case (ast::expr_assign(_, _, _)) { ret true; } + case (ast::expr_swap(_, _, _)) { ret true; } case (ast::expr_assign_op(_, _, _, _)) { ret true; } case (ast::expr_send(_, _, _)) { ret true; } case (ast::expr_recv(_, _, _)) { ret true; } diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs index 30329e1ffd32b..57a75b1e40d81 100644 --- a/src/comp/front/token.rs +++ b/src/comp/front/token.rs @@ -52,6 +52,7 @@ tag token { SEND; RECV; LARROW; + DARROW; LPAREN; RPAREN; LBRACKET; @@ -124,6 +125,7 @@ fn to_str(lexer::reader r, token t) -> str { case (SEND) { ret "<|"; } case (RECV) { ret "<|"; } case (LARROW) { ret "<-"; } + case (DARROW) { ret "<->"; } case (LPAREN) { ret "("; } case (RPAREN) { ret ")"; } case (LBRACKET) { ret "["; } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index e378a4d7b09e9..8c0b357cb5d55 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3027,7 +3027,7 @@ fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src, ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) { ret res(cx, cx.build.Store(src, dst)); } else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) || - ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) { + ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) { ret res(cx, C_nil()); } else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) { if (action == DROP_EXISTING) { @@ -3038,7 +3038,7 @@ fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src, } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) || ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) { if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; } - auto r = memmove_ty(cx, dst, cx.build.Load(src), t); + auto r = memmove_ty(cx, dst, src, t); ret zero_alloca(r.bcx, src, t); } cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " + @@ -5404,6 +5404,24 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) -> rhs_res.val, t); ret res(copy_res.bcx, C_nil()); } + case (ast::expr_swap(?dst, ?src, _)) { + auto lhs_res = trans_lval(cx, dst); + assert (lhs_res.is_mem); + // FIXME Fill in lhs_res.res.bcx.sp + + auto rhs_res = trans_lval(lhs_res.res.bcx, src); + auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src); + auto tmp_res = alloc_ty(rhs_res.res.bcx, t); + + // Swap through a temporary. + auto move1_res = memmove_ty(tmp_res.bcx, tmp_res.val, + lhs_res.res.val, t); + auto move2_res = memmove_ty(move1_res.bcx, lhs_res.res.val, + rhs_res.res.val, t); + auto move3_res = memmove_ty(move2_res.bcx, rhs_res.res.val, + tmp_res.val, t); + ret res(move3_res.bcx, C_nil()); + } case (ast::expr_assign_op(?op, ?dst, ?src, _)) { auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src); auto lhs_res = trans_lval(cx, dst); diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index a355c9f3f1217..a108f94653966 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -293,6 +293,10 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) { case (_) { find_pre_post_exprs(fcx, [lhs, rhs], a); } } } + case (expr_swap(?lhs, ?rhs, ?a)) { + // Both sides must already be initialized + find_pre_post_exprs(fcx, [lhs, rhs], a); + } case (expr_assign(?lhs, ?rhs, ?a)) { alt (lhs.node) { case (expr_path(?p, ?a_lhs)) { diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index ddcf448c471ed..ab0cf1434d131 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -328,6 +328,20 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { } ret changed; } + case (expr_swap(?lhs, ?rhs, ?a)) { + /* quite similar to binary -- should abstract this */ + changed = extend_prestate_ann(fcx.ccx, a, pres) || changed; + changed = find_pre_post_state_expr(fcx, pres, lhs) + || changed; + changed = + find_pre_post_state_expr(fcx, + expr_poststate(fcx.ccx, lhs), + rhs) || changed; + changed = + extend_poststate_ann(fcx.ccx, a, + expr_poststate(fcx.ccx, rhs)) || changed; + ret changed; + } case (expr_recv(?lhs, ?rhs, ?a)) { extend_prestate_ann(fcx.ccx, a, pres); alt (lhs.node) { diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 6ef2384d8f145..39601c603ffa2 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1548,6 +1548,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann { case (ast::expr_block(_, ?a)) { ret a; } case (ast::expr_move(_, _, ?a)) { ret a; } case (ast::expr_assign(_, _, ?a)) { ret a; } + case (ast::expr_swap(_,_,?a)) { ret a; } case (ast::expr_assign_op(_, _, _, ?a)) { ret a; } case (ast::expr_send(_, _, ?a)) { ret a; } case (ast::expr_recv(_, _, ?a)) { ret a; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index bd804b97bd216..6a88ab3c88603 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1639,6 +1639,10 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); check_assignment(fcx, expr.span, lhs, rhs, a); } + case (ast::expr_swap(?lhs, ?rhs, ?a)) { + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, expr.span, lhs, rhs, a); + } case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); check_assignment(fcx, expr.span, lhs, rhs, a); diff --git a/src/comp/middle/visit.rs b/src/comp/middle/visit.rs index 46acc83345960..0d7605b71d84b 100644 --- a/src/comp/middle/visit.rs +++ b/src/comp/middle/visit.rs @@ -314,6 +314,10 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) { vt(v).visit_expr(b, e, v); vt(v).visit_expr(a, e, v); } + case (expr_swap(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } case (expr_assign_op(_, ?a, ?b, _)) { vt(v).visit_expr(b, e, v); vt(v).visit_expr(a, e, v); diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index a57d3183677aa..13a4eade83960 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -347,6 +347,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { walk_expr(v, b); } case (ast::expr_move(?a, ?b, _)) { walk_expr(v, a); walk_expr(v, b); } + case (ast::expr_swap(?a, ?b, _)) { walk_expr(v, a); walk_expr(v, b); } case (ast::expr_assign_op(_, ?a, ?b, _)) { walk_expr(v, a); walk_expr(v, b); diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 8db88541c2fc5..b5bfe23bab767 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -704,6 +704,12 @@ fn print_expr(&ps s, &@ast::expr expr) { word_space(s, "="); print_expr(s, rhs); } + case (ast::expr_swap(?lhs, ?rhs, _)) { + print_expr(s, lhs); + space(s.s); + word_space(s, "<->"); + print_expr(s, rhs); + } case (ast::expr_assign_op(?op, ?lhs, ?rhs, _)) { print_expr(s, lhs); space(s.s); diff --git a/src/test/compile-fail/swap-uninit.rs b/src/test/compile-fail/swap-uninit.rs new file mode 100644 index 0000000000000..18ca56b5aea07 --- /dev/null +++ b/src/test/compile-fail/swap-uninit.rs @@ -0,0 +1,7 @@ +// error-pattern:Unsatisfied precondition + +fn main() { + auto x = 3; + auto y; + x <-> y; +} diff --git a/src/test/run-pass/swap-1.rs b/src/test/run-pass/swap-1.rs new file mode 100644 index 0000000000000..a4ce5bf2d6295 --- /dev/null +++ b/src/test/run-pass/swap-1.rs @@ -0,0 +1,7 @@ +fn main() { + auto x = 3; + auto y = 7; + x <-> y; + assert (x == 7); + assert (y == 3); +} diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs new file mode 100644 index 0000000000000..6c33030ba0a56 --- /dev/null +++ b/src/test/run-pass/swap-2.rs @@ -0,0 +1,14 @@ +fn swap[T](&vec[mutable T] v, int i, int j) { + v.(i) <-> v.(j); +} + +fn main() { + let vec[mutable int] a = [mutable 0,1,2,3,4,5,6]; + swap(a, 2, 4); + assert(a.(2) == 4); + assert(a.(4) == 2); + auto n = 42; + n <-> a.(0); + assert(a.(0) == 42); + assert(n == 0); +}