Remove the '<->' operator from the language

This commit is contained in:
Alex Crichton 2013-05-06 00:43:19 -04:00
parent 998fececd6
commit 63c7e2f991
18 changed files with 16 additions and 128 deletions

View File

@ -1946,35 +1946,6 @@ fn avg(v: &[float]) -> float {
}
~~~~
#### Swap expressions
A _swap expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) followed by a bi-directional arrow (`<->`) and another [lvalue](#lvalues-rvalues-and-temporaries).
Evaluating a swap expression causes, as a side effect, the values held in the left-hand-side and right-hand-side [lvalues](#lvalues-rvalues-and-temporaries) to be exchanged indivisibly.
Evaluating a swap expression neither changes reference counts,
nor deeply copies any owned structure pointed to by the moved [rvalue](#lvalues-rvalues-and-temporaries).
Instead, the swap expression represents an indivisible *exchange of ownership*,
between the right-hand-side and the left-hand-side of the expression.
No allocation or destruction is entailed.
An example of three different swap expressions:
~~~~~~~~
# let mut x = &mut [0];
# let mut a = &mut [0];
# let i = 0;
# struct S1 { z: int };
# struct S2 { c: int };
# let mut y = S1{z: 0};
# let mut b = S2{c: 0};
x <-> a;
x[i] <-> a[i];
y.z <-> b.c;
~~~~~~~~
#### Assignment expressions
An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
@ -2015,7 +1986,7 @@ as
== !=
&&
||
= <->
=
~~~~
Operators at the same precedence level are evaluated left-to-right.

View File

@ -758,10 +758,6 @@ fn check_loans_in_expr<'a>(expr: @ast::expr,
}
match expr.node {
ast::expr_swap(l, r) => {
self.check_assignment(l);
self.check_assignment(r);
}
ast::expr_assign(dest, _) |
ast::expr_assign_op(_, dest, _) => {
self.check_assignment(dest);

View File

@ -698,11 +698,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
self.walk_expr(l, in_out, loop_scopes);
}
ast::expr_swap(l, r) => {
self.walk_expr(l, in_out, loop_scopes);
self.walk_expr(r, in_out, loop_scopes);
}
ast::expr_vec(ref exprs, _) => {
self.walk_exprs(*exprs, in_out, loop_scopes)
}

View File

@ -523,7 +523,7 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) {
expr_binary(*) | expr_addr_of(*) | expr_copy(*) | expr_loop_body(*) |
expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) |
expr_assign(*) | expr_swap(*) | expr_assign_op(*) | expr_mac(*) |
expr_assign(*) | expr_assign_op(*) | expr_mac(*) |
expr_struct(*) | expr_repeat(*) | expr_paren(*) |
expr_inline_asm(*) => {
visit::visit_expr(expr, self, vt);
@ -1141,21 +1141,6 @@ pub impl Liveness {
self.propagate_through_expr(r, succ)
}
expr_swap(l, r) => {
// see comment on lvalues in
// propagate_through_lvalue_components()
// I count swaps as `used` cause it might be something like:
// foo.bar <-> x
// and I am too lazy to distinguish this case from
// y <-> x
// (where both x, y are unused) just for a warning.
let succ = self.write_lvalue(r, succ, ACC_WRITE|ACC_READ|ACC_USE);
let succ = self.write_lvalue(l, succ, ACC_WRITE|ACC_READ|ACC_USE);
let succ = self.propagate_through_lvalue_components(r, succ);
self.propagate_through_lvalue_components(l, succ)
}
expr_assign_op(_, l, r) => {
// see comment on lvalues in
// propagate_through_lvalue_components()
@ -1533,7 +1518,7 @@ fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) {
expr_vstore(*) | expr_vec(*) | expr_tup(*) | expr_log(*) |
expr_binary(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) |
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
expr_again(*) | expr_lit(_) | expr_block(*) | expr_swap(*) |
expr_again(*) | expr_lit(_) | expr_block(*) |
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
expr_paren(*) => {
visit::visit_expr(expr, self, vt);

View File

@ -413,7 +413,7 @@ pub impl mem_categorization_ctxt {
ast::expr_paren(e) => self.cat_expr_unadjusted(e),
ast::expr_addr_of(*) | ast::expr_call(*) | ast::expr_swap(*) |
ast::expr_addr_of(*) | ast::expr_call(*) |
ast::expr_assign(*) | ast::expr_assign_op(*) |
ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) |
ast::expr_do_body(*) | ast::expr_unary(*) |

View File

@ -650,11 +650,6 @@ pub impl VisitContext {
self.consume_expr(count, visitor);
}
expr_swap(lhs, rhs) => {
self.use_expr(lhs, Read, visitor);
self.use_expr(rhs, Read, visitor);
}
expr_loop_body(base) |
expr_do_body(base) => {
self.use_expr(base, comp_mode, visitor);

View File

@ -528,33 +528,6 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
return src_datum.store_to_datum(
bcx, src.id, DROP_EXISTING, dst_datum);
}
ast::expr_swap(dst, src) => {
let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst));
let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src));
// If the source and destination are the same, then don't swap.
// Avoids performing an overlapping memcpy
let dst_datum_ref = dst_datum.to_ref_llval(bcx);
let src_datum_ref = src_datum.to_ref_llval(bcx);
let cmp = ICmp(bcx, lib::llvm::IntEQ,
src_datum_ref,
dst_datum_ref);
let swap_cx = base::sub_block(bcx, "swap");
let next_cx = base::sub_block(bcx, "next");
CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb);
let scratch = scratch_datum(swap_cx, dst_datum.ty, false);
let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch);
let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum);
let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum);
Br(swap_cx, next_cx.llbb);
return next_cx;
}
ast::expr_assign_op(op, dst, src) => {
return trans_assign_op(bcx, expr, op, dst, src);
}

