From 069529bc5cc14f63035609cdfae5b21ca7999d4b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Mar 2013 15:04:30 -0400 Subject: [PATCH] Autoref the argument to the index operator (#4920) --- src/libcore/ops.rs | 2 +- src/librustc/middle/astencode.rs | 10 ++-- src/librustc/middle/moves.rs | 28 +++------- src/librustc/middle/trans/expr.rs | 16 +++--- src/librustc/middle/typeck/check/mod.rs | 4 +- src/libstd/bitv.rs | 10 ++-- src/libstd/ebml.rs | 8 ++- src/test/run-pass/operator-overloading.rs | 4 +- src/test/run-pass/overload-index-operator.rs | 55 ++++++++++++++++++++ 9 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 src/test/run-pass/overload-index-operator.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 2f7fe1e4aa8b..d0623ef60407 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -77,5 +77,5 @@ pub trait Shr { #[lang="index"] pub trait Index { - fn index(&self, index: Index) -> Result; + fn index(&self, index: &Index) -> Result; } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 1e1dde330378..2ec5b59b9c55 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -342,7 +342,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item { } fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { - let chi_doc = par_doc[c::tag_tree as uint]; + let chi_doc = par_doc.get(c::tag_tree as uint); let d = &reader::Decoder(chi_doc); Decodable::decode(d) } @@ -1089,9 +1089,9 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { fn decode_side_tables(xcx: @ExtendedDecodeContext, ast_doc: ebml::Doc) { let dcx = xcx.dcx; - let tbl_doc = ast_doc[c::tag_table as uint]; + let tbl_doc = ast_doc.get(c::tag_table as uint); for reader::docs(tbl_doc) |tag, entry_doc| { - let id0 = entry_doc[c::tag_table_id as uint].as_int(); + let id0 = entry_doc.get(c::tag_table_id as uint).as_int(); let id = xcx.tr_id(id0); debug!(">> Side table document with tag 0x%x \ @@ -1103,7 +1103,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, } else if tag == (c::tag_table_moves_map as uint) { dcx.maps.moves_map.insert(id); } else { - let val_doc = entry_doc[c::tag_table_val as uint]; + let val_doc = entry_doc.get(c::tag_table_val as uint); let val_dsr = &reader::Decoder(val_doc); if tag == (c::tag_table_def as uint) { let def = decode_def(xcx, val_doc); @@ -1172,7 +1172,7 @@ fn encode_item_ast(ebml_w: writer::Encoder, item: @ast::item) { #[cfg(test)] fn decode_item_ast(par_doc: ebml::Doc) -> @ast::item { - let chi_doc = par_doc[c::tag_tree as uint]; + let chi_doc = par_doc.get(c::tag_tree as uint); let d = &reader::Decoder(chi_doc); @Decodable::decode(d) } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index d97ec6b99051..f5382d69174d 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -436,7 +436,7 @@ pub impl VisitContext { expr_unary(deref, base) => { // *base if !self.use_overloaded_operator( - expr, DontDerefArgs, base, [], visitor) + expr, base, [], visitor) { // Moving out of *base moves out of base. self.use_expr(base, comp_mode, visitor); @@ -450,7 +450,7 @@ pub impl VisitContext { expr_index(lhs, rhs) => { // lhs[rhs] if !self.use_overloaded_operator( - expr, DontDerefArgs, lhs, [rhs], visitor) + expr, lhs, [rhs], visitor) { self.use_expr(lhs, comp_mode, visitor); self.consume_expr(rhs, visitor); @@ -579,7 +579,7 @@ pub impl VisitContext { expr_unary(_, lhs) => { if !self.use_overloaded_operator( - expr, DontDerefArgs, lhs, [], visitor) + expr, lhs, [], visitor) { self.consume_expr(lhs, visitor); } @@ -587,7 +587,7 @@ pub impl VisitContext { expr_binary(_, lhs, rhs) => { if !self.use_overloaded_operator( - expr, DoDerefArgs, lhs, [rhs], visitor) + expr, lhs, [rhs], visitor) { self.consume_expr(lhs, visitor); self.consume_expr(rhs, visitor); @@ -659,7 +659,6 @@ pub impl VisitContext { fn use_overloaded_operator(&self, expr: @expr, - deref_args: DerefArgs, receiver_expr: @expr, arg_exprs: &[@expr], visitor: vt) -> bool @@ -670,21 +669,10 @@ pub impl VisitContext { self.use_receiver(expr.id, expr.span, receiver_expr, visitor); - // The deref_args stuff should eventually be converted into - // adjustments. Moreover, it should eventually be applied - // consistently to all overloaded operators. But that's not - // how it is today. - match deref_args { - DoDerefArgs => { - // we are always passing in a borrowed pointer, - // so it's always read mode: - for arg_exprs.each |arg_expr| { - self.use_expr(*arg_expr, Read, visitor); - } - } - DontDerefArgs => { - self.use_fn_args(expr.callee_id, arg_exprs, visitor); - } + // for overloaded operatrs, we are always passing in a + // borrowed pointer, so it's always read mode: + for arg_exprs.each |arg_expr| { + self.use_expr(*arg_expr, Read, visitor); } return true; diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 33576a682a7f..0da1a9acef21 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -766,18 +766,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_binary(_, lhs, rhs) => { // if not overloaded, would be RvalueDatumExpr - return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest, - DoAutorefArg); + return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest); } ast::expr_unary(_, subexpr) => { // if not overloaded, would be RvalueDatumExpr - return trans_overloaded_op(bcx, expr, subexpr, ~[], dest, - DontAutorefArg); + return trans_overloaded_op(bcx, expr, subexpr, ~[], dest); } ast::expr_index(base, idx) => { // if not overloaded, would be RvalueDatumExpr - return trans_overloaded_op(bcx, expr, base, ~[idx], dest, - DontAutorefArg); + return trans_overloaded_op(bcx, expr, base, ~[idx], dest); } ast::expr_cast(val, _) => { match ty::get(node_id_type(bcx, expr.id)).sty { @@ -1644,8 +1641,7 @@ fn trans_overloaded_op(bcx: block, expr: @ast::expr, rcvr: @ast::expr, +args: ~[@ast::expr], - dest: Dest, - +autoref_arg: AutorefArg) -> block + dest: Dest) -> block { let origin = *bcx.ccx().maps.method_map.get(&expr.id); let fty = node_id_type(bcx, expr.callee_id); @@ -1653,7 +1649,7 @@ fn trans_overloaded_op(bcx: block, bcx, expr.info(), fty, expr_ty(bcx, expr), |bcx| meth::trans_method_callee(bcx, expr.callee_id, rcvr, origin), - callee::ArgExprs(args), dest, autoref_arg); + callee::ArgExprs(args), dest, DoAutorefArg); } fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, @@ -1806,7 +1802,7 @@ fn trans_assign_op(bcx: block, // FIXME(#2528) evaluates the receiver twice!! let scratch = scratch_datum(bcx, dst_datum.ty, false); let bcx = trans_overloaded_op(bcx, expr, dst, ~[src], - SaveIn(scratch.val), DoAutorefArg); + SaveIn(scratch.val)); return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum); } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d568773f90f8..732026a3033a 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1549,7 +1549,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, lookup_op_method( fcx, ex, rhs_expr, rhs_t, fcx.tcx().sess.ident_of(mname), ~[], - DontDerefArgs, DontAutoderefReceiver, + DoDerefArgs, DontAutoderefReceiver, || { fcx.type_error_message(ex.span, |actual| { fmt!("cannot apply unary operator `%s` to type `%s`", @@ -2757,7 +2757,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expr.span, raw_base_t); let ret_ty = lookup_op_method(fcx, expr, base, resolved, tcx.sess.ident_of(~"index"), - ~[idx], DontDerefArgs, AutoderefReceiver, + ~[idx], DoDerefArgs, AutoderefReceiver, || { fcx.type_error_message(expr.span, |actual| fmt!("cannot index a value \ diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 3acc95a3aad6..8bac0fed3c92 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -437,7 +437,8 @@ pub impl Bitv { if offset >= bitv.nbits { 0 } else { - bitv[offset] as u8 << (7 - bit) + // NOTE cannot use bitv[offset] until snapshot + bitv.index(&offset) as u8 << (7 - bit) } } @@ -459,7 +460,8 @@ pub impl Bitv { * Transform self into a [bool] by turning each bit into a bool */ fn to_bools(&self) -> ~[bool] { - vec::from_fn(self.nbits, |i| self[i]) + // NOTE cannot use self[i] until snapshot + vec::from_fn(self.nbits, |i| self.index(&i)) } /** @@ -555,8 +557,8 @@ pub fn from_fn(len: uint, f: &fn(index: uint) -> bool) -> Bitv { } impl ops::Index for Bitv { - fn index(&self, i: uint) -> bool { - self.get(i) + fn index(&self, i: &uint) -> bool { + self.get(*i) } } diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 92898af2993d..b82616d386af 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -68,11 +68,9 @@ pub mod reader { // ebml reading - impl ops::Index for Doc { - fn index(&self, tag: uint) -> Doc { - unsafe { - get_doc(*self, tag) - } + pub impl Doc { + fn get(&self, tag: uint) -> Doc { + get_doc(*self, tag) } } diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index 9299e3e365e3..6f479140d73a 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -40,8 +40,8 @@ impl ops::Not for Point { } impl ops::Index for Point { - fn index(&self, +x: bool) -> int { - if x { self.x } else { self.y } + fn index(&self, +x: &bool) -> int { + if *x { self.x } else { self.y } } } diff --git a/src/test/run-pass/overload-index-operator.rs b/src/test/run-pass/overload-index-operator.rs new file mode 100644 index 000000000000..7d1d0c6be0e5 --- /dev/null +++ b/src/test/run-pass/overload-index-operator.rs @@ -0,0 +1,55 @@ +// Copyright 2012 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 overloading of the `[]` operator. In particular test that it +// takes its argument *by reference*. + +use core::ops::Index; + +struct AssociationList { + pairs: ~[AssociationPair] +} + +struct AssociationPair { + key: K, + value: V +} + +impl AssociationList { + fn push(&mut self, key: K, value: V) { + self.pairs.push(AssociationPair {key: key, value: value}); + } +} + +impl Index for AssociationList { + fn index(&self, index: &K) -> V { + for self.pairs.each |pair| { + if pair.key == *index { + return copy pair.value; + } + } + fail!(fmt!("No value found for key: %?", index)); + } +} + +pub fn main() { + let foo = ~"foo"; + let bar = ~"bar"; + + let mut list = AssociationList {pairs: ~[]}; + list.push(copy foo, 22); + list.push(copy bar, 44); + + fail_unless!(list[foo] == 22) + fail_unless!(list[bar] == 44) + + fail_unless!(list[foo] == 22) + fail_unless!(list[bar] == 44) +} \ No newline at end of file