mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-22 04:34:51 +00:00
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
|
#### Assignment expressions
|
||||||
|
|
||||||
An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
|
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.
|
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 {
|
match expr.node {
|
||||||
ast::expr_swap(l, r) => {
|
|
||||||
self.check_assignment(l);
|
|
||||||
self.check_assignment(r);
|
|
||||||
}
|
|
||||||
ast::expr_assign(dest, _) |
|
ast::expr_assign(dest, _) |
|
||||||
ast::expr_assign_op(_, dest, _) => {
|
ast::expr_assign_op(_, dest, _) => {
|
||||||
self.check_assignment(dest);
|
self.check_assignment(dest);
|
||||||
|
@ -698,11 +698,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
|
|||||||
self.walk_expr(l, in_out, loop_scopes);
|
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, _) => {
|
ast::expr_vec(ref exprs, _) => {
|
||||||
self.walk_exprs(*exprs, in_out, loop_scopes)
|
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_binary(*) | expr_addr_of(*) | expr_copy(*) | expr_loop_body(*) |
|
||||||
expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
|
expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
|
||||||
expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) |
|
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_struct(*) | expr_repeat(*) | expr_paren(*) |
|
||||||
expr_inline_asm(*) => {
|
expr_inline_asm(*) => {
|
||||||
visit::visit_expr(expr, self, vt);
|
visit::visit_expr(expr, self, vt);
|
||||||
@ -1141,21 +1141,6 @@ pub impl Liveness {
|
|||||||
self.propagate_through_expr(r, succ)
|
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) => {
|
expr_assign_op(_, l, r) => {
|
||||||
// see comment on lvalues in
|
// see comment on lvalues in
|
||||||
// propagate_through_lvalue_components()
|
// 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_vstore(*) | expr_vec(*) | expr_tup(*) | expr_log(*) |
|
||||||
expr_binary(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) |
|
expr_binary(*) | expr_copy(*) | expr_loop_body(*) | expr_do_body(*) |
|
||||||
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
|
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_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |
|
||||||
expr_paren(*) => {
|
expr_paren(*) => {
|
||||||
visit::visit_expr(expr, self, vt);
|
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_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_assign(*) | ast::expr_assign_op(*) |
|
||||||
ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) |
|
ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) |
|
||||||
ast::expr_do_body(*) | ast::expr_unary(*) |
|
ast::expr_do_body(*) | ast::expr_unary(*) |
|
||||||
|
@ -650,11 +650,6 @@ pub impl VisitContext {
|
|||||||
self.consume_expr(count, visitor);
|
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_loop_body(base) |
|
||||||
expr_do_body(base) => {
|
expr_do_body(base) => {
|
||||||
self.use_expr(base, comp_mode, visitor);
|
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(
|
return src_datum.store_to_datum(
|
||||||
bcx, src.id, DROP_EXISTING, dst_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) => {
|
ast::expr_assign_op(op, dst, src) => {
|
||||||
return trans_assign_op(bcx, expr, 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)) => {
|
expr_ret(Some(val)) => {
|
||||||
node_type_needs(cx, use_repr, val.id);
|
node_type_needs(cx, use_repr, val.id);
|
||||||
}
|
}
|
||||||
|
@ -3465,7 +3465,6 @@ pub fn expr_kind(tcx: ctxt,
|
|||||||
ast::expr_while(*) |
|
ast::expr_while(*) |
|
||||||
ast::expr_loop(*) |
|
ast::expr_loop(*) |
|
||||||
ast::expr_assign(*) |
|
ast::expr_assign(*) |
|
||||||
ast::expr_swap(*) |
|
|
||||||
ast::expr_inline_asm(*) |
|
ast::expr_inline_asm(*) |
|
||||||
ast::expr_assign_op(*) => {
|
ast::expr_assign_op(*) => {
|
||||||
RvalueStmtExpr
|
RvalueStmtExpr
|
||||||
|
@ -2460,20 +2460,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
|||||||
fcx.write_nil(id);
|
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) => {
|
ast::expr_if(cond, ref thn, elsopt) => {
|
||||||
check_expr_has_type(fcx, cond, ty::mk_bool());
|
check_expr_has_type(fcx, cond, ty::mk_bool());
|
||||||
check_then_else(fcx, thn, elsopt, id, expr.span);
|
check_then_else(fcx, thn, elsopt, id, expr.span);
|
||||||
|
@ -1016,7 +1016,6 @@ pub mod guarantor {
|
|||||||
ast::expr_while(*) |
|
ast::expr_while(*) |
|
||||||
ast::expr_loop(*) |
|
ast::expr_loop(*) |
|
||||||
ast::expr_assign(*) |
|
ast::expr_assign(*) |
|
||||||
ast::expr_swap(*) |
|
|
||||||
ast::expr_assign_op(*) |
|
ast::expr_assign_op(*) |
|
||||||
ast::expr_cast(*) |
|
ast::expr_cast(*) |
|
||||||
ast::expr_call(*) |
|
ast::expr_call(*) |
|
||||||
|
@ -96,10 +96,6 @@ fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
|
|||||||
match expr.node {
|
match expr.node {
|
||||||
ast::expr_assign(*) |
|
ast::expr_assign(*) |
|
||||||
ast::expr_assign_op(*) |
|
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_copy(@expr),
|
||||||
expr_assign(@expr, @expr),
|
expr_assign(@expr, @expr),
|
||||||
expr_swap(@expr, @expr),
|
|
||||||
expr_assign_op(binop, @expr, @expr),
|
expr_assign_op(binop, @expr, @expr),
|
||||||
expr_field(@expr, ident, ~[@Ty]),
|
expr_field(@expr, ident, ~[@Ty]),
|
||||||
expr_index(@expr, @expr),
|
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(el, er) => {
|
||||||
expr_assign(fld.fold_expr(el), fld.fold_expr(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, el, er) => {
|
||||||
expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
|
expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ pub enum ObsoleteSyntax {
|
|||||||
ObsoleteModeInFnType,
|
ObsoleteModeInFnType,
|
||||||
ObsoleteMoveInit,
|
ObsoleteMoveInit,
|
||||||
ObsoleteBinaryMove,
|
ObsoleteBinaryMove,
|
||||||
|
ObsoleteSwap,
|
||||||
ObsoleteUnsafeBlock,
|
ObsoleteUnsafeBlock,
|
||||||
ObsoleteUnenforcedBound,
|
ObsoleteUnenforcedBound,
|
||||||
ObsoleteImplSyntax,
|
ObsoleteImplSyntax,
|
||||||
@ -129,6 +130,10 @@ pub impl Parser {
|
|||||||
"binary move",
|
"binary move",
|
||||||
"Write `foo = move bar` instead"
|
"Write `foo = move bar` instead"
|
||||||
),
|
),
|
||||||
|
ObsoleteSwap => (
|
||||||
|
"swap",
|
||||||
|
"Use core::util::{swap, replace} instead"
|
||||||
|
),
|
||||||
ObsoleteUnsafeBlock => (
|
ObsoleteUnsafeBlock => (
|
||||||
"non-standalone unsafe block",
|
"non-standalone unsafe block",
|
||||||
"use an inner `unsafe { ... }` block instead"
|
"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_field, expr_fn_block, expr_if, expr_index};
|
||||||
use ast::{expr_lit, expr_log, expr_loop, expr_loop_body, expr_mac};
|
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_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_vec, expr_vstore, expr_vstore_mut_box};
|
||||||
use ast::{expr_vstore_slice, expr_vstore_box};
|
use ast::{expr_vstore_slice, expr_vstore_box};
|
||||||
use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
|
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::lexer::TokenAndSpan;
|
||||||
use parse::obsolete::{ObsoleteClassTraits};
|
use parse::obsolete::{ObsoleteClassTraits};
|
||||||
use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
|
use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
|
||||||
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove};
|
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
|
||||||
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
|
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
|
||||||
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
|
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
|
||||||
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
|
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
|
||||||
@ -1849,9 +1849,11 @@ pub impl Parser {
|
|||||||
expr_break(None))
|
expr_break(None))
|
||||||
}
|
}
|
||||||
token::DARROW => {
|
token::DARROW => {
|
||||||
|
self.obsolete(*self.span, ObsoleteSwap);
|
||||||
self.bump();
|
self.bump();
|
||||||
let rhs = self.parse_expr();
|
// Ignore what we get, this is an error anyway
|
||||||
self.mk_expr(lo, rhs.span.hi, expr_swap(lhs, rhs))
|
self.parse_expr();
|
||||||
|
self.mk_expr(lo, self.span.hi, expr_break(None))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
lhs
|
lhs
|
||||||
|
@ -1328,12 +1328,6 @@ pub fn print_expr(s: @ps, expr: @ast::expr) {
|
|||||||
word_space(s, ~"=");
|
word_space(s, ~"=");
|
||||||
print_expr(s, rhs);
|
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) => {
|
ast::expr_assign_op(op, lhs, rhs) => {
|
||||||
print_expr(s, lhs);
|
print_expr(s, lhs);
|
||||||
space(s.s);
|
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);
|
(v.visit_expr)(a, e, v);
|
||||||
}
|
}
|
||||||
expr_copy(a) => (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) => {
|
expr_assign_op(_, a, b) => {
|
||||||
(v.visit_expr)(b, e, v);
|
(v.visit_expr)(b, e, v);
|
||||||
(v.visit_expr)(a, e, v);
|
(v.visit_expr)(a, e, v);
|
||||||
|
Loading…
Reference in New Issue
Block a user