mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-23 21:23:20 +00:00
Overloaded augmented assignments
This commit is contained in:
parent
fb5de8ce57
commit
3ae3a5fc3c
@ -927,6 +927,534 @@ macro_rules! shr_impl_all {
|
|||||||
|
|
||||||
shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
|
/// The `AddAssign` trait is used to specify the functionality of `+=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up
|
||||||
|
/// calling `add_assign`, and therefore, `main` prints `Adding!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::AddAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl AddAssign for Foo {
|
||||||
|
/// fn add_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Adding!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo += Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "add_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait AddAssign<Rhs=Self> {
|
||||||
|
/// The method for the `+=` operator
|
||||||
|
fn add_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! add_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl AddAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn add_assign(&mut self, other: $t) { *self += other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
||||||
|
|
||||||
|
/// The `SubAssign` trait is used to specify the functionality of `-=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up
|
||||||
|
/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::SubAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl SubAssign for Foo {
|
||||||
|
/// fn sub_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Subtracting!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo -= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "sub_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait SubAssign<Rhs=Self> {
|
||||||
|
/// The method for the `-=` operator
|
||||||
|
fn sub_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! sub_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl SubAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, other: $t) { *self -= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
sub_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
||||||
|
|
||||||
|
/// The `MulAssign` trait is used to specify the functionality of `*=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up
|
||||||
|
/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::MulAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl MulAssign for Foo {
|
||||||
|
/// fn mul_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Multiplying!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo *= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "mul_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait MulAssign<Rhs=Self> {
|
||||||
|
/// The method for the `*=` operator
|
||||||
|
fn mul_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! mul_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl MulAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, other: $t) { *self *= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
mul_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
||||||
|
|
||||||
|
/// The `DivAssign` trait is used to specify the functionality of `/=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up
|
||||||
|
/// calling `div_assign`, and therefore, `main` prints `Dividing!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::DivAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl DivAssign for Foo {
|
||||||
|
/// fn div_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Dividing!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo /= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "div_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait DivAssign<Rhs=Self> {
|
||||||
|
/// The method for the `/=` operator
|
||||||
|
fn div_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! div_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl DivAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn div_assign(&mut self, other: $t) { *self /= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
div_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
||||||
|
|
||||||
|
/// The `RemAssign` trait is used to specify the functionality of `%=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up
|
||||||
|
/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::RemAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl RemAssign for Foo {
|
||||||
|
/// fn rem_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Remainder-ing!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo %= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "rem_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait RemAssign<Rhs=Self> {
|
||||||
|
/// The method for the `%=` operator
|
||||||
|
fn rem_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! rem_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl RemAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn rem_assign(&mut self, other: $t) { *self %= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
||||||
|
|
||||||
|
/// The `BitAndAssign` trait is used to specify the functionality of `&=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `BitAndAssign`. When `Foo &= Foo` happens, it ends up
|
||||||
|
/// calling `bitand_assign`, and therefore, `main` prints `Bitwise And-ing!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::BitAndAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl BitAndAssign for Foo {
|
||||||
|
/// fn bitand_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Bitwise And-ing!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo &= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "bitand_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait BitAndAssign<Rhs=Self> {
|
||||||
|
/// The method for the `&` operator
|
||||||
|
fn bitand_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! bitand_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl BitAndAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn bitand_assign(&mut self, other: $t) { *self &= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
bitand_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||||
|
|
||||||
|
/// The `BitOrAssign` trait is used to specify the functionality of `|=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up
|
||||||
|
/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::BitOrAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl BitOrAssign for Foo {
|
||||||
|
/// fn bitor_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Bitwise Or-ing!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo |= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "bitor_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait BitOrAssign<Rhs=Self> {
|
||||||
|
/// The method for the `|=` operator
|
||||||
|
fn bitor_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! bitor_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl BitOrAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn bitor_assign(&mut self, other: $t) { *self |= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
bitor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||||
|
|
||||||
|
/// The `BitXorAssign` trait is used to specify the functionality of `^=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up
|
||||||
|
/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::BitXorAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl BitXorAssign for Foo {
|
||||||
|
/// fn bitxor_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Bitwise Xor-ing!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo ^= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "bitxor_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait BitXorAssign<Rhs=Self> {
|
||||||
|
/// The method for the `^=` operator
|
||||||
|
fn bitxor_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! bitxor_assign_impl {
|
||||||
|
($($t:ty)+) => ($(
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl BitXorAssign for $t {
|
||||||
|
#[inline]
|
||||||
|
fn bitxor_assign(&mut self, other: $t) { *self ^= other }
|
||||||
|
}
|
||||||
|
)+)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
bitxor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||||
|
|
||||||
|
/// The `ShlAssign` trait is used to specify the functionality of `<<=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up
|
||||||
|
/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::ShlAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl ShlAssign<Foo> for Foo {
|
||||||
|
/// fn shl_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Shifting left!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo <<= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "shl_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait ShlAssign<Rhs> {
|
||||||
|
/// The method for the `<<=` operator
|
||||||
|
fn shl_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! shl_assign_impl {
|
||||||
|
($t:ty, $f:ty) => (
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl ShlAssign<$f> for $t {
|
||||||
|
#[inline]
|
||||||
|
fn shl_assign(&mut self, other: $f) {
|
||||||
|
*self <<= other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! shl_assign_impl_all {
|
||||||
|
($($t:ty)*) => ($(
|
||||||
|
shl_assign_impl! { $t, u8 }
|
||||||
|
shl_assign_impl! { $t, u16 }
|
||||||
|
shl_assign_impl! { $t, u32 }
|
||||||
|
shl_assign_impl! { $t, u64 }
|
||||||
|
shl_assign_impl! { $t, usize }
|
||||||
|
|
||||||
|
shl_assign_impl! { $t, i8 }
|
||||||
|
shl_assign_impl! { $t, i16 }
|
||||||
|
shl_assign_impl! { $t, i32 }
|
||||||
|
shl_assign_impl! { $t, i64 }
|
||||||
|
shl_assign_impl! { $t, isize }
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
shl_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
|
/// The `ShrAssign` trait is used to specify the functionality of `>>=`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up
|
||||||
|
/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(augmented_assignments)]
|
||||||
|
/// #![feature(op_assign_traits)]
|
||||||
|
///
|
||||||
|
/// use std::ops::ShrAssign;
|
||||||
|
///
|
||||||
|
/// #[derive(Copy, Clone)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl ShrAssign<Foo> for Foo {
|
||||||
|
/// fn shr_assign(&mut self, _rhs: Foo) {
|
||||||
|
/// println!("Shifting right!");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut foo = Foo;
|
||||||
|
/// foo >>= Foo;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[lang = "shr_assign"]
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
pub trait ShrAssign<Rhs=Self> {
|
||||||
|
/// The method for the `>>=` operator
|
||||||
|
fn shr_assign(&mut self, Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! shr_assign_impl {
|
||||||
|
($t:ty, $f:ty) => (
|
||||||
|
#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
|
||||||
|
impl ShrAssign<$f> for $t {
|
||||||
|
#[inline]
|
||||||
|
fn shr_assign(&mut self, other: $f) {
|
||||||
|
*self >>= other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
macro_rules! shr_assign_impl_all {
|
||||||
|
($($t:ty)*) => ($(
|
||||||
|
shr_assign_impl! { $t, u8 }
|
||||||
|
shr_assign_impl! { $t, u16 }
|
||||||
|
shr_assign_impl! { $t, u32 }
|
||||||
|
shr_assign_impl! { $t, u64 }
|
||||||
|
shr_assign_impl! { $t, usize }
|
||||||
|
|
||||||
|
shr_assign_impl! { $t, i8 }
|
||||||
|
shr_assign_impl! { $t, i16 }
|
||||||
|
shr_assign_impl! { $t, i32 }
|
||||||
|
shr_assign_impl! { $t, i64 }
|
||||||
|
shr_assign_impl! { $t, isize }
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
/// The `Index` trait is used to specify the functionality of indexing operations
|
/// The `Index` trait is used to specify the functionality of indexing operations
|
||||||
/// like `arr[idx]` when used in an immutable context.
|
/// like `arr[idx]` when used in an immutable context.
|
||||||
///
|
///
|
||||||
|
@ -525,11 +525,17 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
|||||||
self.consume_expr(&**base);
|
self.consume_expr(&**base);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
|
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
||||||
// This will have to change if/when we support
|
let pass_args = if ::rustc_front::util::is_by_value_binop(op.node) {
|
||||||
// overloaded operators for `+=` and so forth.
|
PassArgs::ByValue
|
||||||
self.mutate_expr(expr, &**lhs, WriteAndRead);
|
} else {
|
||||||
self.consume_expr(&**rhs);
|
PassArgs::ByRef
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], pass_args) {
|
||||||
|
self.mutate_expr(expr, &**lhs, WriteAndRead);
|
||||||
|
self.consume_expr(&**rhs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprRepeat(ref base, ref count) => {
|
hir::ExprRepeat(ref base, ref count) => {
|
||||||
|
@ -286,6 +286,16 @@ lets_do_this! {
|
|||||||
BitOrTraitLangItem, "bitor", bitor_trait;
|
BitOrTraitLangItem, "bitor", bitor_trait;
|
||||||
ShlTraitLangItem, "shl", shl_trait;
|
ShlTraitLangItem, "shl", shl_trait;
|
||||||
ShrTraitLangItem, "shr", shr_trait;
|
ShrTraitLangItem, "shr", shr_trait;
|
||||||
|
AddAssignTraitLangItem, "add_assign", add_assign_trait;
|
||||||
|
SubAssignTraitLangItem, "sub_assign", sub_assign_trait;
|
||||||
|
MulAssignTraitLangItem, "mul_assign", mul_assign_trait;
|
||||||
|
DivAssignTraitLangItem, "div_assign", div_assign_trait;
|
||||||
|
RemAssignTraitLangItem, "rem_assign", rem_assign_trait;
|
||||||
|
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait;
|
||||||
|
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait;
|
||||||
|
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait;
|
||||||
|
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait;
|
||||||
|
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait;
|
||||||
IndexTraitLangItem, "index", index_trait;
|
IndexTraitLangItem, "index", index_trait;
|
||||||
IndexMutTraitLangItem, "index_mut", index_mut_trait;
|
IndexMutTraitLangItem, "index_mut", index_mut_trait;
|
||||||
RangeStructLangItem, "range", range_struct;
|
RangeStructLangItem, "range", range_struct;
|
||||||
|
@ -1018,7 +1018,20 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprAssignOp(op, ref dst, ref src) => {
|
hir::ExprAssignOp(op, ref dst, ref src) => {
|
||||||
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
let has_method_map = bcx.tcx()
|
||||||
|
.tables
|
||||||
|
.borrow()
|
||||||
|
.method_map
|
||||||
|
.contains_key(&MethodCall::expr(expr.id));
|
||||||
|
|
||||||
|
if has_method_map {
|
||||||
|
let dst = unpack_datum!(bcx, trans(bcx, &**dst));
|
||||||
|
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
|
||||||
|
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
|
||||||
|
Some((src_datum, src.id)), None, false).bcx
|
||||||
|
} else {
|
||||||
|
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hir::ExprInlineAsm(ref a) => {
|
hir::ExprInlineAsm(ref a) => {
|
||||||
asm::trans_inline_asm(bcx, a)
|
asm::trans_inline_asm(bcx, a)
|
||||||
@ -1207,8 +1220,11 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
// Trait casts used to come this way, now they should be coercions.
|
// Trait casts used to come this way, now they should be coercions.
|
||||||
bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
|
bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
|
||||||
}
|
}
|
||||||
hir::ExprAssignOp(op, ref dst, ref src) => {
|
hir::ExprAssignOp(op, _, _) => {
|
||||||
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
bcx.tcx().sess.span_bug(
|
||||||
|
expr.span,
|
||||||
|
&format!("augmented assignment `{}=` should always be a rvalue_stmt",
|
||||||
|
rustc_front::util::binop_to_string(op.node)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bcx.tcx().sess.span_bug(
|
bcx.tcx().sess.span_bug(
|
||||||
|
@ -17,10 +17,8 @@ use super::{
|
|||||||
demand,
|
demand,
|
||||||
method,
|
method,
|
||||||
FnCtxt,
|
FnCtxt,
|
||||||
structurally_resolved_type,
|
|
||||||
};
|
};
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use middle::traits;
|
|
||||||
use middle::ty::{Ty, HasTypeFlags, PreferMutLvalue};
|
use middle::ty::{Ty, HasTypeFlags, PreferMutLvalue};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
@ -34,34 +32,24 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||||||
lhs_expr: &'tcx hir::Expr,
|
lhs_expr: &'tcx hir::Expr,
|
||||||
rhs_expr: &'tcx hir::Expr)
|
rhs_expr: &'tcx hir::Expr)
|
||||||
{
|
{
|
||||||
let tcx = fcx.ccx.tcx;
|
|
||||||
|
|
||||||
check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue);
|
check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue);
|
||||||
check_expr(fcx, rhs_expr);
|
|
||||||
|
|
||||||
let lhs_ty = structurally_resolved_type(fcx, lhs_expr.span, fcx.expr_ty(lhs_expr));
|
let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
|
||||||
let rhs_ty = structurally_resolved_type(fcx, rhs_expr.span, fcx.expr_ty(rhs_expr));
|
let (rhs_ty, return_ty) =
|
||||||
|
check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, true);
|
||||||
|
let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty);
|
||||||
|
|
||||||
if is_builtin_binop(lhs_ty, rhs_ty, op) {
|
if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
|
||||||
enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
|
enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
|
||||||
fcx.write_nil(expr.id);
|
fcx.write_nil(expr.id);
|
||||||
} else {
|
} else {
|
||||||
// error types are considered "builtin"
|
fcx.write_ty(expr.id, return_ty);
|
||||||
assert!(!lhs_ty.references_error() || !rhs_ty.references_error());
|
|
||||||
span_err!(tcx.sess, lhs_expr.span, E0368,
|
|
||||||
"binary assignment operation `{}=` cannot be applied to types `{}` and `{}`",
|
|
||||||
hir_util::binop_to_string(op.node),
|
|
||||||
lhs_ty,
|
|
||||||
rhs_ty);
|
|
||||||
fcx.write_error(expr.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = fcx.tcx();
|
let tcx = fcx.tcx();
|
||||||
if !tcx.expr_is_lval(lhs_expr) {
|
if !tcx.expr_is_lval(lhs_expr) {
|
||||||
span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
|
span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
fcx.require_expr_have_sized_type(lhs_expr, traits::AssignmentLhsSized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a potentially overloaded binary operator.
|
/// Check a potentially overloaded binary operator.
|
||||||
@ -95,7 +83,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
// overloaded. This is the way to be most flexible w/r/t
|
// overloaded. This is the way to be most flexible w/r/t
|
||||||
// types that get inferred.
|
// types that get inferred.
|
||||||
let (rhs_ty, return_ty) =
|
let (rhs_ty, return_ty) =
|
||||||
check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op);
|
check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, false);
|
||||||
|
|
||||||
// Supply type inference hints if relevant. Probably these
|
// Supply type inference hints if relevant. Probably these
|
||||||
// hints should be enforced during select as part of the
|
// hints should be enforced during select as part of the
|
||||||
@ -167,14 +155,16 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
lhs_expr: &'tcx hir::Expr,
|
lhs_expr: &'tcx hir::Expr,
|
||||||
lhs_ty: Ty<'tcx>,
|
lhs_ty: Ty<'tcx>,
|
||||||
rhs_expr: &'tcx hir::Expr,
|
rhs_expr: &'tcx hir::Expr,
|
||||||
op: hir::BinOp)
|
op: hir::BinOp,
|
||||||
|
assign: bool)
|
||||||
-> (Ty<'tcx>, Ty<'tcx>)
|
-> (Ty<'tcx>, Ty<'tcx>)
|
||||||
{
|
{
|
||||||
debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?})",
|
debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, assign={})",
|
||||||
expr.id,
|
expr.id,
|
||||||
lhs_ty);
|
lhs_ty,
|
||||||
|
assign);
|
||||||
|
|
||||||
let (name, trait_def_id) = name_and_trait_def_id(fcx, op);
|
let (name, trait_def_id) = name_and_trait_def_id(fcx, op, assign);
|
||||||
|
|
||||||
// NB: As we have not yet type-checked the RHS, we don't have the
|
// NB: As we have not yet type-checked the RHS, we don't have the
|
||||||
// type at hand. Make a variable to represent it. The whole reason
|
// type at hand. Make a variable to represent it. The whole reason
|
||||||
@ -191,10 +181,17 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
Err(()) => {
|
Err(()) => {
|
||||||
// error types are considered "builtin"
|
// error types are considered "builtin"
|
||||||
if !lhs_ty.references_error() {
|
if !lhs_ty.references_error() {
|
||||||
span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
|
if assign {
|
||||||
"binary operation `{}` cannot be applied to type `{}`",
|
span_err!(fcx.tcx().sess, lhs_expr.span, E0368,
|
||||||
hir_util::binop_to_string(op.node),
|
"binary assignment operation `{}=` cannot be applied to type `{}`",
|
||||||
lhs_ty);
|
hir_util::binop_to_string(op.node),
|
||||||
|
lhs_ty);
|
||||||
|
} else {
|
||||||
|
span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
|
||||||
|
"binary operation `{}` cannot be applied to type `{}`",
|
||||||
|
hir_util::binop_to_string(op.node),
|
||||||
|
lhs_ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fcx.tcx().types.err
|
fcx.tcx().types.err
|
||||||
}
|
}
|
||||||
@ -231,27 +228,51 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_and_trait_def_id(fcx: &FnCtxt, op: hir::BinOp) -> (&'static str, Option<DefId>) {
|
fn name_and_trait_def_id(fcx: &FnCtxt,
|
||||||
|
op: hir::BinOp,
|
||||||
|
assign: bool)
|
||||||
|
-> (&'static str, Option<DefId>) {
|
||||||
let lang = &fcx.tcx().lang_items;
|
let lang = &fcx.tcx().lang_items;
|
||||||
match op.node {
|
|
||||||
hir::BiAdd => ("add", lang.add_trait()),
|
if assign {
|
||||||
hir::BiSub => ("sub", lang.sub_trait()),
|
match op.node {
|
||||||
hir::BiMul => ("mul", lang.mul_trait()),
|
hir::BiAdd => ("add_assign", lang.add_assign_trait()),
|
||||||
hir::BiDiv => ("div", lang.div_trait()),
|
hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
|
||||||
hir::BiRem => ("rem", lang.rem_trait()),
|
hir::BiMul => ("mul_assign", lang.mul_assign_trait()),
|
||||||
hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
|
hir::BiDiv => ("div_assign", lang.div_assign_trait()),
|
||||||
hir::BiBitAnd => ("bitand", lang.bitand_trait()),
|
hir::BiRem => ("rem_assign", lang.rem_assign_trait()),
|
||||||
hir::BiBitOr => ("bitor", lang.bitor_trait()),
|
hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
|
||||||
hir::BiShl => ("shl", lang.shl_trait()),
|
hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
|
||||||
hir::BiShr => ("shr", lang.shr_trait()),
|
hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
|
||||||
hir::BiLt => ("lt", lang.ord_trait()),
|
hir::BiShl => ("shl_assign", lang.shl_assign_trait()),
|
||||||
hir::BiLe => ("le", lang.ord_trait()),
|
hir::BiShr => ("shr_assign", lang.shr_assign_trait()),
|
||||||
hir::BiGe => ("ge", lang.ord_trait()),
|
hir::BiLt | hir::BiLe | hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd |
|
||||||
hir::BiGt => ("gt", lang.ord_trait()),
|
hir::BiOr => {
|
||||||
hir::BiEq => ("eq", lang.eq_trait()),
|
fcx.tcx().sess.span_bug(op.span, &format!("impossible assignment operation: {}=",
|
||||||
hir::BiNe => ("ne", lang.eq_trait()),
|
hir_util::binop_to_string(op.node)))
|
||||||
hir::BiAnd | hir::BiOr => {
|
}
|
||||||
fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable")
|
}
|
||||||
|
} else {
|
||||||
|
match op.node {
|
||||||
|
hir::BiAdd => ("add", lang.add_trait()),
|
||||||
|
hir::BiSub => ("sub", lang.sub_trait()),
|
||||||
|
hir::BiMul => ("mul", lang.mul_trait()),
|
||||||
|
hir::BiDiv => ("div", lang.div_trait()),
|
||||||
|
hir::BiRem => ("rem", lang.rem_trait()),
|
||||||
|
hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
|
||||||
|
hir::BiBitAnd => ("bitand", lang.bitand_trait()),
|
||||||
|
hir::BiBitOr => ("bitor", lang.bitor_trait()),
|
||||||
|
hir::BiShl => ("shl", lang.shl_trait()),
|
||||||
|
hir::BiShr => ("shr", lang.shr_trait()),
|
||||||
|
hir::BiLt => ("lt", lang.ord_trait()),
|
||||||
|
hir::BiLe => ("le", lang.ord_trait()),
|
||||||
|
hir::BiGe => ("ge", lang.ord_trait()),
|
||||||
|
hir::BiGt => ("gt", lang.ord_trait()),
|
||||||
|
hir::BiEq => ("eq", lang.eq_trait()),
|
||||||
|
hir::BiNe => ("ne", lang.eq_trait()),
|
||||||
|
hir::BiAnd | hir::BiOr => {
|
||||||
|
fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -695,7 +695,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
|
|||||||
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
|
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||||
if has_method_map {
|
if has_method_map {
|
||||||
constrain_call(rcx, expr, Some(&**lhs),
|
constrain_call(rcx, expr, Some(&**lhs),
|
||||||
Some(&**rhs).into_iter(), true);
|
Some(&**rhs).into_iter(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_expr(rcx, expr);
|
visit::walk_expr(rcx, expr);
|
||||||
|
@ -17,7 +17,7 @@ use astconv::AstConv;
|
|||||||
use check::FnCtxt;
|
use check::FnCtxt;
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use middle::ty::{self, Ty, MethodCall, MethodCallee};
|
use middle::ty::{self, Ty, MethodCall, MethodCallee, HasTypeFlags};
|
||||||
use middle::ty::adjustment;
|
use middle::ty::adjustment;
|
||||||
use middle::ty::fold::{TypeFolder,TypeFoldable};
|
use middle::ty::fold::{TypeFolder,TypeFoldable};
|
||||||
use middle::infer;
|
use middle::infer;
|
||||||
@ -91,24 +91,51 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
// we observe that something like `a+b` is (known to be)
|
// we observe that something like `a+b` is (known to be)
|
||||||
// operating on scalars, we clear the overload.
|
// operating on scalars, we clear the overload.
|
||||||
fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
|
fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
|
||||||
if let hir::ExprBinary(ref op, ref lhs, ref rhs) = e.node {
|
match e.node {
|
||||||
let lhs_ty = self.fcx.node_ty(lhs.id);
|
hir::ExprBinary(ref op, ref lhs, ref rhs) |
|
||||||
let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
|
hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
|
||||||
|
let lhs_ty = self.fcx.node_ty(lhs.id);
|
||||||
|
let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
|
||||||
|
|
||||||
let rhs_ty = self.fcx.node_ty(rhs.id);
|
let rhs_ty = self.fcx.node_ty(rhs.id);
|
||||||
let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
|
let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
|
||||||
|
|
||||||
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
|
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
|
||||||
self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
|
self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
|
||||||
|
|
||||||
// weird but true: the by-ref binops put an
|
// weird but true: the by-ref binops put an
|
||||||
// adjustment on the lhs but not the rhs; the
|
// adjustment on the lhs but not the rhs; the
|
||||||
// adjustment for rhs is kind of baked into the
|
// adjustment for rhs is kind of baked into the
|
||||||
// system.
|
// system.
|
||||||
if !hir_util::is_by_value_binop(op.node) {
|
match e.node {
|
||||||
self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
|
hir::ExprBinary(..) => {
|
||||||
|
if !hir_util::is_by_value_binop(op.node) {
|
||||||
|
self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hir::ExprAssignOp(..) => {
|
||||||
|
self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
if let hir::ExprAssignOp(..) = e.node {
|
||||||
|
if !tcx.sess.features.borrow().augmented_assignments &&
|
||||||
|
!self.fcx.expr_ty(e).references_error() {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
e.span,
|
||||||
|
"overloaded augmented assignments are not stable");
|
||||||
|
fileline_help!(
|
||||||
|
tcx.sess, e.span,
|
||||||
|
"add #![feature(augmented_assignments)] to the crate features \
|
||||||
|
to enable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2862,14 +2862,27 @@ impl <T: Foo> Drop for MyStructWrapper<T> {
|
|||||||
|
|
||||||
E0368: r##"
|
E0368: r##"
|
||||||
This error indicates that a binary assignment operator like `+=` or `^=` was
|
This error indicates that a binary assignment operator like `+=` or `^=` was
|
||||||
applied to the wrong types. For example:
|
applied to a type that doesn't support it. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
let mut x: u16 = 5;
|
let mut x = 12f32; // error: binary operation `<<` cannot be applied to
|
||||||
x ^= true; // error, `^=` cannot be applied to types `u16` and `bool`
|
// type `f32`
|
||||||
x += (); // error, `+=` cannot be applied to types `u16` and `()`
|
|
||||||
|
x <<= 2;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To fix this error, please check that this type implements this binary
|
||||||
|
operation. Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
let x = 12u32; // the `u32` type does implement the `ShlAssign` trait
|
||||||
|
|
||||||
|
x <<= 2; // ok!
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to overload most operators for your own type by
|
||||||
|
implementing the `[OP]Assign` traits from `std::ops`.
|
||||||
|
|
||||||
Another problem you might be facing is this: suppose you've overloaded the `+`
|
Another problem you might be facing is this: suppose you've overloaded the `+`
|
||||||
operator for some type `Foo` by implementing the `std::ops::Add` trait for
|
operator for some type `Foo` by implementing the `std::ops::Add` trait for
|
||||||
`Foo`, but you find that using `+=` does not work, as in this example:
|
`Foo`, but you find that using `+=` does not work, as in this example:
|
||||||
@ -2889,15 +2902,12 @@ impl Add for Foo {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut x: Foo = Foo(5);
|
let mut x: Foo = Foo(5);
|
||||||
x += Foo(7); // error, `+= cannot be applied to types `Foo` and `Foo`
|
x += Foo(7); // error, `+= cannot be applied to the type `Foo`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This is because the binary assignment operators currently do not work off of
|
This is because `AddAssign` is not automatically implemented, so you need to
|
||||||
traits, so it is not possible to overload them. See [RFC 953] for a proposal
|
manually implement it for your type.
|
||||||
to change this.
|
|
||||||
|
|
||||||
[RFC 953]: https://github.com/rust-lang/rfcs/pull/953
|
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0369: r##"
|
E0369: r##"
|
||||||
|
@ -194,6 +194,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
|
|||||||
|
|
||||||
// allow empty structs/enum variants with braces
|
// allow empty structs/enum variants with braces
|
||||||
("braced_empty_structs", "1.5.0", None, Active),
|
("braced_empty_structs", "1.5.0", None, Active),
|
||||||
|
|
||||||
|
// allow overloading augmented assignment operations like `a += b`
|
||||||
|
("augmented_assignments", "1.5.0", None, Active),
|
||||||
];
|
];
|
||||||
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
||||||
|
|
||||||
@ -457,6 +460,7 @@ pub struct Features {
|
|||||||
pub default_type_parameter_fallback: bool,
|
pub default_type_parameter_fallback: bool,
|
||||||
pub type_macros: bool,
|
pub type_macros: bool,
|
||||||
pub cfg_target_feature: bool,
|
pub cfg_target_feature: bool,
|
||||||
|
pub augmented_assignments: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Features {
|
impl Features {
|
||||||
@ -485,6 +489,7 @@ impl Features {
|
|||||||
default_type_parameter_fallback: false,
|
default_type_parameter_fallback: false,
|
||||||
type_macros: false,
|
type_macros: false,
|
||||||
cfg_target_feature: false,
|
cfg_target_feature: false,
|
||||||
|
augmented_assignments: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1053,6 +1058,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
|
|||||||
default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
|
default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
|
||||||
type_macros: cx.has_feature("type_macros"),
|
type_macros: cx.has_feature("type_macros"),
|
||||||
cfg_target_feature: cx.has_feature("cfg_target_feature"),
|
cfg_target_feature: cx.has_feature("cfg_target_feature"),
|
||||||
|
augmented_assignments: cx.has_feature("augmented_assignments"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
src/test/auxiliary/augmented_assignments.rs
Normal file
22
src/test/auxiliary/augmented_assignments.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(augmented_assignments)]
|
||||||
|
#![feature(op_assign_traits)]
|
||||||
|
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
|
pub struct Int(i32);
|
||||||
|
|
||||||
|
impl AddAssign<i32> for Int {
|
||||||
|
fn add_assign(&mut self, _: i32) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
@ -13,5 +13,5 @@ struct Foo;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let mut a = Foo;
|
let mut a = Foo;
|
||||||
let ref b = Foo;
|
let ref b = Foo;
|
||||||
a += *b; //~ Error: binary assignment operation `+=` cannot be applied to types `Foo` and `Foo`
|
a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo`
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:augmented_assignments.rs
|
||||||
|
|
||||||
|
// Test that the feature gate is needed when using augmented assignments that were overloaded in
|
||||||
|
// another crate
|
||||||
|
|
||||||
|
extern crate augmented_assignments;
|
||||||
|
|
||||||
|
use augmented_assignments::Int;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = Int(0);
|
||||||
|
x += 1;
|
||||||
|
//~^ error: overloaded augmented assignments are not stable
|
||||||
|
// | help: add #![feature(augmented_assignments)] to the crate features to enable
|
||||||
|
}
|
26
src/test/compile-fail/augmented-assignments-feature-gate.rs
Normal file
26
src/test/compile-fail/augmented-assignments-feature-gate.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
|
struct Int(i32);
|
||||||
|
|
||||||
|
impl AddAssign<i32> for Int {
|
||||||
|
fn add_assign(&mut self, _: i32) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = Int(0);
|
||||||
|
x += 1;
|
||||||
|
//~^ error: overloaded augmented assignments are not stable
|
||||||
|
// | help: add #![feature(augmented_assignments)] to the crate features to enable
|
||||||
|
}
|
33
src/test/compile-fail/augmented-assignments.rs
Normal file
33
src/test/compile-fail/augmented-assignments.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(augmented_assignments)]
|
||||||
|
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
|
struct Int(i32);
|
||||||
|
|
||||||
|
impl AddAssign for Int {
|
||||||
|
fn add_assign(&mut self, _: Int) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = Int(1);
|
||||||
|
x //~ error: use of moved value: `x`
|
||||||
|
+=
|
||||||
|
x; //~ note: `x` moved here because it has type `Int`, which is non-copyable
|
||||||
|
|
||||||
|
let y = Int(2);
|
||||||
|
y //~ error: cannot borrow immutable local variable `y` as mutable
|
||||||
|
+=
|
||||||
|
Int(1);
|
||||||
|
}
|
164
src/test/run-pass/augmented-assignments.rs
Normal file
164
src/test/run-pass/augmented-assignments.rs
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Copyright 2015 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(augmented_assignments)]
|
||||||
|
#![feature(op_assign_traits)]
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{
|
||||||
|
AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, Index, MulAssign, RemAssign,
|
||||||
|
ShlAssign, ShrAssign, SubAssign,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Int(i32);
|
||||||
|
|
||||||
|
struct Slice([i32]);
|
||||||
|
|
||||||
|
impl Slice {
|
||||||
|
fn new(slice: &mut [i32]) -> &mut Slice {
|
||||||
|
unsafe {
|
||||||
|
mem::transmute(slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = Int(1);
|
||||||
|
|
||||||
|
x += Int(2);
|
||||||
|
assert_eq!(x, Int(0b11));
|
||||||
|
|
||||||
|
x &= Int(0b01);
|
||||||
|
assert_eq!(x, Int(0b01));
|
||||||
|
|
||||||
|
x |= Int(0b10);
|
||||||
|
assert_eq!(x, Int(0b11));
|
||||||
|
|
||||||
|
x ^= Int(0b01);
|
||||||
|
assert_eq!(x, Int(0b10));
|
||||||
|
|
||||||
|
x /= Int(2);
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
x *= Int(3);
|
||||||
|
assert_eq!(x, Int(3));
|
||||||
|
|
||||||
|
x %= Int(2);
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
// overloaded RHS
|
||||||
|
x <<= 1u8;
|
||||||
|
assert_eq!(x, Int(2));
|
||||||
|
|
||||||
|
x <<= 1u16;
|
||||||
|
assert_eq!(x, Int(4));
|
||||||
|
|
||||||
|
x >>= 1u8;
|
||||||
|
assert_eq!(x, Int(2));
|
||||||
|
|
||||||
|
x >>= 1u16;
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
x -= Int(1);
|
||||||
|
assert_eq!(x, Int(0));
|
||||||
|
|
||||||
|
// indexed LHS
|
||||||
|
let mut v = vec![Int(1), Int(2)];
|
||||||
|
v[0] += Int(2);
|
||||||
|
assert_eq!(v[0], Int(3));
|
||||||
|
|
||||||
|
// unsized RHS
|
||||||
|
let mut array = [0, 1, 2];
|
||||||
|
*Slice::new(&mut array) += 1;
|
||||||
|
assert_eq!(array[0], 1);
|
||||||
|
assert_eq!(array[1], 2);
|
||||||
|
assert_eq!(array[2], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Int {
|
||||||
|
fn add_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 += rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAndAssign for Int {
|
||||||
|
fn bitand_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 &= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOrAssign for Int {
|
||||||
|
fn bitor_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 |= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitXorAssign for Int {
|
||||||
|
fn bitxor_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 ^= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DivAssign for Int {
|
||||||
|
fn div_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 /= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for Int {
|
||||||
|
fn mul_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 *= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemAssign for Int {
|
||||||
|
fn rem_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 %= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShlAssign<u8> for Int {
|
||||||
|
fn shl_assign(&mut self, rhs: u8) {
|
||||||
|
self.0 <<= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShlAssign<u16> for Int {
|
||||||
|
fn shl_assign(&mut self, rhs: u16) {
|
||||||
|
self.0 <<= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShrAssign<u8> for Int {
|
||||||
|
fn shr_assign(&mut self, rhs: u8) {
|
||||||
|
self.0 >>= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShrAssign<u16> for Int {
|
||||||
|
fn shr_assign(&mut self, rhs: u16) {
|
||||||
|
self.0 >>= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Int {
|
||||||
|
fn sub_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 -= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<i32> for Slice {
|
||||||
|
fn add_assign(&mut self, rhs: i32) {
|
||||||
|
for lhs in &mut self.0 {
|
||||||
|
*lhs += rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user