Skip to content

Commit f940800

Browse files
author
Jorge Aparicio
committed
add lang items, update typeck/trans and add tests
1 parent 3986181 commit f940800

File tree

6 files changed

+235
-24
lines changed

6 files changed

+235
-24
lines changed

src/librustc/middle/expr_use_visitor.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,15 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
584584
}
585585

586586
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
587-
// This will have to change if/when we support
588-
// overloaded operators for `+=` and so forth.
589587
self.mutate_expr(expr, &**lhs, WriteAndRead);
590-
self.consume_expr(&**rhs);
588+
589+
if self.typer.is_method_call(expr.id) {
590+
let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
591+
self.borrow_expr(rhs, r, ty::ImmBorrow, OverloadedOperator);
592+
} else {
593+
// built-in assignment operations consume the RHS
594+
self.consume_expr(&**rhs);
595+
}
591596
}
592597

593598
ast::ExprRepeat(ref base, ref count) => {

src/librustc/middle/lang_items.rs

+11
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@ lets_do_this! {
265265
RangeToStructLangItem, "range_to", range_to_struct;
266266
RangeFullStructLangItem, "range_full", range_full_struct;
267267

268+
AddAssignTraitLangItem, "add_assign", add_assign_trait;
269+
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait;
270+
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait;
271+
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait;
272+
DivAssignTraitLangItem, "div_assign", div_assign_trait;
273+
MulAssignTraitLangItem, "mul_assign", mul_assign_trait;
274+
RemAssignTraitLangItem, "rem_assign", rem_assign_trait;
275+
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait;
276+
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait;
277+
SubAssignTraitLangItem, "sub_assign", sub_assign_trait;
278+
268279
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type;
269280

270281
DerefTraitLangItem, "deref", deref_trait;

src/librustc_trans/trans/expr.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,15 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10051005
}
10061006
}
10071007
ast::ExprAssignOp(op, ref dst, ref src) => {
1008-
trans_assign_op(bcx, expr, op, &**dst, &**src)
1008+
if ty::is_binopable(bcx.tcx(), node_id_type(bcx, dst.id), op) {
1009+
trans_assign_op(bcx, expr, op, &**dst, &**src)
1010+
} else {
1011+
let dst = unpack_datum!(bcx, trans(bcx, &**dst));
1012+
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
1013+
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
1014+
vec![(src_datum, src.id)], None,
1015+
true).bcx
1016+
}
10091017
}
10101018
ast::ExprInlineAsm(ref a) => {
10111019
asm::trans_inline_asm(bcx, a)
@@ -1203,8 +1211,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
12031211
"expr_cast of non-trait");
12041212
}
12051213
}
1206-
ast::ExprAssignOp(op, ref dst, ref src) => {
1207-
trans_assign_op(bcx, expr, op, &**dst, &**src)
1214+
ast::ExprAssignOp(..) => {
1215+
bcx.tcx().sess.span_bug(expr.span,
1216+
"operator assignment (`+=`) should always be an rvalue_stmt");
12081217
}
12091218
_ => {
12101219
bcx.tcx().sess.span_bug(

src/librustc_typeck/check/mod.rs

+38-18
Original file line numberDiff line numberDiff line change
@@ -2988,19 +2988,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
29882988
let result_t = if is_binop_assignment == SimpleBinop {
29892989
check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
29902990
} else {
2991-
fcx.type_error_message(expr.span,
2992-
|actual| {
2993-
format!("binary assignment \
2994-
operation `{}=` \
2995-
cannot be applied to \
2996-
type `{}`",
2997-
ast_util::binop_to_string(op.node),
2998-
actual)
2999-
},
3000-
lhs_t,
3001-
None);
3002-
check_expr(fcx, &**rhs);
3003-
fcx.tcx().types.err
2991+
check_user_binop_assign(fcx, expr, lhs, lhs_t, op, rhs)
30042992
};
30052993

30062994
fcx.write_ty(expr.id, result_t);
@@ -3049,6 +3037,42 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
30493037
}, if ast_util::is_by_value_binop(op.node) { AutorefArgs::No } else { AutorefArgs::Yes })
30503038
}
30513039