View File

@ -314,7 +314,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
}
}
}
expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) |
expr_assign(val, _) | expr_assign_op(_, val, _) |
expr_ret(Some(val)) => {
node_type_needs(cx, use_repr, val.id);
}

View File

@ -3465,7 +3465,6 @@ pub fn expr_kind(tcx: ctxt,
ast::expr_while(*) |
ast::expr_loop(*) |
ast::expr_assign(*) |
ast::expr_swap(*) |
ast::expr_inline_asm(*) |
ast::expr_assign_op(*) => {
RvalueStmtExpr

View File

@ -2460,20 +2460,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_nil(id);
}
}
ast::expr_swap(lhs, rhs) => {
check_assignment(fcx, lhs, rhs, id);
let lhs_ty = fcx.expr_ty(lhs);
let rhs_ty = fcx.expr_ty(rhs);
if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
fcx.write_error(id);
}
else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
fcx.write_bot(id);
}
else {
fcx.write_nil(id);
}
}
ast::expr_if(cond, ref thn, elsopt) => {
check_expr_has_type(fcx, cond, ty::mk_bool());
check_then_else(fcx, thn, elsopt, id, expr.span);

View File

@ -1016,7 +1016,6 @@ pub mod guarantor {
ast::expr_while(*) |
ast::expr_loop(*) |
ast::expr_assign(*) |
ast::expr_swap(*) |
ast::expr_assign_op(*) |
ast::expr_cast(*) |
ast::expr_call(*) |

View File

@ -96,10 +96,6 @@ fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
match expr.node {
ast::expr_assign(*) |
ast::expr_assign_op(*) |
ast::expr_swap(*) => {
pprust::print_stmt(pp, *stmt);
writer.write_line(~"");
}
_ => {}
}
}

View File

@ -569,7 +569,6 @@ pub enum expr_ {
expr_copy(@expr),
expr_assign(@expr, @expr),
expr_swap(@expr, @expr),
expr_assign_op(binop, @expr, @expr),
expr_field(@expr, ident, ~[@Ty]),
expr_index(@expr, @expr),

View File

@ -511,9 +511,6 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
expr_assign(el, er) => {
expr_assign(fld.fold_expr(el), fld.fold_expr(er))
}
expr_swap(el, er) => {
expr_swap(fld.fold_expr(el), fld.fold_expr(er))
}
expr_assign_op(op, el, er) => {
expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
}

View File

@ -40,6 +40,7 @@ pub enum ObsoleteSyntax {
ObsoleteModeInFnType,
ObsoleteMoveInit,
ObsoleteBinaryMove,
ObsoleteSwap,
ObsoleteUnsafeBlock,
ObsoleteUnenforcedBound,
ObsoleteImplSyntax,
@ -129,6 +130,10 @@ pub impl Parser {
"binary move",
"Write `foo = move bar` instead"
),
ObsoleteSwap => (
"swap",
"Use core::util::{swap, replace} instead"
),
ObsoleteUnsafeBlock => (
"non-standalone unsafe block",
"use an inner `unsafe { ... }` block instead"

View File

@ -26,7 +26,7 @@ use ast::{expr_break, expr_call, expr_cast, expr_copy, expr_do_body};
use ast::{expr_field, expr_fn_block, expr_if, expr_index};
use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
use ast::{expr_ret, expr_struct, expr_tup, expr_unary};
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
use ast::{expr_vstore_slice, expr_vstore_box};
use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
@ -70,7 +70,7 @@ use parse::lexer::reader;
use parse::lexer::TokenAndSpan;
use parse::obsolete::{ObsoleteClassTraits};
use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove};
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
@ -1849,9 +1849,11 @@ pub impl Parser {
expr_break(None))
}
token::DARROW => {
self.obsolete(*self.span, ObsoleteSwap);
self.bump();
let rhs = self.parse_expr();
self.mk_expr(lo, rhs.span.hi, expr_swap(lhs, rhs))
// Ignore what we get, this is an error anyway
self.parse_expr();
self.mk_expr(lo, self.span.hi, expr_break(None))
}
_ => {
lhs

View File

@ -1328,12 +1328,6 @@ pub fn print_expr(s: @ps, expr: @ast::expr) {
word_space(s, ~"=");
print_expr(s, rhs);
}
ast::expr_swap(lhs, rhs) => {
print_expr(s, lhs);
space(s.s);
word_space(s, ~"<->");
print_expr(s, rhs);
}
ast::expr_assign_op(op, lhs, rhs) => {
print_expr(s, lhs);
space(s.s);

View File

@ -516,10 +516,6 @@ pub fn visit_expr<E: Copy>(ex: @expr, e: E, v: vt<E>) {
(v.visit_expr)(a, e, v);
}
expr_copy(a) => (v.visit_expr)(a, e, v),
expr_swap(a, b) => {
(v.visit_expr)(a, e, v);
(v.visit_expr)(b, e, v);
}
expr_assign_op(_, a, b) => {
(v.visit_expr)(b, e, v);
(v.visit_expr)(a, e, v);