Remove the '<->' operator from the language
This commit is contained in:
parent
998fececd6
commit
63c7e2f991
31
doc/rust.md
31
doc/rust.md
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(*) |
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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(*) |
|
||||
|
@ -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(~"");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user