3040+
fn check_user_binop_assign<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3041+
ex: &'tcx ast::Expr,
3042+
lhs_expr: &'tcx ast::Expr,
3043+
lhs_resolved_t: Ty<'tcx>,
3044+
op: ast::BinOp,
3045+
rhs: &'tcx P<ast::Expr>) -> Ty<'tcx> {
3046+
let tcx = fcx.ccx.tcx;
3047+
let lang = &tcx.lang_items;
3048+
let (name, trait_did) = match op.node {
3049+
ast::BiAdd => ("add_assign", lang.add_assign_trait()),
3050+
ast::BiSub => ("sub_assign", lang.sub_assign_trait()),
3051+
ast::BiMul => ("mul_assign", lang.mul_assign_trait()),
3052+
ast::BiDiv => ("div_assign", lang.div_assign_trait()),
3053+
ast::BiRem => ("rem_assign", lang.rem_assign_trait()),
3054+
ast::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
3055+
ast::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
3056+
ast::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
3057+
ast::BiShl => ("shl_assign", lang.shl_assign_trait()),
3058+
ast::BiShr => ("shr_assign", lang.shr_assign_trait()),
3059+
ast::BiLt | ast::BiLe | ast::BiGe | ast::BiGt | ast::BiEq | ast::BiNe | ast::BiAnd |
3060+
ast::BiOr =>
3061+
{
3062+
check_expr(fcx, &**rhs);
3063+
return tcx.types.err;
3064+
}
3065+
};
3066+
lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
3067+
trait_did, lhs_expr, Some(rhs), || {
3068+
fcx.type_error_message(ex.span, |actual| {
3069+
format!("binary operation `{}=` cannot be applied to type `{}`",
3070+
ast_util::binop_to_string(op.node),
3071+
actual)
3072+
}, lhs_resolved_t, None)
3073+
}, AutorefArgs::Yes)
3074+
}
3075+
30523076
fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
30533077
op_str: &str,
30543078
mname: &str,
@@ -3480,10 +3504,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
34803504
ast::ExprAssignOp(op, ref lhs, ref rhs) => {
34813505
check_binop(fcx, expr, op, &**lhs, rhs, BinopAssignment);
34823506

3483-
let lhs_t = fcx.expr_ty(&**lhs);
3484-
let result_t = fcx.expr_ty(expr);
3485-
demand::suptype(fcx, expr.span, result_t, lhs_t);
3486-
34873507
let tcx = fcx.tcx();
34883508
if !ty::expr_is_lval(tcx, &**lhs) {
34893509
span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression");
@@ -3494,7 +3514,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
34943514
// Overwrite result of check_binop...this preserves existing behavior
34953515
// but seems quite dubious with regard to user-defined methods
34963516
// and so forth. - Niko
3497-
if !ty::type_is_error(result_t) {
3517+
if !ty::type_is_error(fcx.expr_ty(expr)) {
34983518
fcx.write_nil(expr.id);
34993519
}
35003520
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::AddAssign;
12+
13+
struct Int(i32);
14+
15+
impl AddAssign for Int {
16+
fn add_assign(&mut self, rhs: &Int) {
17+
self.0 += rhs.0
18+
}
19+
}
20+
21+
fn main() {
22+
let mut x = Int(1);
23+
x //~ error: cannot borrow `x` as mutable because it is also borrowed as immutable
24+
+=
25+
x; //~ note: previous borrow of `x` occurs here
26+
27+
let y = Int(2);
28+
y //~ error: cannot borrow immutable local variable `y` as mutable
29+
+=
30+
Int(1);
31+
}

src/test/run-pass/op-assign.rs

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::{
12+
AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, ShlAssign,
13+
ShrAssign, SubAssign,
14+
};
15+
16+
#[derive(Debug, PartialEq)]
17+
struct Int(i32);
18+
19+
fn main() {
20+
let mut x = Int(1);
21+
22+
x += Int(2);
23+
assert_eq!(x, Int(0b11));
24+
25+
x &= Int(0b01);
26+
assert_eq!(x, Int(0b01));
27+
28+
x |= Int(0b10);
29+
assert_eq!(x, Int(0b11));
30+
31+
x ^= Int(0b01);
32+
assert_eq!(x, Int(0b10));
33+
34+
x /= Int(2);
35+
assert_eq!(x, Int(1));
36+
37+
x *= Int(3);
38+
assert_eq!(x, Int(3));
39+
40+
x %= Int(2);
41+
assert_eq!(x, Int(1));
42+
43+
// overloaded RHS
44+
x <<= 1u8;
45+
assert_eq!(x, Int(2));
46+
47+
x <<= 1u16;
48+
assert_eq!(x, Int(4));
49+
50+
x >>= 1u8;
51+
assert_eq!(x, Int(2));
52+
53+
x >>= 1u16;
54+
assert_eq!(x, Int(1));
55+
56+
x -= Int(1);
57+
assert_eq!(x, Int(0));
58+
59+
// indexing
60+
let mut v = vec![Int(1), Int(2)];
61+
v[0] += Int(2);
62+
assert_eq!(v[0], Int(3));
63+
}
64+
65+
impl AddAssign for Int {
66+
fn add_assign(&mut self, rhs: &Int) {
67+
self.0 += rhs.0;
68+
}
69+
}
70+
71+
impl BitAndAssign for Int {
72+
fn bitand_assign(&mut self, rhs: &Int) {
73+
self.0 &= rhs.0;
74+
}
75+
}
76+
77+
impl BitOrAssign for Int {
78+
fn bitor_assign(&mut self, rhs: &Int) {
79+
self.0 |= rhs.0;
80+
}
81+
}
82+
83+
impl BitXorAssign for Int {
84+
fn bitxor_assign(&mut self, rhs: &Int) {
85+
self.0 ^= rhs.0;
86+
}
87+
}
88+
89+
impl DivAssign for Int {
90+
fn div_assign(&mut self, rhs: &Int) {
91+
self.0 /= rhs.0;
92+
}
93+
}
94+
95+
impl MulAssign for Int {
96+
fn mul_assign(&mut self, rhs: &Int) {
97+
self.0 *= rhs.0;
98+
}
99+
}
100+
101+
impl RemAssign for Int {
102+
fn rem_assign(&mut self, rhs: &Int) {
103+
self.0 %= rhs.0;
104+
}
105+
}
106+
107+
impl ShlAssign<u8> for Int {
108+
fn shl_assign(&mut self, &rhs: &u8) {
109+
self.0 <<= rhs;
110+
}
111+
}
112+
113+
impl ShlAssign<u16> for Int {
114+
fn shl_assign(&mut self, &rhs: &u16) {
115+
self.0 <<= rhs;
116+
}
117+
}
118+
119+
impl ShrAssign<u8> for Int {
120+
fn shr_assign(&mut self, &rhs: &u8) {
121+
self.0 >>= rhs;
122+
}
123+
}
124+
125+
impl ShrAssign<u16> for Int {
126+
fn shr_assign(&mut self, &rhs: &u16) {
127+
self.0 >>= rhs;
128+
}
129+
}
130+
131+
impl SubAssign for Int {
132+
fn sub_assign(&mut self, rhs: &Int) {
133+
self.0 -= rhs.0;
134+
}
135+
}

0 commit comments

Comments
 (0)