From 14c0a708cc33245d86d48b99d7dc93a6f5b9d20d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 11:34:28 -0500 Subject: [PATCH 01/30] syntax/ast_util: add `is_by_value_binop()` --- src/libsyntax/ast_util.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 7579972c6d8..71ce4847922 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -85,6 +85,16 @@ pub fn is_shift_binop(b: BinOp) -> bool { } } +/// Returns `true` is the binary operator takes its arguments by value +pub fn is_by_value_binop(b: BinOp) -> bool { + match b { + BiAdd | BiSub | BiMul | BiDiv | BiRem | BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => { + true + } + _ => false + } +} + pub fn unop_to_string(op: UnOp) -> &'static str { match op { UnUniq => "box() ", From c3a6d2860cc0448dea8a9918d22b30839d2548c8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 12:23:56 -0500 Subject: [PATCH 02/30] Tell typeck which binops are by value --- src/librustc_typeck/check/mod.rs | 48 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 18a773fb949..2dcb07e0fb5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2904,6 +2904,7 @@ pub fn lookup_tup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, // Controls whether the arguments are automatically referenced. This is useful // for overloaded binary and unary operators. +#[deriving(PartialEq)] pub enum DerefArgs { DontDerefArgs, DoDerefArgs @@ -3130,7 +3131,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, trait_did: Option, lhs: &'a ast::Expr, rhs: Option<&P>, - unbound_method: F) -> Ty<'tcx> where + unbound_method: F, + deref_args: DerefArgs) -> Ty<'tcx> where F: FnOnce(), { let method = match trait_did { @@ -3146,7 +3148,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // traits that don't force left and right to have same // type. let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) => { + ty::ty_rptr(r_in, mt) if deref_args == DoDerefArgs => { let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span)); fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, r_in); let adjusted_ty = ty::mk_rptr(fcx.tcx(), r_adj, mt); @@ -3183,7 +3185,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, method_ty, op_ex, args.as_slice(), - DoDerefArgs, + deref_args, DontTupleArguments) { ty::FnConverging(result_type) => result_type, ty::FnDiverging => ty::mk_err() @@ -3199,7 +3201,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expected_ty, op_ex, args.as_slice(), - DoDerefArgs, + deref_args, DontTupleArguments); ty::mk_err() } @@ -3318,23 +3320,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, rhs: &P) -> Ty<'tcx> { let tcx = fcx.ccx.tcx; let lang = &tcx.lang_items; - let (name, trait_did) = match op { - ast::BiAdd => ("add", lang.add_trait()), - ast::BiSub => ("sub", lang.sub_trait()), - ast::BiMul => ("mul", lang.mul_trait()), - ast::BiDiv => ("div", lang.div_trait()), - ast::BiRem => ("rem", lang.rem_trait()), - ast::BiBitXor => ("bitxor", lang.bitxor_trait()), - ast::BiBitAnd => ("bitand", lang.bitand_trait()), - ast::BiBitOr => ("bitor", lang.bitor_trait()), - ast::BiShl => ("shl", lang.shl_trait()), - ast::BiShr => ("shr", lang.shr_trait()), - ast::BiLt => ("lt", lang.ord_trait()), - ast::BiLe => ("le", lang.ord_trait()), - ast::BiGe => ("ge", lang.ord_trait()), - ast::BiGt => ("gt", lang.ord_trait()), - ast::BiEq => ("eq", lang.eq_trait()), - ast::BiNe => ("ne", lang.eq_trait()), + let (name, trait_did, deref_args) = match op { + ast::BiAdd => ("add", lang.add_trait(), DontDerefArgs), + ast::BiSub => ("sub", lang.sub_trait(), DontDerefArgs), + ast::BiMul => ("mul", lang.mul_trait(), DontDerefArgs), + ast::BiDiv => ("div", lang.div_trait(), DontDerefArgs), + ast::BiRem => ("rem", lang.rem_trait(), DontDerefArgs), + ast::BiBitXor => ("bitxor", lang.bitxor_trait(), DontDerefArgs), + ast::BiBitAnd => ("bitand", lang.bitand_trait(), DontDerefArgs), + ast::BiBitOr => ("bitor", lang.bitor_trait(), DontDerefArgs), + ast::BiShl => ("shl", lang.shl_trait(), DontDerefArgs), + ast::BiShr => ("shr", lang.shr_trait(), DontDerefArgs), + ast::BiLt => ("lt", lang.ord_trait(), DoDerefArgs), + ast::BiLe => ("le", lang.ord_trait(), DoDerefArgs), + ast::BiGe => ("ge", lang.ord_trait(), DoDerefArgs), + ast::BiGt => ("gt", lang.ord_trait(), DoDerefArgs), + ast::BiEq => ("eq", lang.eq_trait(), DoDerefArgs), + ast::BiNe => ("ne", lang.eq_trait(), DoDerefArgs), ast::BiAnd | ast::BiOr => { check_expr(fcx, &**rhs); return ty::mk_err(); @@ -3347,7 +3349,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast_util::binop_to_string(op), actual) }, lhs_resolved_t, None) - }) + }, deref_args) } fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -3363,7 +3365,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) }, rhs_t, None); - }) + }, DontDerefArgs) } // Check field access expressions From f64e52a7f703ecb18cbf7c39bd1479cd99bd20ae Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 13:18:18 -0500 Subject: [PATCH 03/30] Tell trans which binops are by value --- src/librustc_trans/trans/callee.rs | 11 ++++++----- src/librustc_trans/trans/expr.rs | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index b8b2395dde1..bde68981ff4 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -996,10 +996,11 @@ pub enum CallArgs<'a, 'tcx> { // value. ArgVals(&'a [ValueRef]), - // For overloaded operators: `(lhs, Vec(rhs, rhs_id))`. `lhs` + // For overloaded operators: `(lhs, Vec(rhs, rhs_id), autoref)`. `lhs` // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of - // the right-hand-side arguments (if any). - ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>), + // the right-hand-side arguments (if any). `autoref` indicates whether the `rhs` + // arguments should be auto-referenced + ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>, bool), // Supply value of arguments as a list of expressions that must be // translated, for overloaded call operators. @@ -1171,7 +1172,7 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, arg_cleanup_scope, ignore_self) } - ArgOverloadedOp(lhs, rhs) => { + ArgOverloadedOp(lhs, rhs, autoref) => { assert!(!variadic); llargs.push(unpack_result!(bcx, { @@ -1185,7 +1186,7 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, llargs.push(unpack_result!(bcx, { trans_arg_datum(bcx, arg_tys[1], rhs, arg_cleanup_scope, - DoAutorefArg(rhs_id)) + if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }) })); } } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index e1769001942..55672004f14 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -609,7 +609,8 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call, base_datum, args, - Some(SaveIn(scratch.val)))); + Some(SaveIn(scratch.val)), + true)); DatumBlock::new(bcx, scratch.to_expr_datum()) } ast::ExprBox(_, ref contents) => { @@ -762,7 +763,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call, base_datum, vec![(ix_datum, idx.id)], - Some(SaveIn(scratch.val)))); + Some(SaveIn(scratch.val)), + true)); let datum = scratch.to_expr_datum(); if ty::type_is_sized(bcx.tcx(), elt_ty) { Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr) @@ -1092,25 +1094,26 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, callee::ArgExprs(args.as_slice()), dest) } - ast::ExprBinary(_, ref lhs, ref rhs) => { + ast::ExprBinary(op, ref lhs, ref rhs) => { // if not overloaded, would be RvalueDatumExpr let lhs = unpack_datum!(bcx, trans(bcx, &**lhs)); let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs, - vec![(rhs_datum, rhs.id)], Some(dest)).bcx + vec![(rhs_datum, rhs.id)], Some(dest), + !ast_util::is_by_value_binop(op)).bcx } ast::ExprUnary(_, ref subexpr) => { // if not overloaded, would be RvalueDatumExpr let arg = unpack_datum!(bcx, trans(bcx, &**subexpr)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), - arg, Vec::new(), Some(dest)).bcx + arg, Vec::new(), Some(dest), true).bcx } ast::ExprIndex(ref base, ref idx) => { // if not overloaded, would be RvalueDatumExpr let base = unpack_datum!(bcx, trans(bcx, &**base)); let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base, - vec![(idx_datum, idx.id)], Some(dest)).bcx + vec![(idx_datum, idx.id)], Some(dest), true).bcx } ast::ExprCast(ref val, _) => { // DPS output mode means this is a trait cast: @@ -1803,7 +1806,8 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call: MethodCall, lhs: Datum<'tcx, Expr>, rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>, - dest: Option) + dest: Option, + autoref: bool) -> Result<'blk, 'tcx> { let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty; callee::trans_call_inner(bcx, @@ -1815,7 +1819,7 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None, arg_cleanup_scope) }, - callee::ArgOverloadedOp(lhs, rhs), + callee::ArgOverloadedOp(lhs, rhs, autoref), dest) } @@ -2122,7 +2126,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, - datum, Vec::new(), Some(SaveIn(scratch.val)))); + datum, Vec::new(), Some(SaveIn(scratch.val)), + false)); scratch.to_expr_datum() } None => { From 5038f5a70c8fd12703fe5d78b8d04918336e764c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:47:06 -0500 Subject: [PATCH 04/30] Tell expr_use_visitor which binops are by value --- src/librustc/middle/expr_use_visitor.rs | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8e00c96535b..59872c69462 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -30,7 +30,7 @@ use middle::ty::{MethodStatic, MethodStaticUnboxedClosure}; use util::ppaux::Repr; use std::kinds; -use syntax::ast; +use syntax::{ast, ast_util}; use syntax::ptr::P; use syntax::codemap::Span; @@ -438,7 +438,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ast::ExprPath(..) => { } ast::ExprUnary(ast::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &**base, Vec::new()) { + if !self.walk_overloaded_operator(expr, &**base, Vec::new(), None) { self.select_from_expr(&**base); } } @@ -452,7 +452,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) { + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], None) { self.select_from_expr(&**lhs); self.consume_expr(&**rhs); } @@ -465,7 +465,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { (&None, &Some(ref e)) => vec![&**e], (&None, &None) => Vec::new() }; - let overloaded = self.walk_overloaded_operator(expr, &**base, args); + let overloaded = self.walk_overloaded_operator(expr, &**base, args, None); assert!(overloaded); } @@ -570,13 +570,14 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprUnary(_, ref lhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, Vec::new()) { + if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), None) { self.consume_expr(&**lhs); } } - ast::ExprBinary(_, ref lhs, ref rhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) { + ast::ExprBinary(op, ref lhs, ref rhs) => { + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], Some(op)) + { self.consume_expr(&**lhs); self.consume_expr(&**rhs); } @@ -911,13 +912,24 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { fn walk_overloaded_operator(&mut self, expr: &ast::Expr, receiver: &ast::Expr, - rhs: Vec<&ast::Expr>) + rhs: Vec<&ast::Expr>, + binop: Option) -> bool { if !self.typer.is_method_call(expr.id) { return false; } + match binop { + Some(binop) if ast_util::is_by_value_binop(binop) => { + self.consume_expr(receiver); + self.consume_expr(rhs[0]); + + return true; + }, + _ => {}, + } + self.walk_expr(receiver); // Arguments (but not receivers) to overloaded operator From 227435a11eb3bf06049b2420ce648b238decfcd5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 15:34:36 -0500 Subject: [PATCH 05/30] Tell regionck which binops are by value --- src/librustc_typeck/check/regionck.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index cadcee43b44..3e7992b3cba 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -131,7 +131,7 @@ use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; use util::ppaux::{ty_to_string, Repr}; -use syntax::ast; +use syntax::{ast, ast_util}; use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; @@ -637,14 +637,22 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { visit::walk_expr(rcx, expr); } - ast::ExprIndex(ref lhs, ref rhs) | - ast::ExprBinary(_, ref lhs, ref rhs) if has_method_map => { + ast::ExprIndex(ref lhs, ref rhs) if has_method_map => { + constrain_call(rcx, expr, Some(&**lhs), + Some(&**rhs).into_iter(), true); + + visit::walk_expr(rcx, expr); + }, + + ast::ExprBinary(op, ref lhs, ref rhs) if has_method_map => { + let implicitly_ref_args = !ast_util::is_by_value_binop(op); + // As `expr_method_call`, but the call is via an // overloaded op. Note that we (sadly) currently use an // implicit "by ref" sort of passing style here. This // should be converted to an adjustment! constrain_call(rcx, expr, Some(&**lhs), - Some(&**rhs).into_iter(), true); + Some(&**rhs).into_iter(), implicitly_ref_args); visit::walk_expr(rcx, expr); } From c73259a269c11ba9cb2917f9459204b7dcaa9646 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 13:00:23 -0500 Subject: [PATCH 06/30] libcore: convert binop traits to by value --- src/libcore/ops.rs | 437 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index ebe46af5169..d283d70815c 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -103,12 +103,16 @@ pub trait Drop { /// Foo + Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="add"] pub trait Add for Sized? { /// The method for the `+` operator fn add(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! add_impl( ($($t:ty)*) => ($( impl Add<$t, $t> for $t { @@ -118,6 +122,44 @@ macro_rules! add_impl( )*) ) +/// The `Add` trait is used to specify the functionality of `+`. +/// +/// # Example +/// +/// A trivial implementation of `Add`. When `Foo + Foo` happens, it ends up +/// calling `add`, and therefore, `main` prints `Adding!`. +/// +/// ```rust +/// struct Foo; +/// +/// impl Add for Foo { +/// fn add(&self, _rhs: &Foo) -> Foo { +/// println!("Adding!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo + Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="add"] +pub trait Add { + /// The method for the `+` operator + fn add(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! add_impl( + ($($t:ty)*) => ($( + impl Add<$t, $t> for $t { + #[inline] + fn add(self, other: $t) -> $t { self + other } + } + )*) +) + add_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// The `Sub` trait is used to specify the functionality of `-`. @@ -143,12 +185,16 @@ add_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// Foo - Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="sub"] pub trait Sub for Sized? { /// The method for the `-` operator fn sub(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! sub_impl( ($($t:ty)*) => ($( impl Sub<$t, $t> for $t { @@ -158,6 +204,44 @@ macro_rules! sub_impl( )*) ) +/// The `Sub` trait is used to specify the functionality of `-`. +/// +/// # Example +/// +/// A trivial implementation of `Sub`. When `Foo - Foo` happens, it ends up +/// calling `sub`, and therefore, `main` prints `Subtracting!`. +/// +/// ```rust +/// struct Foo; +/// +/// impl Sub for Foo { +/// fn sub(&self, _rhs: &Foo) -> Foo { +/// println!("Subtracting!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo - Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="sub"] +pub trait Sub { + /// The method for the `-` operator + fn sub(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! sub_impl( + ($($t:ty)*) => ($( + impl Sub<$t, $t> for $t { + #[inline] + fn sub(self, other: $t) -> $t { self - other } + } + )*) +) + sub_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// The `Mul` trait is used to specify the functionality of `*`. @@ -183,12 +267,16 @@ sub_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// Foo * Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="mul"] pub trait Mul for Sized? { /// The method for the `*` operator fn mul(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! mul_impl( ($($t:ty)*) => ($( impl Mul<$t, $t> for $t { @@ -198,6 +286,44 @@ macro_rules! mul_impl( )*) ) +/// The `Mul` trait is used to specify the functionality of `*`. +/// +/// # Example +/// +/// A trivial implementation of `Mul`. When `Foo * Foo` happens, it ends up +/// calling `mul`, and therefore, `main` prints `Multiplying!`. +/// +/// ```rust +/// struct Foo; +/// +/// impl Mul for Foo { +/// fn mul(&self, _rhs: &Foo) -> Foo { +/// println!("Multiplying!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo * Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="mul"] +pub trait Mul { + /// The method for the `*` operator + fn mul(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! mul_impl( + ($($t:ty)*) => ($( + impl Mul<$t, $t> for $t { + #[inline] + fn mul(self, other: $t) -> $t { self * other } + } + )*) +) + mul_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// The `Div` trait is used to specify the functionality of `/`. @@ -223,12 +349,16 @@ mul_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// Foo / Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="div"] pub trait Div for Sized? { /// The method for the `/` operator fn div(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! div_impl( ($($t:ty)*) => ($( impl Div<$t, $t> for $t { @@ -238,6 +368,44 @@ macro_rules! div_impl( )*) ) +/// The `Div` trait is used to specify the functionality of `/`. +/// +/// # Example +/// +/// A trivial implementation of `Div`. When `Foo / Foo` happens, it ends up +/// calling `div`, and therefore, `main` prints `Dividing!`. +/// +/// ``` +/// struct Foo; +/// +/// impl Div for Foo { +/// fn div(&self, _rhs: &Foo) -> Foo { +/// println!("Dividing!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo / Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="div"] +pub trait Div { + /// The method for the `/` operator + fn div(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! div_impl( + ($($t:ty)*) => ($( + impl Div<$t, $t> for $t { + #[inline] + fn div(self, other: $t) -> $t { self / other } + } + )*) +) + div_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// The `Rem` trait is used to specify the functionality of `%`. @@ -263,12 +431,16 @@ div_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) /// Foo % Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="rem"] pub trait Rem for Sized? { /// The method for the `%` operator fn rem(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! rem_impl( ($($t:ty)*) => ($( impl Rem<$t, $t> for $t { @@ -278,6 +450,8 @@ macro_rules! rem_impl( )*) ) +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! rem_float_impl( ($t:ty, $fmod:ident) => { impl Rem<$t, $t> for $t { @@ -290,6 +464,57 @@ macro_rules! rem_float_impl( } ) +/// The `Rem` trait is used to specify the functionality of `%`. +/// +/// # Example +/// +/// A trivial implementation of `Rem`. When `Foo % Foo` happens, it ends up +/// calling `rem`, and therefore, `main` prints `Remainder-ing!`. +/// +/// ``` +/// struct Foo; +/// +/// impl Rem for Foo { +/// fn rem(&self, _rhs: &Foo) -> Foo { +/// println!("Remainder-ing!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo % Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="rem"] +pub trait Rem { + /// The method for the `%` operator + fn rem(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! rem_impl( + ($($t:ty)*) => ($( + impl Rem<$t, $t> for $t { + #[inline] + fn rem(self, other: $t) -> $t { self % other } + } + )*) +) + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! rem_float_impl( + ($t:ty, $fmod:ident) => { + impl Rem<$t, $t> for $t { + #[inline] + fn rem(self, other: $t) -> $t { + extern { fn $fmod(a: $t, b: $t) -> $t; } + unsafe { $fmod(self, other) } + } + } + } +) + rem_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) rem_float_impl!(f32, fmodf) rem_float_impl!(f64, fmod) @@ -414,12 +639,16 @@ not_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// Foo & Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="bitand"] pub trait BitAnd for Sized? { /// The method for the `&` operator fn bitand(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! bitand_impl( ($($t:ty)*) => ($( impl BitAnd<$t, $t> for $t { @@ -429,6 +658,44 @@ macro_rules! bitand_impl( )*) ) +/// The `BitAnd` trait is used to specify the functionality of `&`. +/// +/// # Example +/// +/// A trivial implementation of `BitAnd`. When `Foo & Foo` happens, it ends up +/// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`. +/// +/// ``` +/// struct Foo; +/// +/// impl BitAnd for Foo { +/// fn bitand(&self, _rhs: &Foo) -> Foo { +/// println!("Bitwise And-ing!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo & Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="bitand"] +pub trait BitAnd { + /// The method for the `&` operator + fn bitand(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! bitand_impl( + ($($t:ty)*) => ($( + impl BitAnd<$t, $t> for $t { + #[inline] + fn bitand(self, rhs: $t) -> $t { self & rhs } + } + )*) +) + bitand_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// The `BitOr` trait is used to specify the functionality of `|`. @@ -454,12 +721,16 @@ bitand_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// Foo | Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="bitor"] pub trait BitOr for Sized? { /// The method for the `|` operator fn bitor(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! bitor_impl( ($($t:ty)*) => ($( impl BitOr<$t,$t> for $t { @@ -469,6 +740,44 @@ macro_rules! bitor_impl( )*) ) +/// The `BitOr` trait is used to specify the functionality of `|`. +/// +/// # Example +/// +/// A trivial implementation of `BitOr`. When `Foo | Foo` happens, it ends up +/// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`. +/// +/// ``` +/// struct Foo; +/// +/// impl BitOr for Foo { +/// fn bitor(&self, _rhs: &Foo) -> Foo { +/// println!("Bitwise Or-ing!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo | Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="bitor"] +pub trait BitOr { + /// The method for the `|` operator + fn bitor(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! bitor_impl( + ($($t:ty)*) => ($( + impl BitOr<$t,$t> for $t { + #[inline] + fn bitor(self, rhs: $t) -> $t { self | rhs } + } + )*) +) + bitor_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// The `BitXor` trait is used to specify the functionality of `^`. @@ -494,12 +803,16 @@ bitor_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// Foo ^ Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="bitxor"] pub trait BitXor for Sized? { /// The method for the `^` operator fn bitxor(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! bitxor_impl( ($($t:ty)*) => ($( impl BitXor<$t, $t> for $t { @@ -509,6 +822,44 @@ macro_rules! bitxor_impl( )*) ) +/// The `BitXor` trait is used to specify the functionality of `^`. +/// +/// # Example +/// +/// A trivial implementation of `BitXor`. When `Foo ^ Foo` happens, it ends up +/// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`. +/// +/// ``` +/// struct Foo; +/// +/// impl BitXor for Foo { +/// fn bitxor(&self, _rhs: &Foo) -> Foo { +/// println!("Bitwise Xor-ing!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo ^ Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="bitxor"] +pub trait BitXor { + /// The method for the `^` operator + fn bitxor(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! bitxor_impl( + ($($t:ty)*) => ($( + impl BitXor<$t, $t> for $t { + #[inline] + fn bitxor(self, other: $t) -> $t { self ^ other } + } + )*) +) + bitxor_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// The `Shl` trait is used to specify the functionality of `<<`. @@ -534,12 +885,16 @@ bitxor_impl!(bool uint u8 u16 u32 u64 int i8 i16 i32 i64) /// Foo << Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="shl"] pub trait Shl for Sized? { /// The method for the `<<` operator fn shl(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! shl_impl( ($($t:ty)*) => ($( impl Shl for $t { @@ -551,6 +906,46 @@ macro_rules! shl_impl( )*) ) +/// The `Shl` trait is used to specify the functionality of `<<`. +/// +/// # Example +/// +/// A trivial implementation of `Shl`. When `Foo << Foo` happens, it ends up +/// calling `shl`, and therefore, `main` prints `Shifting left!`. +/// +/// ``` +/// struct Foo; +/// +/// impl Shl for Foo { +/// fn shl(&self, _rhs: &Foo) -> Foo { +/// println!("Shifting left!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo << Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="shl"] +pub trait Shl { + /// The method for the `<<` operator + fn shl(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! shl_impl( + ($($t:ty)*) => ($( + impl Shl for $t { + #[inline] + fn shl(self, other: uint) -> $t { + self << other + } + } + )*) +) + shl_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) /// The `Shr` trait is used to specify the functionality of `>>`. @@ -576,12 +971,16 @@ shl_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) /// Foo >> Foo; /// } /// ``` +// NOTE(stage0): Remove trait after a snapshot +#[cfg(stage0)] #[lang="shr"] pub trait Shr for Sized? { /// The method for the `>>` operator fn shr(&self, rhs: &RHS) -> Result; } +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! shr_impl( ($($t:ty)*) => ($( impl Shr for $t { @@ -591,6 +990,44 @@ macro_rules! shr_impl( )*) ) +/// The `Shr` trait is used to specify the functionality of `>>`. +/// +/// # Example +/// +/// A trivial implementation of `Shr`. When `Foo >> Foo` happens, it ends up +/// calling `shr`, and therefore, `main` prints `Shifting right!`. +/// +/// ``` +/// struct Foo; +/// +/// impl Shr for Foo { +/// fn shr(&self, _rhs: &Foo) -> Foo { +/// println!("Shifting right!"); +/// *self +/// } +/// } +/// +/// fn main() { +/// Foo >> Foo; +/// } +/// ``` +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[lang="shr"] +pub trait Shr { + /// The method for the `>>` operator + fn shr(self, rhs: RHS) -> Result; +} + +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +macro_rules! shr_impl( + ($($t:ty)*) => ($( + impl Shr for $t { + #[inline] + fn shr(self, other: uint) -> $t { self >> other } + } + )*) +) + shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) /// The `Index` trait is used to specify the functionality of indexing operations From 65d3a40c07d1efae8039d3341a07ac748063fc79 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 15:52:17 -0500 Subject: [PATCH 07/30] libcore: fix move semantics fallout --- src/libcore/iter.rs | 2 +- src/libcore/num/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 8ee2a8874bb..5405c7aa3b7 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2166,7 +2166,7 @@ impl + Clone> Iterator for Counter { #[inline] fn next(&mut self) -> Option { let result = self.state.clone(); - self.state = self.state + self.step; + self.state = self.state.clone() + self.step.clone(); Some(result) } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 3c9b68b350b..2416cf5bcc7 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -37,8 +37,8 @@ use str::{FromStr, from_str, StrPrelude}; /// Simultaneous division and remainder #[inline] #[deprecated = "use division and remainder directly"] -pub fn div_rem + Rem>(x: T, y: T) -> (T, T) { - (x / y, x % y) +pub fn div_rem + Rem>(x: T, y: T) -> (T, T) { + (x.clone() / y.clone(), x % y) } /// Raises a `base` to the power of `exp`, using exponentiation by squaring. From dbc7e17cce0344b774c2ad45066f84d29ce972e9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:01:15 -0500 Subject: [PATCH 08/30] libcollections: Vec + &[T] --- src/libcollections/vec.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 2ed8686394c..56cfa19e887 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1273,6 +1273,8 @@ impl AsSlice for Vec { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl> Add> for Vec { #[inline] fn add(&self, rhs: &V) -> Vec { @@ -1283,6 +1285,16 @@ impl> Add> for Vec { } } + +#[cfg(not(stage0))] // NOTE(stage0): Remove impl after a snapshot +impl<'a, T: Clone> Add<&'a [T], Vec> for Vec { + #[inline] + fn add(mut self, rhs: &[T]) -> Vec { + self.push_all(rhs); + self + } +} + #[unsafe_destructor] impl Drop for Vec { fn drop(&mut self) { From 076e932fd5c6deb1a71e73f46f700743e0b9746c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:08:56 -0500 Subject: [PATCH 09/30] libcollections: String + &str --- src/libcollections/string.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index c4659f86680..cefdabac097 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -855,6 +855,8 @@ impl<'a, S: Str> Equiv for String { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] #[experimental = "waiting on Add stabilization"] impl Add for String { fn add(&self, other: &S) -> String { @@ -864,6 +866,14 @@ impl Add for String { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a> Add<&'a str, String> for String { + fn add(mut self, other: &str) -> String { + self.push_str(other); + self + } +} + impl ops::Slice for String { #[inline] fn as_slice_<'a>(&'a self) -> &'a str { From baf79d4a118c42f9ac0a7df3ff9b566d1450140d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:10:04 -0500 Subject: [PATCH 10/30] libcollections: make `EnumSet` binops by value --- src/libcollections/enum_set.rs | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index d8dc1f36e05..4df1be1bb35 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -183,30 +183,66 @@ impl EnumSet { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub, EnumSet> for EnumSet { fn sub(&self, e: &EnumSet) -> EnumSet { EnumSet {bits: self.bits & !e.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Sub, EnumSet> for EnumSet { + fn sub(self, e: EnumSet) -> EnumSet { + EnumSet {bits: self.bits & !e.bits} + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitOr, EnumSet> for EnumSet { fn bitor(&self, e: &EnumSet) -> EnumSet { EnumSet {bits: self.bits | e.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl BitOr, EnumSet> for EnumSet { + fn bitor(self, e: EnumSet) -> EnumSet { + EnumSet {bits: self.bits | e.bits} + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitAnd, EnumSet> for EnumSet { fn bitand(&self, e: &EnumSet) -> EnumSet { EnumSet {bits: self.bits & e.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl BitAnd, EnumSet> for EnumSet { + fn bitand(self, e: EnumSet) -> EnumSet { + EnumSet {bits: self.bits & e.bits} + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitXor, EnumSet> for EnumSet { fn bitxor(&self, e: &EnumSet) -> EnumSet { EnumSet {bits: self.bits ^ e.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl BitXor, EnumSet> for EnumSet { + fn bitxor(self, e: EnumSet) -> EnumSet { + EnumSet {bits: self.bits ^ e.bits} + } +} + /// An iterator over an EnumSet pub struct Items { index: uint, From 32168faf9f7a9e634647b86c1a671ae68dbe9c9d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:29:47 -0500 Subject: [PATCH 11/30] libstd: convert `BitFlags` binops to by value --- src/libstd/bitflags.rs | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index ffcd6505dad..38bb32ea775 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -209,6 +209,8 @@ macro_rules! bitflags { } } + // NOTE(stage0): Remove impl after a snapshot + #[cfg(stage0)] impl BitOr<$BitFlags, $BitFlags> for $BitFlags { /// Returns the union of the two sets of flags. #[inline] @@ -217,6 +219,17 @@ macro_rules! bitflags { } } + #[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot + impl BitOr<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + // NOTE(stage0): Remove impl after a snapshot + #[cfg(stage0)] impl BitXor<$BitFlags, $BitFlags> for $BitFlags { /// Returns the left flags, but with all the right flags toggled. #[inline] @@ -225,6 +238,17 @@ macro_rules! bitflags { } } + #[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot + impl BitXor<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + // NOTE(stage0): Remove impl after a snapshot + #[cfg(stage0)] impl BitAnd<$BitFlags, $BitFlags> for $BitFlags { /// Returns the intersection between the two sets of flags. #[inline] @@ -233,6 +257,17 @@ macro_rules! bitflags { } } + #[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot + impl BitAnd<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + // NOTE(stage0): Remove impl after a snapshot + #[cfg(stage0)] impl Sub<$BitFlags, $BitFlags> for $BitFlags { /// Returns the set difference of the two sets of flags. #[inline] @@ -241,6 +276,15 @@ macro_rules! bitflags { } } + #[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot + impl Sub<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + impl Not<$BitFlags> for $BitFlags { /// Returns the complement of this set of flags. #[inline] From 9126a24e423a8339230f1dde7e36f79faaeaa9d3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:32:36 -0500 Subject: [PATCH 12/30] libstd: convert `Duration` binops to by value --- src/libstd/time/duration.rs | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 34a3d6aa275..f98cebd9675 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -276,6 +276,8 @@ impl Neg for Duration { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Add for Duration { fn add(&self, rhs: &Duration) -> Duration { let mut secs = self.secs + rhs.secs; @@ -288,6 +290,21 @@ impl Add for Duration { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Add for Duration { + fn add(self, rhs: Duration) -> Duration { + let mut secs = self.secs + rhs.secs; + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub for Duration { fn sub(&self, rhs: &Duration) -> Duration { let mut secs = self.secs - rhs.secs; @@ -300,6 +317,21 @@ impl Sub for Duration { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Sub for Duration { + fn sub(self, rhs: Duration) -> Duration { + let mut secs = self.secs - rhs.secs; + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Mul for Duration { fn mul(&self, rhs: &i32) -> Duration { // Multiply nanoseconds as i64, because it cannot overflow that way. @@ -310,6 +342,19 @@ impl Mul for Duration { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Mul for Duration { + fn mul(self, rhs: i32) -> Duration { + // Multiply nanoseconds as i64, because it cannot overflow that way. + let total_nanos = self.nanos as i64 * rhs as i64; + let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); + let secs = self.secs * rhs as i64 + extra_secs; + Duration { secs: secs, nanos: nanos as i32 } + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Div for Duration { fn div(&self, rhs: &i32) -> Duration { let mut secs = self.secs / *rhs as i64; @@ -328,6 +373,25 @@ impl Div for Duration { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Div for Duration { + fn div(self, rhs: i32) -> Duration { + let mut secs = self.secs / rhs as i64; + let carry = self.secs - secs * rhs as i64; + let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; + let mut nanos = self.nanos / rhs + extra_nanos as i32; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + impl fmt::Show for Duration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // technically speaking, negative duration is not valid ISO 8601, From b5537fa838112192f0ed1f1593c574fe621497a6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:54:31 -0500 Subject: [PATCH 13/30] libtime: convert `Timespec` binops to by value --- src/libtime/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index e293c547944..4129086e9ec 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -99,6 +99,8 @@ impl Timespec { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Add for Timespec { fn add(&self, other: &Duration) -> Timespec { let d_sec = other.num_seconds(); @@ -119,6 +121,29 @@ impl Add for Timespec { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Add for Timespec { + fn add(self, other: Duration) -> Timespec { + let d_sec = other.num_seconds(); + // It is safe to unwrap the nanoseconds, because there cannot be + // more than one second left, which fits in i64 and in i32. + let d_nsec = (other - Duration::seconds(d_sec)) + .num_nanoseconds().unwrap() as i32; + let mut sec = self.sec + d_sec; + let mut nsec = self.nsec + d_nsec; + if nsec >= NSEC_PER_SEC { + nsec -= NSEC_PER_SEC; + sec += 1; + } else if nsec < 0 { + nsec += NSEC_PER_SEC; + sec -= 1; + } + Timespec::new(sec, nsec) + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub for Timespec { fn sub(&self, other: &Timespec) -> Duration { let sec = self.sec - other.sec; @@ -127,6 +152,15 @@ impl Sub for Timespec { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Sub for Timespec { + fn sub(self, other: Timespec) -> Duration { + let sec = self.sec - other.sec; + let nsec = self.nsec - other.nsec; + Duration::seconds(sec) + Duration::nanoseconds(nsec as i64) + } +} + /// Returns the current time as a `timespec` containing the seconds and /// nanoseconds since 1970-01-01T00:00:00Z. pub fn get_time() -> Timespec { From 265b89abde76f7e0555712d7c9056c6f6c57ff96 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 14:59:55 -0500 Subject: [PATCH 14/30] libsyntax: convert `BytePos`/`CharPos` binops to by value --- src/libsyntax/codemap.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index d2fe667339c..592fdd7207c 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -52,35 +52,71 @@ impl Pos for BytePos { fn to_uint(&self) -> uint { let BytePos(n) = *self; n as uint } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Add for BytePos { fn add(&self, rhs: &BytePos) -> BytePos { BytePos((self.to_uint() + rhs.to_uint()) as u32) } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Add for BytePos { + fn add(self, rhs: BytePos) -> BytePos { + BytePos((self.to_uint() + rhs.to_uint()) as u32) + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub for BytePos { fn sub(&self, rhs: &BytePos) -> BytePos { BytePos((self.to_uint() - rhs.to_uint()) as u32) } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Sub for BytePos { + fn sub(self, rhs: BytePos) -> BytePos { + BytePos((self.to_uint() - rhs.to_uint()) as u32) + } +} + impl Pos for CharPos { fn from_uint(n: uint) -> CharPos { CharPos(n) } fn to_uint(&self) -> uint { let CharPos(n) = *self; n } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Add for CharPos { fn add(&self, rhs: &CharPos) -> CharPos { CharPos(self.to_uint() + rhs.to_uint()) } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Add for CharPos { + fn add(self, rhs: CharPos) -> CharPos { + CharPos(self.to_uint() + rhs.to_uint()) + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub for CharPos { fn sub(&self, rhs: &CharPos) -> CharPos { CharPos(self.to_uint() - rhs.to_uint()) } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Sub for CharPos { + fn sub(self, rhs: CharPos) -> CharPos { + CharPos(self.to_uint() - rhs.to_uint()) + } +} + /// Spans represent a region of code, used for error reporting. Positions in spans /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back From c4fa2a37ae4958cae22d442885f04eeba9ba21ba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 15:09:03 -0500 Subject: [PATCH 15/30] libsyntax: convert `LockstepIterSize` binops to by value --- src/libsyntax/ext/tt/transcribe.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 99799fecb78..e2439bad178 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -106,6 +106,8 @@ enum LockstepIterSize { LisContradiction(String), } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Add for LockstepIterSize { fn add(&self, other: &LockstepIterSize) -> LockstepIterSize { match *self { @@ -127,6 +129,28 @@ impl Add for LockstepIterSize { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl Add for LockstepIterSize { + fn add(self, other: LockstepIterSize) -> LockstepIterSize { + match self { + LisUnconstrained => other, + LisContradiction(_) => self, + LisConstraint(l_len, ref l_id) => match other { + LisUnconstrained => self.clone(), + LisContradiction(_) => other, + LisConstraint(r_len, _) if l_len == r_len => self.clone(), + LisConstraint(r_len, r_id) => { + let l_n = token::get_ident(l_id.clone()); + let r_n = token::get_ident(r_id); + LisContradiction(format!("inconsistent lockstep iteration: \ + '{}' has {} items, but '{}' has {}", + l_n, l_len, r_n, r_len).to_string()) + } + }, + } + } +} + fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize { match *t { TtDelimited(_, ref delimed) => { From eb71976137ba1528c0cfca2fdbdb13dcc712809c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 16:34:57 -0500 Subject: [PATCH 16/30] librustc: convert `TypeContents` binops to by value --- src/librustc/middle/ty.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8e99045cffb..2f694b382cc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2859,24 +2859,51 @@ impl TypeContents { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl ops::BitOr for TypeContents { fn bitor(&self, other: &TypeContents) -> TypeContents { TypeContents {bits: self.bits | other.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl ops::BitOr for TypeContents { + fn bitor(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits | other.bits} + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl ops::BitAnd for TypeContents { fn bitand(&self, other: &TypeContents) -> TypeContents { TypeContents {bits: self.bits & other.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl ops::BitAnd for TypeContents { + fn bitand(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits & other.bits} + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl ops::Sub for TypeContents { fn sub(&self, other: &TypeContents) -> TypeContents { TypeContents {bits: self.bits & !other.bits} } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl ops::Sub for TypeContents { + fn sub(self, other: TypeContents) -> TypeContents { + TypeContents {bits: self.bits & !other.bits} + } +} + impl fmt::Show for TypeContents { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TypeContents({:b})", self.bits) From fb1d4f1b1390654cdbe193882c9ed63a34dd720b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 16:47:48 -0500 Subject: [PATCH 17/30] librustdoc: convert `Counts` binops to by value --- src/librustdoc/stability_summary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index 881270afe14..f92cdaf46b6 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -42,7 +42,7 @@ pub struct Counts { impl Copy for Counts {} impl Add for Counts { - fn add(&self, other: &Counts) -> Counts { + fn add(self, other: Counts) -> Counts { Counts { deprecated: self.deprecated + other.deprecated, experimental: self.experimental + other.experimental, From 2b170839880e82a72d463b00759c409cb61d41b0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 16:52:13 -0500 Subject: [PATCH 18/30] Test that binops consume their arguments --- src/test/compile-fail/binop-consume-args.rs | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/test/compile-fail/binop-consume-args.rs diff --git a/src/test/compile-fail/binop-consume-args.rs b/src/test/compile-fail/binop-consume-args.rs new file mode 100644 index 00000000000..2bdd148b99b --- /dev/null +++ b/src/test/compile-fail/binop-consume-args.rs @@ -0,0 +1,73 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that binary operators consume their arguments + +fn add, B>(lhs: A, rhs: B) { + lhs + rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn sub, B>(lhs: A, rhs: B) { + lhs - rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn mul, B>(lhs: A, rhs: B) { + lhs * rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn div, B>(lhs: A, rhs: B) { + lhs / rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn rem, B>(lhs: A, rhs: B) { + lhs % rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn bitand, B>(lhs: A, rhs: B) { + lhs & rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn bitor, B>(lhs: A, rhs: B) { + lhs | rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn bitxor, B>(lhs: A, rhs: B) { + lhs ^ rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn shl, B>(lhs: A, rhs: B) { + lhs << rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn shr, B>(lhs: A, rhs: B) { + lhs >> rhs; + drop(lhs); //~ ERROR use of moved value: `lhs` + drop(rhs); //~ ERROR use of moved value: `rhs` +} + +fn main() {} From 971add88d820ef84d02f2dab306b07ff09491c84 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 17:33:22 -0500 Subject: [PATCH 19/30] Fix run-pass tests --- .../trait_inheritance_overloading_xc.rs | 10 ++++---- src/test/run-pass/bool.rs | 24 +++++++++---------- src/test/run-pass/deriving-zero.rs | 10 ++++---- src/test/run-pass/issue-3743.rs | 2 +- .../run-pass/numeric-method-autoexport.rs | 20 ++++++++-------- src/test/run-pass/operator-multidispatch.rs | 6 ++--- src/test/run-pass/operator-overloading.rs | 10 ++++---- .../overloaded-calls-param-vtables.rs | 2 +- src/test/run-pass/simd-generics.rs | 4 ++-- .../trait-inheritance-overloading-xc-exe.rs | 2 +- .../run-pass/trait-inheritance-overloading.rs | 12 +++++----- 11 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/test/auxiliary/trait_inheritance_overloading_xc.rs b/src/test/auxiliary/trait_inheritance_overloading_xc.rs index 95bdecd7760..61854aba279 100644 --- a/src/test/auxiliary/trait_inheritance_overloading_xc.rs +++ b/src/test/auxiliary/trait_inheritance_overloading_xc.rs @@ -10,24 +10,24 @@ use std::cmp::PartialEq; -pub trait MyNum : Add + Sub + Mul + PartialEq { +pub trait MyNum : Add + Sub + Mul + PartialEq + Clone { } -#[deriving(Show)] +#[deriving(Clone, Show)] pub struct MyInt { pub val: int } impl Add for MyInt { - fn add(&self, other: &MyInt) -> MyInt { mi(self.val + other.val) } + fn add(self, other: MyInt) -> MyInt { mi(self.val + other.val) } } impl Sub for MyInt { - fn sub(&self, other: &MyInt) -> MyInt { mi(self.val - other.val) } + fn sub(self, other: MyInt) -> MyInt { mi(self.val - other.val) } } impl Mul for MyInt { - fn mul(&self, other: &MyInt) -> MyInt { mi(self.val * other.val) } + fn mul(self, other: MyInt) -> MyInt { mi(self.val * other.val) } } impl PartialEq for MyInt { diff --git a/src/test/run-pass/bool.rs b/src/test/run-pass/bool.rs index 91075633ab8..238d0ecdca7 100644 --- a/src/test/run-pass/bool.rs +++ b/src/test/run-pass/bool.rs @@ -16,30 +16,30 @@ fn main() { assert_eq!(false != true, true); assert_eq!(false.ne(&false), false); - assert_eq!(false.bitand(&false), false); - assert_eq!(true.bitand(&false), false); - assert_eq!(false.bitand(&true), false); - assert_eq!(true.bitand(&true), true); + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); assert_eq!(false & false, false); assert_eq!(true & false, false); assert_eq!(false & true, false); assert_eq!(true & true, true); - assert_eq!(false.bitor(&false), false); - assert_eq!(true.bitor(&false), true); - assert_eq!(false.bitor(&true), true); - assert_eq!(true.bitor(&true), true); + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); assert_eq!(false | false, false); assert_eq!(true | false, true); assert_eq!(false | true, true); assert_eq!(true | true, true); - assert_eq!(false.bitxor(&false), false); - assert_eq!(true.bitxor(&false), true); - assert_eq!(false.bitxor(&true), true); - assert_eq!(true.bitxor(&true), false); + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); assert_eq!(false ^ false, false); assert_eq!(true ^ false, true); diff --git a/src/test/run-pass/deriving-zero.rs b/src/test/run-pass/deriving-zero.rs index 690d82a4ed2..88f3e5775b7 100644 --- a/src/test/run-pass/deriving-zero.rs +++ b/src/test/run-pass/deriving-zero.rs @@ -15,10 +15,10 @@ use std::num::Zero; struct Vector2(T, T); impl> Add, Vector2> for Vector2 { - fn add(&self, other: &Vector2) -> Vector2 { + fn add(self, other: Vector2) -> Vector2 { match (self, other) { - (&Vector2(ref x0, ref y0), &Vector2(ref x1, ref y1)) => { - Vector2(*x0 + *x1, *y0 + *y1) + (Vector2(x0, y0), Vector2(x1, y1)) => { + Vector2(x0 + x1, y0 + y1) } } } @@ -30,7 +30,7 @@ struct Vector3 { } impl> Add, Vector3> for Vector3 { - fn add(&self, other: &Vector3) -> Vector3 { + fn add(self, other: Vector3) -> Vector3 { Vector3 { x: self.x + other.x, y: self.y + other.y, @@ -47,7 +47,7 @@ struct Matrix3x2 { } impl> Add, Matrix3x2> for Matrix3x2 { - fn add(&self, other: &Matrix3x2) -> Matrix3x2 { + fn add(self, other: Matrix3x2) -> Matrix3x2 { Matrix3x2 { x: self.x + other.x, y: self.y + other.y, diff --git a/src/test/run-pass/issue-3743.rs b/src/test/run-pass/issue-3743.rs index ada3e37c092..80d3d29bc00 100644 --- a/src/test/run-pass/issue-3743.rs +++ b/src/test/run-pass/issue-3743.rs @@ -28,7 +28,7 @@ trait RhsOfVec2Mul { fn mul_vec2_by(&self, lhs: &Vec2) -> Result; } // Vec2's implementation of Mul "from the other side" using the above trait impl> Mul for Vec2 { - fn mul(&self, rhs: &Rhs) -> Res { rhs.mul_vec2_by(self) } + fn mul(self, rhs: Rhs) -> Res { rhs.mul_vec2_by(&self) } } // Implementation of 'f64 as right-hand-side of Vec2::Mul' diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index 585ade71fc6..f8184d248ff 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -18,19 +18,19 @@ pub fn main() { // ints // num - assert_eq!(15i.add(&6), 21); - assert_eq!(15i8.add(&6i8), 21i8); - assert_eq!(15i16.add(&6i16), 21i16); - assert_eq!(15i32.add(&6i32), 21i32); - assert_eq!(15i64.add(&6i64), 21i64); + assert_eq!(15i.add(6), 21); + assert_eq!(15i8.add(6i8), 21i8); + assert_eq!(15i16.add(6i16), 21i16); + assert_eq!(15i32.add(6i32), 21i32); + assert_eq!(15i64.add(6i64), 21i64); // uints // num - assert_eq!(15u.add(&6u), 21u); - assert_eq!(15u8.add(&6u8), 21u8); - assert_eq!(15u16.add(&6u16), 21u16); - assert_eq!(15u32.add(&6u32), 21u32); - assert_eq!(15u64.add(&6u64), 21u64); + assert_eq!(15u.add(6u), 21u); + assert_eq!(15u8.add(6u8), 21u8); + assert_eq!(15u16.add(6u16), 21u16); + assert_eq!(15u32.add(6u32), 21u32); + assert_eq!(15u64.add(6u64), 21u64); // floats // num diff --git a/src/test/run-pass/operator-multidispatch.rs b/src/test/run-pass/operator-multidispatch.rs index fc79e4f0edb..cb3397c00bc 100644 --- a/src/test/run-pass/operator-multidispatch.rs +++ b/src/test/run-pass/operator-multidispatch.rs @@ -20,13 +20,13 @@ struct Point { } impl ops::Add for Point { - fn add(&self, other: &Point) -> Point { - Point {x: self.x + (*other).x, y: self.y + (*other).y} + fn add(self, other: Point) -> Point { + Point {x: self.x + other.x, y: self.y + other.y} } } impl ops::Add for Point { - fn add(&self, &other: &int) -> Point { + fn add(self, other: int) -> Point { Point {x: self.x + other, y: self.y + other} } diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index a896d2b06f7..0f3da6836cb 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -12,21 +12,21 @@ use std::cmp; use std::ops; -#[deriving(Show)] +#[deriving(Copy, Show)] struct Point { x: int, y: int } impl ops::Add for Point { - fn add(&self, other: &Point) -> Point { - Point {x: self.x + (*other).x, y: self.y + (*other).y} + fn add(self, other: Point) -> Point { + Point {x: self.x + other.x, y: self.y + other.y} } } impl ops::Sub for Point { - fn sub(&self, other: &Point) -> Point { - Point {x: self.x - (*other).x, y: self.y - (*other).y} + fn sub(self, other: Point) -> Point { + Point {x: self.x - other.x, y: self.y - other.y} } } diff --git a/src/test/run-pass/overloaded-calls-param-vtables.rs b/src/test/run-pass/overloaded-calls-param-vtables.rs index d0dbee39ae0..2e8ec3916bd 100644 --- a/src/test/run-pass/overloaded-calls-param-vtables.rs +++ b/src/test/run-pass/overloaded-calls-param-vtables.rs @@ -18,7 +18,7 @@ struct G; impl<'a, A: Add> Fn<(A,), int> for G { extern "rust-call" fn call(&self, (arg,): (A,)) -> int { - arg.add(&1) + arg.add(1) } } diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 31c29b615fc..42f93a97142 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -22,8 +22,8 @@ fn add>(lhs: T, rhs: T) -> T { } impl ops::Add for f32x4 { - fn add(&self, rhs: &f32x4) -> f32x4 { - *self + *rhs + fn add(self, rhs: f32x4) -> f32x4 { + self + rhs } } diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index 7760395bf1c..2a087e5e425 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -14,7 +14,7 @@ extern crate trait_inheritance_overloading_xc; use trait_inheritance_overloading_xc::{MyNum, MyInt}; fn f(x: T, y: T) -> (T, T, T) { - return (x + y, x - y, x * y); + return (x.clone() + y.clone(), x.clone() - y.clone(), x * y); } fn mi(v: int) -> MyInt { MyInt { val: v } } diff --git a/src/test/run-pass/trait-inheritance-overloading.rs b/src/test/run-pass/trait-inheritance-overloading.rs index b13ea7ae0ba..5f8e945cce8 100644 --- a/src/test/run-pass/trait-inheritance-overloading.rs +++ b/src/test/run-pass/trait-inheritance-overloading.rs @@ -10,21 +10,21 @@ use std::cmp::PartialEq; -trait MyNum : Add + Sub + Mul + PartialEq { } +trait MyNum : Add + Sub + Mul + PartialEq + Clone { } -#[deriving(Show)] +#[deriving(Clone, Show)] struct MyInt { val: int } impl Add for MyInt { - fn add(&self, other: &MyInt) -> MyInt { mi(self.val + other.val) } + fn add(self, other: MyInt) -> MyInt { mi(self.val + other.val) } } impl Sub for MyInt { - fn sub(&self, other: &MyInt) -> MyInt { mi(self.val - other.val) } + fn sub(self, other: MyInt) -> MyInt { mi(self.val - other.val) } } impl Mul for MyInt { - fn mul(&self, other: &MyInt) -> MyInt { mi(self.val * other.val) } + fn mul(self, other: MyInt) -> MyInt { mi(self.val * other.val) } } impl PartialEq for MyInt { @@ -35,7 +35,7 @@ impl PartialEq for MyInt { impl MyNum for MyInt {} fn f(x: T, y: T) -> (T, T, T) { - return (x + y, x - y, x * y); + return (x.clone() + y.clone(), x.clone() - y.clone(), x * y); } fn mi(v: int) -> MyInt { MyInt { val: v } } From f0b65674c3ecc7b9501dfd3484c5dabb572017d4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 17:52:10 -0500 Subject: [PATCH 20/30] Fix compile-fail tests --- .../borrowck-loan-in-overloaded-op.rs | 11 ++++++----- .../borrowck-loan-rcvr-overloaded-op.rs | 10 +++++----- .../compile-fail/wrong-mul-method-signature.rs | 16 ++++++++-------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs index 4a6c20079c1..692303fc1e4 100644 --- a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs @@ -9,18 +9,19 @@ // except according to those terms. +#[deriving(Clone)] struct foo(Box); impl Add for foo { - fn add(&self, f: &foo) -> foo { - let foo(box i) = *self; - let foo(box j) = *f; + fn add(self, f: foo) -> foo { + let foo(box i) = self; + let foo(box j) = f; foo(box() (i + j)) } } fn main() { let x = foo(box 3); - let _y = x + {x}; // the `{x}` forces a move to occur - //~^ ERROR cannot move out of `x` + let _y = {x} + x.clone(); // the `{x}` forces a move to occur + //~^ ERROR use of moved value: `x` } diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index c5d7b6fa451..b83e1544c96 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +#[deriving(Copy)] struct Point { x: int, y: int, } -impl Add for Point { - fn add(&self, z: &int) -> int { - self.x + self.y + (*z) +impl Add for Point { + fn add(self, z: int) -> int { + self.x + self.y + z } } @@ -41,7 +41,7 @@ fn b() { let q = &mut p; - p + 3; //~ ERROR cannot borrow `p` + p + 3; //~ ERROR cannot use `p` p.times(3); //~ ERROR cannot borrow `p` *q + 3; // OK to use the new alias `q` diff --git a/src/test/compile-fail/wrong-mul-method-signature.rs b/src/test/compile-fail/wrong-mul-method-signature.rs index aead739d3e0..b5e4cac7555 100644 --- a/src/test/compile-fail/wrong-mul-method-signature.rs +++ b/src/test/compile-fail/wrong-mul-method-signature.rs @@ -17,12 +17,12 @@ struct Vec1 { x: f64 } -// Expecting ref in input signature +// Expecting value in input signature impl Mul for Vec1 { - fn mul(&self, s: f64) -> Vec1 { - //~^ ERROR: method `mul` has an incompatible type for trait: expected &-ptr, found f64 + fn mul(self, s: &f64) -> Vec1 { + //~^ ERROR: method `mul` has an incompatible type for trait: expected f64, found &-ptr Vec1 { - x: self.x * s + x: self.x * *s } } } @@ -34,8 +34,8 @@ struct Vec2 { // Wrong type parameter ordering impl Mul for Vec2 { - fn mul(&self, s: f64) -> Vec2 { - //~^ ERROR: method `mul` has an incompatible type for trait: expected &-ptr, found f64 + fn mul(self, s: f64) -> Vec2 { + //~^ ERROR: method `mul` has an incompatible type for trait: expected struct Vec2, found f64 Vec2 { x: self.x * s, y: self.y * s @@ -51,9 +51,9 @@ struct Vec3 { // Unexpected return type impl Mul for Vec3 { - fn mul(&self, s: &f64) -> f64 { + fn mul(self, s: f64) -> f64 { //~^ ERROR: method `mul` has an incompatible type for trait: expected i32, found f64 - *s + s } } From a672b27cbc8de4f3cb6e5f2b3ed5a473204680b7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 18:02:39 -0500 Subject: [PATCH 21/30] libcollections: fix unit tests --- src/libcollections/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cefdabac097..0e3d2f02ae9 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1290,7 +1290,7 @@ mod tests { fn test_str_add() { let a = String::from_str("12345"); let b = a + "2"; - let b = b + String::from_str("2"); + let b = b + "2"; assert_eq!(b.len(), 7); assert_eq!(b, "1234522"); } From 1ec5650ad3a95d6ebdcaa21b87fb2d0f5423f0ba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 18:04:46 -0500 Subject: [PATCH 22/30] libcoretest: fix unit tests --- src/libcoretest/num/int_macros.rs | 10 +++++----- src/libcoretest/num/mod.rs | 22 ++++++++++++---------- src/libcoretest/num/uint_macros.rs | 10 +++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/libcoretest/num/int_macros.rs b/src/libcoretest/num/int_macros.rs index e25f10bd0da..87e2fe75299 100644 --- a/src/libcoretest/num/int_macros.rs +++ b/src/libcoretest/num/int_macros.rs @@ -64,11 +64,11 @@ mod tests { #[test] fn test_bitwise_operators() { - assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); - assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); - assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); - assert!(0b1110 as $T == (0b0111 as $T).shl(&1)); - assert!(0b0111 as $T == (0b1110 as $T).shr(&1)); + assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T)); + assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T)); + assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); + assert!(0b1110 as $T == (0b0111 as $T).shl(1)); + assert!(0b0111 as $T == (0b1110 as $T).shr(1)); assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not()); } diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 6ee3633d36c..b7f8b81f996 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -12,6 +12,7 @@ use core::cmp::PartialEq; use core::fmt::Show; use core::num::{NumCast, cast}; use core::ops::{Add, Sub, Mul, Div, Rem}; +use core::kinds::Copy; mod int_macros; mod i8; @@ -32,18 +33,19 @@ pub fn test_num(ten: T, two: T) where + Add + Sub + Mul + Div + Rem + Show + + Copy { - assert_eq!(ten.add(&two), cast(12i).unwrap()); - assert_eq!(ten.sub(&two), cast(8i).unwrap()); - assert_eq!(ten.mul(&two), cast(20i).unwrap()); - assert_eq!(ten.div(&two), cast(5i).unwrap()); - assert_eq!(ten.rem(&two), cast(0i).unwrap()); + assert_eq!(ten.add(two), cast(12i).unwrap()); + assert_eq!(ten.sub(two), cast(8i).unwrap()); + assert_eq!(ten.mul(two), cast(20i).unwrap()); + assert_eq!(ten.div(two), cast(5i).unwrap()); + assert_eq!(ten.rem(two), cast(0i).unwrap()); - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.rem(&two), ten % two); + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); } #[cfg(test)] diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcoretest/num/uint_macros.rs index 01a88119b64..5657a43de19 100644 --- a/src/libcoretest/num/uint_macros.rs +++ b/src/libcoretest/num/uint_macros.rs @@ -31,11 +31,11 @@ mod tests { #[test] fn test_bitwise_operators() { - assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); - assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); - assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); - assert!(0b1110 as $T == (0b0111 as $T).shl(&1u)); - assert!(0b0111 as $T == (0b1110 as $T).shr(&1u)); + assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T)); + assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T)); + assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); + assert!(0b1110 as $T == (0b0111 as $T).shl(1u)); + assert!(0b0111 as $T == (0b1110 as $T).shr(1u)); assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); } From bc23b8ebc64565bc3838a8bbfb03ed52e900cfca Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 17:55:28 -0500 Subject: [PATCH 23/30] libstd: fix unit tests --- src/libstd/num/mod.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index a15e71b4a2a..9aaaceb87e6 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -19,6 +19,7 @@ #[cfg(test)] use cmp::PartialEq; #[cfg(test)] use fmt::Show; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; +#[cfg(test)] use kinds::Copy; pub use core::num::{Num, div_rem, Zero, zero, One, one}; pub use core::num::{Unsigned, pow, Bounded}; @@ -130,18 +131,19 @@ pub fn test_num(ten: T, two: T) where + Add + Sub + Mul + Div + Rem + Show + + Copy { - assert_eq!(ten.add(&two), cast(12i).unwrap()); - assert_eq!(ten.sub(&two), cast(8i).unwrap()); - assert_eq!(ten.mul(&two), cast(20i).unwrap()); - assert_eq!(ten.div(&two), cast(5i).unwrap()); - assert_eq!(ten.rem(&two), cast(0i).unwrap()); + assert_eq!(ten.add(two), cast(12i).unwrap()); + assert_eq!(ten.sub(two), cast(8i).unwrap()); + assert_eq!(ten.mul(two), cast(20i).unwrap()); + assert_eq!(ten.div(two), cast(5i).unwrap()); + assert_eq!(ten.rem(two), cast(0i).unwrap()); - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.rem(&two), ten % two); + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); } #[cfg(test)] From d193bf30ce1991297225801600da158c18bd3e16 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 1 Dec 2014 19:10:12 -0500 Subject: [PATCH 24/30] libcore: fix doctests --- src/libcore/ops.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index d283d70815c..7ff5026d0b9 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -32,13 +32,13 @@ //! } //! //! impl Add for Point { -//! fn add(&self, other: &Point) -> Point { +//! fn add(self, other: Point) -> Point { //! Point {x: self.x + other.x, y: self.y + other.y} //! } //! } //! //! impl Sub for Point { -//! fn sub(&self, other: &Point) -> Point { +//! fn sub(self, other: Point) -> Point { //! Point {x: self.x - other.x, y: self.y - other.y} //! } //! } @@ -133,9 +133,9 @@ macro_rules! add_impl( /// struct Foo; /// /// impl Add for Foo { -/// fn add(&self, _rhs: &Foo) -> Foo { +/// fn add(self, _rhs: Foo) -> Foo { /// println!("Adding!"); -/// *self +/// self /// } /// } /// @@ -215,9 +215,9 @@ macro_rules! sub_impl( /// struct Foo; /// /// impl Sub for Foo { -/// fn sub(&self, _rhs: &Foo) -> Foo { +/// fn sub(self, _rhs: Foo) -> Foo { /// println!("Subtracting!"); -/// *self +/// self /// } /// } /// @@ -297,9 +297,9 @@ macro_rules! mul_impl( /// struct Foo; /// /// impl Mul for Foo { -/// fn mul(&self, _rhs: &Foo) -> Foo { +/// fn mul(self, _rhs: Foo) -> Foo { /// println!("Multiplying!"); -/// *self +/// self /// } /// } /// @@ -379,9 +379,9 @@ macro_rules! div_impl( /// struct Foo; /// /// impl Div for Foo { -/// fn div(&self, _rhs: &Foo) -> Foo { +/// fn div(self, _rhs: Foo) -> Foo { /// println!("Dividing!"); -/// *self +/// self /// } /// } /// @@ -475,9 +475,9 @@ macro_rules! rem_float_impl( /// struct Foo; /// /// impl Rem for Foo { -/// fn rem(&self, _rhs: &Foo) -> Foo { +/// fn rem(self, _rhs: Foo) -> Foo { /// println!("Remainder-ing!"); -/// *self +/// self /// } /// } /// @@ -669,9 +669,9 @@ macro_rules! bitand_impl( /// struct Foo; /// /// impl BitAnd for Foo { -/// fn bitand(&self, _rhs: &Foo) -> Foo { +/// fn bitand(self, _rhs: Foo) -> Foo { /// println!("Bitwise And-ing!"); -/// *self +/// self /// } /// } /// @@ -751,9 +751,9 @@ macro_rules! bitor_impl( /// struct Foo; /// /// impl BitOr for Foo { -/// fn bitor(&self, _rhs: &Foo) -> Foo { +/// fn bitor(self, _rhs: Foo) -> Foo { /// println!("Bitwise Or-ing!"); -/// *self +/// self /// } /// } /// @@ -833,9 +833,9 @@ macro_rules! bitxor_impl( /// struct Foo; /// /// impl BitXor for Foo { -/// fn bitxor(&self, _rhs: &Foo) -> Foo { +/// fn bitxor(self, _rhs: Foo) -> Foo { /// println!("Bitwise Xor-ing!"); -/// *self +/// self /// } /// } /// @@ -917,9 +917,9 @@ macro_rules! shl_impl( /// struct Foo; /// /// impl Shl for Foo { -/// fn shl(&self, _rhs: &Foo) -> Foo { +/// fn shl(self, _rhs: Foo) -> Foo { /// println!("Shifting left!"); -/// *self +/// self /// } /// } /// @@ -1001,9 +1001,9 @@ macro_rules! shr_impl( /// struct Foo; /// /// impl Shr for Foo { -/// fn shr(&self, _rhs: &Foo) -> Foo { +/// fn shr(self, _rhs: Foo) -> Foo { /// println!("Shifting right!"); -/// *self +/// self /// } /// } /// From f4abb12b0c822e119e69023ab94664415061d955 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 3 Dec 2014 00:39:53 -0500 Subject: [PATCH 25/30] Address Niko's comments --- src/librustc/middle/expr_use_visitor.rs | 32 ++++++---- src/librustc_typeck/check/mod.rs | 79 ++++++++++++------------- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 59872c69462..59344258833 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -329,6 +329,12 @@ macro_rules! return_if_err( ) ) +/// Whether the elements of an overloaded operation are passed by value or by reference +enum PassArgs { + ByValue, + ByRef, +} + impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { pub fn new(delegate: &'d mut Delegate<'tcx>, typer: &'t TYPER, @@ -438,7 +444,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ast::ExprPath(..) => { } ast::ExprUnary(ast::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &**base, Vec::new(), None) { + if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) { self.select_from_expr(&**base); } } @@ -452,7 +458,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], None) { + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], PassArgs::ByRef) { self.select_from_expr(&**lhs); self.consume_expr(&**rhs); } @@ -465,7 +471,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { (&None, &Some(ref e)) => vec![&**e], (&None, &None) => Vec::new() }; - let overloaded = self.walk_overloaded_operator(expr, &**base, args, None); + let overloaded = + self.walk_overloaded_operator(expr, &**base, args, PassArgs::ByRef); assert!(overloaded); } @@ -570,14 +577,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprUnary(_, ref lhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), None) { + if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), PassArgs::ByRef) { self.consume_expr(&**lhs); } } ast::ExprBinary(op, ref lhs, ref rhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], Some(op)) - { + let pass_args = if ast_util::is_by_value_binop(op) { + PassArgs::ByValue + } else { + PassArgs::ByRef + }; + + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], pass_args) { self.consume_expr(&**lhs); self.consume_expr(&**rhs); } @@ -913,21 +925,21 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { expr: &ast::Expr, receiver: &ast::Expr, rhs: Vec<&ast::Expr>, - binop: Option) + pass_args: PassArgs) -> bool { if !self.typer.is_method_call(expr.id) { return false; } - match binop { - Some(binop) if ast_util::is_by_value_binop(binop) => { + match pass_args { + PassArgs::ByValue => { self.consume_expr(receiver); self.consume_expr(rhs[0]); return true; }, - _ => {}, + PassArgs::ByRef => {}, } self.walk_expr(receiver); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2dcb07e0fb5..5f8991278b0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,7 +77,6 @@ type parameter). */ pub use self::LvaluePreference::*; -pub use self::DerefArgs::*; pub use self::Expectation::*; use self::IsBinopAssignment::*; use self::TupleArgumentsFlag::*; @@ -2117,7 +2116,7 @@ fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_callee.ty, call_expression, args, - DontDerefArgs, + AutorefArgs::No, TupleArguments); fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); write_call(fcx, call_expression, output_type); @@ -2274,7 +2273,7 @@ fn try_overloaded_slice<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_ty_or_err, expr, args.as_slice(), - DoDerefArgs, + AutorefArgs::Yes, DontTupleArguments); opt_method_ty.map(|method_ty| { @@ -2480,7 +2479,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_type, iterator_expr, &[], - DontDerefArgs, + AutorefArgs::No, DontTupleArguments); match method { @@ -2522,7 +2521,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_fn_ty: Ty<'tcx>, callee_expr: &ast::Expr, args_no_rcvr: &[&P], - deref_args: DerefArgs, + autoref_args: AutorefArgs, tuple_arguments: TupleArgumentsFlag) -> ty::FnOutput<'tcx> { if ty::type_is_error(method_fn_ty) { @@ -2538,7 +2537,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, err_inputs.as_slice(), callee_expr, args_no_rcvr, - deref_args, + autoref_args, false, tuple_arguments); ty::FnConverging(ty::mk_err()) @@ -2551,7 +2550,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fty.sig.inputs.slice_from(1), callee_expr, args_no_rcvr, - deref_args, + autoref_args, fty.sig.variadic, tuple_arguments); fty.sig.output @@ -2571,7 +2570,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn_inputs: &[Ty<'tcx>], _callee_expr: &ast::Expr, args: &[&P], - deref_args: DerefArgs, + autoref_args: AutorefArgs, variadic: bool, tuple_arguments: TupleArgumentsFlag) { let tcx = fcx.ccx.tcx; @@ -2674,8 +2673,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("checking the argument"); let mut formal_ty = formal_tys[i]; - match deref_args { - DoDerefArgs => { + match autoref_args { + AutorefArgs::Yes => { match formal_ty.sty { ty::ty_rptr(_, mt) => formal_ty = mt.ty, ty::ty_err => (), @@ -2690,7 +2689,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } } - DontDerefArgs => {} + AutorefArgs::No => {} } check_expr_coercable_to_type(fcx, &***arg, formal_ty); @@ -2905,12 +2904,12 @@ pub fn lookup_tup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, // Controls whether the arguments are automatically referenced. This is useful // for overloaded binary and unary operators. #[deriving(PartialEq)] -pub enum DerefArgs { - DontDerefArgs, - DoDerefArgs +pub enum AutorefArgs { + Yes, + No, } -impl Copy for DerefArgs {} +impl Copy for AutorefArgs {} /// Controls whether the arguments are tupled. This is used for the call /// operator. @@ -2998,7 +2997,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn_sig.inputs.as_slice(), f, args, - DontDerefArgs, + AutorefArgs::No, fn_sig.variadic, DontTupleArguments); @@ -3048,7 +3047,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn_ty, expr, args.as_slice(), - DontDerefArgs, + AutorefArgs::No, DontTupleArguments); write_call(fcx, expr, ret_ty); @@ -3132,7 +3131,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lhs: &'a ast::Expr, rhs: Option<&P>, unbound_method: F, - deref_args: DerefArgs) -> Ty<'tcx> where + autoref_args: AutorefArgs) -> Ty<'tcx> where F: FnOnce(), { let method = match trait_did { @@ -3148,7 +3147,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // traits that don't force left and right to have same // type. let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) if deref_args == DoDerefArgs => { + ty::ty_rptr(r_in, mt) => { let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span)); fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, r_in); let adjusted_ty = ty::mk_rptr(fcx.tcx(), r_adj, mt); @@ -3185,7 +3184,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, method_ty, op_ex, args.as_slice(), - deref_args, + autoref_args, DontTupleArguments) { ty::FnConverging(result_type) => result_type, ty::FnDiverging => ty::mk_err() @@ -3201,7 +3200,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expected_ty, op_ex, args.as_slice(), - deref_args, + autoref_args, DontTupleArguments); ty::mk_err() } @@ -3320,23 +3319,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, rhs: &P) -> Ty<'tcx> { let tcx = fcx.ccx.tcx; let lang = &tcx.lang_items; - let (name, trait_did, deref_args) = match op { - ast::BiAdd => ("add", lang.add_trait(), DontDerefArgs), - ast::BiSub => ("sub", lang.sub_trait(), DontDerefArgs), - ast::BiMul => ("mul", lang.mul_trait(), DontDerefArgs), - ast::BiDiv => ("div", lang.div_trait(), DontDerefArgs), - ast::BiRem => ("rem", lang.rem_trait(), DontDerefArgs), - ast::BiBitXor => ("bitxor", lang.bitxor_trait(), DontDerefArgs), - ast::BiBitAnd => ("bitand", lang.bitand_trait(), DontDerefArgs), - ast::BiBitOr => ("bitor", lang.bitor_trait(), DontDerefArgs), - ast::BiShl => ("shl", lang.shl_trait(), DontDerefArgs), - ast::BiShr => ("shr", lang.shr_trait(), DontDerefArgs), - ast::BiLt => ("lt", lang.ord_trait(), DoDerefArgs), - ast::BiLe => ("le", lang.ord_trait(), DoDerefArgs), - ast::BiGe => ("ge", lang.ord_trait(), DoDerefArgs), - ast::BiGt => ("gt", lang.ord_trait(), DoDerefArgs), - ast::BiEq => ("eq", lang.eq_trait(), DoDerefArgs), - ast::BiNe => ("ne", lang.eq_trait(), DoDerefArgs), + let (name, trait_did) = match op { + ast::BiAdd => ("add", lang.add_trait()), + ast::BiSub => ("sub", lang.sub_trait()), + ast::BiMul => ("mul", lang.mul_trait()), + ast::BiDiv => ("div", lang.div_trait()), + ast::BiRem => ("rem", lang.rem_trait()), + ast::BiBitXor => ("bitxor", lang.bitxor_trait()), + ast::BiBitAnd => ("bitand", lang.bitand_trait()), + ast::BiBitOr => ("bitor", lang.bitor_trait()), + ast::BiShl => ("shl", lang.shl_trait()), + ast::BiShr => ("shr", lang.shr_trait()), + ast::BiLt => ("lt", lang.ord_trait()), + ast::BiLe => ("le", lang.ord_trait()), + ast::BiGe => ("ge", lang.ord_trait()), + ast::BiGt => ("gt", lang.ord_trait()), + ast::BiEq => ("eq", lang.eq_trait()), + ast::BiNe => ("ne", lang.eq_trait()), ast::BiAnd | ast::BiOr => { check_expr(fcx, &**rhs); return ty::mk_err(); @@ -3349,7 +3348,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast_util::binop_to_string(op), actual) }, lhs_resolved_t, None) - }, deref_args) + }, if ast_util::is_by_value_binop(op) { AutorefArgs::No } else { AutorefArgs::Yes }) } fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -3365,7 +3364,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) }, rhs_t, None); - }, DontDerefArgs) + }, AutorefArgs::Yes) } // Check field access expressions From 949b55e58e8a26e5c05cc5350dee8017e7653ad5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 3 Dec 2014 02:22:41 -0500 Subject: [PATCH 26/30] libcollections: add commutative version of `Vec`/`String` addition --- src/libcollections/string.rs | 8 ++++++++ src/libcollections/vec.rs | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0e3d2f02ae9..f3a9e7b1867 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -874,6 +874,14 @@ impl<'a> Add<&'a str, String> for String { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a> Add for &'a str { + fn add(self, mut other: String) -> String { + other.push_str(self); + other + } +} + impl ops::Slice for String { #[inline] fn as_slice_<'a>(&'a self) -> &'a str { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56cfa19e887..275825da3b5 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1295,6 +1295,15 @@ impl<'a, T: Clone> Add<&'a [T], Vec> for Vec { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove impl after a snapshot +impl<'a, T: Clone> Add, Vec> for &'a [T] { + #[inline] + fn add(self, mut rhs: Vec) -> Vec { + rhs.push_all(self); + rhs + } +} + #[unsafe_destructor] impl Drop for Vec { fn drop(&mut self) { From dff2b395d21e8e6f322a3de2e68d20451afc08f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 3 Dec 2014 02:34:49 -0500 Subject: [PATCH 27/30] Test binops move semantics --- src/test/compile-fail/binop-move-semantics.rs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/test/compile-fail/binop-move-semantics.rs diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs new file mode 100644 index 00000000000..d9440e18375 --- /dev/null +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -0,0 +1,69 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that move restrictions are enforced on overloaded binary operations + +fn double_move>(x: T) { + x + + + x; //~ ERROR: use of moved value +} + +fn move_then_borrow + Clone>(x: T) { + x + + + x.clone(); //~ ERROR: use of moved value +} + +fn move_borrowed>(x: T, mut y: T) { + let m = &x; + let n = &mut y; + + x //~ ERROR: cannot move out of `x` because it is borrowed + + + y; //~ ERROR: cannot move out of `y` because it is borrowed +} + +fn illegal_dereference>(mut x: T, y: T) { + let m = &mut x; + let n = &y; + + *m //~ ERROR: cannot move out of dereference of `&mut`-pointer + + + *n; //~ ERROR: cannot move out of dereference of `&`-pointer +} + +struct Foo; + +impl<'a, 'b> Add<&'b Foo, ()> for &'a mut Foo { + fn add(self, _: &Foo) {} +} + +impl<'a, 'b> Add<&'b mut Foo, ()> for &'a Foo { + fn add(self, _: &mut Foo) {} +} + +fn mut_plus_immut() { + let mut f = Foo; + + &mut f + + + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable +} + +fn immut_plus_mut() { + let mut f = Foo; + + &f + + + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable +} + +fn main() {} From 308460400bbab1383a61e1e61238a9c730d30ed9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 5 Dec 2014 19:39:57 -0500 Subject: [PATCH 28/30] libcollections: convert `TrieSet` binops to by value --- src/libcollections/trie/set.rs | 104 +++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/src/libcollections/trie/set.rs b/src/libcollections/trie/set.rs index 5621726dc56..7b7b4d8280b 100644 --- a/src/libcollections/trie/set.rs +++ b/src/libcollections/trie/set.rs @@ -462,6 +462,8 @@ impl Extend for TrieSet { } } +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] #[unstable = "matches collection reform specification, waiting for dust to settle"] impl BitOr for TrieSet { /// Returns the union of `self` and `rhs` as a new `TrieSet`. @@ -483,6 +485,30 @@ impl BitOr for TrieSet { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl<'a, 'b> BitOr<&'b TrieSet, TrieSet> for &'a TrieSet { + /// Returns the union of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = &a | &b; + /// let v: Vec = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2, 3, 4, 5]); + /// ``` + fn bitor(self, rhs: &TrieSet) -> TrieSet { + self.union(rhs).collect() + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] #[unstable = "matches collection reform specification, waiting for dust to settle"] impl BitAnd for TrieSet { /// Returns the intersection of `self` and `rhs` as a new `TrieSet`. @@ -504,6 +530,30 @@ impl BitAnd for TrieSet { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl<'a, 'b> BitAnd<&'b TrieSet, TrieSet> for &'a TrieSet { + /// Returns the intersection of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![2, 3, 4].into_iter().collect(); + /// + /// let set: TrieSet = &a & &b; + /// let v: Vec = set.iter().collect(); + /// assert_eq!(v, vec![2u, 3]); + /// ``` + fn bitand(self, rhs: &TrieSet) -> TrieSet { + self.intersection(rhs).collect() + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] #[unstable = "matches collection reform specification, waiting for dust to settle"] impl BitXor for TrieSet { /// Returns the symmetric difference of `self` and `rhs` as a new `TrieSet`. @@ -525,6 +575,30 @@ impl BitXor for TrieSet { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl<'a, 'b> BitXor<&'b TrieSet, TrieSet> for &'a TrieSet { + /// Returns the symmetric difference of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = &a ^ &b; + /// let v: Vec = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2, 4, 5]); + /// ``` + fn bitxor(self, rhs: &TrieSet) -> TrieSet { + self.symmetric_difference(rhs).collect() + } +} + +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] #[unstable = "matches collection reform specification, waiting for dust to settle"] impl Sub for TrieSet { /// Returns the difference of `self` and `rhs` as a new `TrieSet`. @@ -546,6 +620,28 @@ impl Sub for TrieSet { } } +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl<'a, 'b> Sub<&'b TrieSet, TrieSet> for &'a TrieSet { + /// Returns the difference of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = &a - &b; + /// let v: Vec = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2]); + /// ``` + fn sub(self, rhs: &TrieSet) -> TrieSet { + self.difference(rhs).collect() + } +} + /// A forward iterator over a set. pub struct SetItems<'a> { iter: Entries<'a, ()> @@ -837,7 +933,7 @@ mod test { let a: TrieSet = vec![1, 2, 3].into_iter().collect(); let b: TrieSet = vec![3, 4, 5].into_iter().collect(); - let set: TrieSet = a | b; + let set: TrieSet = &a | &b; let v: Vec = set.iter().collect(); assert_eq!(v, vec![1u, 2, 3, 4, 5]); } @@ -847,7 +943,7 @@ mod test { let a: TrieSet = vec![1, 2, 3].into_iter().collect(); let b: TrieSet = vec![2, 3, 4].into_iter().collect(); - let set: TrieSet = a & b; + let set: TrieSet = &a & &b; let v: Vec = set.iter().collect(); assert_eq!(v, vec![2u, 3]); } @@ -857,7 +953,7 @@ mod test { let a: TrieSet = vec![1, 2, 3].into_iter().collect(); let b: TrieSet = vec![3, 4, 5].into_iter().collect(); - let set: TrieSet = a ^ b; + let set: TrieSet = &a ^ &b; let v: Vec = set.iter().collect(); assert_eq!(v, vec![1u, 2, 4, 5]); } @@ -867,7 +963,7 @@ mod test { let a: TrieSet = vec![1, 2, 3].into_iter().collect(); let b: TrieSet = vec![3, 4, 5].into_iter().collect(); - let set: TrieSet = a - b; + let set: TrieSet = &a - &b; let v: Vec = set.iter().collect(); assert_eq!(v, vec![1u, 2]); } From e00e4611a82641c61dd694ce9aa675b9d8ecf9a8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Dec 2014 16:29:02 -0500 Subject: [PATCH 29/30] libcollections: convert `TreeSet` binops to by value --- src/libcollections/tree/set.rs | 104 +++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/src/libcollections/tree/set.rs b/src/libcollections/tree/set.rs index bd8bf5c6cb6..1d3ec2eb7f2 100644 --- a/src/libcollections/tree/set.rs +++ b/src/libcollections/tree/set.rs @@ -668,6 +668,8 @@ impl<'a, T: Ord> Iterator<&'a T> for UnionItems<'a, T> { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitOr, TreeSet> for TreeSet { /// Returns the union of `self` and `rhs` as a new `TreeSet`. /// @@ -689,6 +691,30 @@ impl BitOr, TreeSet> for TreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitOr<&'b TreeSet, TreeSet> for &'a TreeSet { + /// Returns the union of `self` and `rhs` as a new `TreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::TreeSet; + /// + /// let a: TreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TreeSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TreeSet = &a | &b; + /// let v: Vec = set.into_iter().collect(); + /// assert_eq!(v, vec![1, 2, 3, 4, 5]); + /// ``` + fn bitor(self, rhs: &TreeSet) -> TreeSet { + self.union(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitAnd, TreeSet> for TreeSet { /// Returns the intersection of `self` and `rhs` as a new `TreeSet`. /// @@ -710,6 +736,30 @@ impl BitAnd, TreeSet> for TreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitAnd<&'b TreeSet, TreeSet> for &'a TreeSet { + /// Returns the intersection of `self` and `rhs` as a new `TreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::TreeSet; + /// + /// let a: TreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TreeSet = vec![2, 3, 4].into_iter().collect(); + /// + /// let set: TreeSet = &a & &b; + /// let v: Vec = set.into_iter().collect(); + /// assert_eq!(v, vec![2, 3]); + /// ``` + fn bitand(self, rhs: &TreeSet) -> TreeSet { + self.intersection(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitXor, TreeSet> for TreeSet { /// Returns the symmetric difference of `self` and `rhs` as a new `TreeSet`. /// @@ -731,6 +781,30 @@ impl BitXor, TreeSet> for TreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitXor<&'b TreeSet, TreeSet> for &'a TreeSet { + /// Returns the symmetric difference of `self` and `rhs` as a new `TreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::TreeSet; + /// + /// let a: TreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TreeSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TreeSet = &a ^ &b; + /// let v: Vec = set.into_iter().collect(); + /// assert_eq!(v, vec![1, 2, 4, 5]); + /// ``` + fn bitxor(self, rhs: &TreeSet) -> TreeSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub, TreeSet> for TreeSet { /// Returns the difference of `self` and `rhs` as a new `TreeSet`. /// @@ -751,6 +825,28 @@ impl Sub, TreeSet> for TreeSet { } } +#[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> Sub<&'b TreeSet, TreeSet> for &'a TreeSet { + /// Returns the difference of `self` and `rhs` as a new `TreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::TreeSet; + /// + /// let a: TreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TreeSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TreeSet = &a - &b; + /// let v: Vec = set.into_iter().collect(); + /// assert_eq!(v, vec![1, 2]); + /// ``` + fn sub(self, rhs: &TreeSet) -> TreeSet { + self.difference(rhs).cloned().collect() + } +} + impl FromIterator for TreeSet { fn from_iter>(iter: Iter) -> TreeSet { let mut set = TreeSet::new(); @@ -1032,7 +1128,7 @@ mod test { let a: TreeSet = vec![1, 3, 5, 9, 11, 16, 19, 24].into_iter().collect(); let b: TreeSet = vec![-2, 1, 5, 9, 13, 19].into_iter().collect(); - let set: TreeSet = a | b; + let set: TreeSet = &a | &b; let v: Vec = set.into_iter().collect(); assert_eq!(v, vec![-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]); } @@ -1042,7 +1138,7 @@ mod test { let a: TreeSet = vec![11, 1, 3, 77, 103, 5, -5].into_iter().collect(); let b: TreeSet = vec![2, 11, 77, -9, -42, 5, 3].into_iter().collect(); - let set: TreeSet = a & b; + let set: TreeSet = &a & &b; let v: Vec = set.into_iter().collect(); assert_eq!(v, vec![3, 5, 11, 77]); } @@ -1052,7 +1148,7 @@ mod test { let a: TreeSet = vec![1, 3, 5, 9, 11].into_iter().collect(); let b: TreeSet = vec![-2, 3, 9, 14, 22].into_iter().collect(); - let set: TreeSet = a ^ b; + let set: TreeSet = &a ^ &b; let v: Vec = set.into_iter().collect(); assert_eq!(v, vec![-2, 1, 5, 11, 14, 22]); } @@ -1062,7 +1158,7 @@ mod test { let a: TreeSet = vec![-5, 11, 22, 33, 40, 42].into_iter().collect(); let b: TreeSet = vec![-12, -5, 14, 23, 34, 38, 39, 50].into_iter().collect(); - let set: TreeSet = a - b; + let set: TreeSet = &a - &b; let v: Vec = set.into_iter().collect(); assert_eq!(v, vec![11, 22, 33, 40, 42]); } From 89d2061c8f1cc2bcd5e9bb8a97e214f482d5ff2c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Dec 2014 16:34:36 -0500 Subject: [PATCH 30/30] libcollections: convert `BTreeSet` binops to by value --- src/libcollections/btree/set.rs | 96 +++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index cd01c008fe1..d4c05e4b7d3 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -409,6 +409,8 @@ impl Default for BTreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl Sub,BTreeSet> for BTreeSet { /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. /// @@ -430,6 +432,30 @@ impl Sub,BTreeSet> for BTreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet, BTreeSet> for &'a BTreeSet { + /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let result: BTreeSet = &a - &b; + /// let result_vec: Vec = result.into_iter().collect(); + /// assert_eq!(result_vec, vec![1, 2]); + /// ``` + fn sub(self, rhs: &BTreeSet) -> BTreeSet { + self.difference(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitXor,BTreeSet> for BTreeSet { /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. /// @@ -451,6 +477,30 @@ impl BitXor,BTreeSet> for BTreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet, BTreeSet> for &'a BTreeSet { + /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet = vec![2, 3, 4].into_iter().collect(); + /// + /// let result: BTreeSet = &a ^ &b; + /// let result_vec: Vec = result.into_iter().collect(); + /// assert_eq!(result_vec, vec![1, 4]); + /// ``` + fn bitxor(self, rhs: &BTreeSet) -> BTreeSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitAnd,BTreeSet> for BTreeSet { /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. /// @@ -472,6 +522,30 @@ impl BitAnd,BTreeSet> for BTreeSet { } #[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet, BTreeSet> for &'a BTreeSet { + /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet = vec![2, 3, 4].into_iter().collect(); + /// + /// let result: BTreeSet = &a & &b; + /// let result_vec: Vec = result.into_iter().collect(); + /// assert_eq!(result_vec, vec![2, 3]); + /// ``` + fn bitand(self, rhs: &BTreeSet) -> BTreeSet { + self.intersection(rhs).cloned().collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +// NOTE(stage0): Remove impl after a snapshot +#[cfg(stage0)] impl BitOr,BTreeSet> for BTreeSet { /// Returns the union of `self` and `rhs` as a new `BTreeSet`. /// @@ -492,6 +566,28 @@ impl BitOr,BTreeSet> for BTreeSet { } } +#[unstable = "matches collection reform specification, waiting for dust to settle"] +#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot +impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet, BTreeSet> for &'a BTreeSet { + /// Returns the union of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let result: BTreeSet = &a | &b; + /// let result_vec: Vec = result.into_iter().collect(); + /// assert_eq!(result_vec, vec![1, 2, 3, 4, 5]); + /// ``` + fn bitor(self, rhs: &BTreeSet) -> BTreeSet { + self.union(rhs).cloned().collect() + } +} + impl Show for BTreeSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{"));