mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
auto merge of #15394 : pcwalton/rust/new-index-traits, r=nick29581
This will break code that used the old `Index` trait. Change this code to use the new `Index` traits. For reference, here are their signatures: pub trait Index<Index,Result> { fn index<'a>(&'a self, index: &Index) -> &'a Result; } pub trait IndexMut<Index,Result> { fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result; } Closes #6515. [breaking-change] r? @nick29581
This commit is contained in:
commit
00cdd639a9
@ -65,7 +65,7 @@ syn keyword rustTrait Copy Send Sized Share
|
|||||||
syn keyword rustTrait Add Sub Mul Div Rem Neg Not
|
syn keyword rustTrait Add Sub Mul Div Rem Neg Not
|
||||||
syn keyword rustTrait BitAnd BitOr BitXor
|
syn keyword rustTrait BitAnd BitOr BitXor
|
||||||
syn keyword rustTrait Drop Deref DerefMut
|
syn keyword rustTrait Drop Deref DerefMut
|
||||||
syn keyword rustTrait Shl Shr Index
|
syn keyword rustTrait Shl Shr Index IndexMut
|
||||||
syn keyword rustEnum Option
|
syn keyword rustEnum Option
|
||||||
syn keyword rustEnumVariant Some None
|
syn keyword rustEnumVariant Some None
|
||||||
syn keyword rustEnum Result
|
syn keyword rustEnum Result
|
||||||
|
@ -16,7 +16,6 @@ use core::cmp;
|
|||||||
use core::default::Default;
|
use core::default::Default;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::Take;
|
use core::iter::Take;
|
||||||
use core::ops;
|
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::uint;
|
use core::uint;
|
||||||
use std::hash;
|
use std::hash;
|
||||||
@ -24,6 +23,29 @@ use std::hash;
|
|||||||
use {Collection, Mutable, Set, MutableSet};
|
use {Collection, Mutable, Set, MutableSet};
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
use core::ops::Index;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
static TRUE: bool = true;
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
static FALSE: bool = false;
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
struct SmallBitv {
|
||||||
|
/// only the lowest nbits of this value are used. the rest is undefined.
|
||||||
|
bits: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
struct BigBitv {
|
||||||
|
storage: Vec<uint>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
enum BitvVariant { Big(BigBitv), Small(SmallBitv) }
|
||||||
|
|
||||||
/// The bitvector type
|
/// The bitvector type
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -58,6 +80,18 @@ pub struct Bitv {
|
|||||||
nbits: uint
|
nbits: uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
impl Index<uint,bool> for Bitv {
|
||||||
|
#[inline]
|
||||||
|
fn index<'a>(&'a self, i: &uint) -> &'a bool {
|
||||||
|
if self.get(*i) {
|
||||||
|
&TRUE
|
||||||
|
} else {
|
||||||
|
&FALSE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct MaskWords<'a> {
|
struct MaskWords<'a> {
|
||||||
iter: slice::Items<'a, uint>,
|
iter: slice::Items<'a, uint>,
|
||||||
next_word: Option<&'a uint>,
|
next_word: Option<&'a uint>,
|
||||||
@ -268,7 +302,7 @@ impl Bitv {
|
|||||||
if offset >= bitv.nbits {
|
if offset >= bitv.nbits {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
bitv[offset] as u8 << (7 - bit)
|
bitv.get(offset) as u8 << (7 - bit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,6 +320,13 @@ impl Bitv {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform `self` into a `Vec<bool>` by turning each bit into a `bool`.
|
||||||
|
*/
|
||||||
|
pub fn to_bools(&self) -> Vec<bool> {
|
||||||
|
Vec::from_fn(self.nbits, |i| self.get(i))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare a bitvector to a vector of `bool`.
|
* Compare a bitvector to a vector of `bool`.
|
||||||
*
|
*
|
||||||
@ -504,13 +545,6 @@ impl Clone for Bitv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<uint,bool> for Bitv {
|
|
||||||
#[inline]
|
|
||||||
fn index(&self, i: &uint) -> bool {
|
|
||||||
self.get(*i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Show for Bitv {
|
impl fmt::Show for Bitv {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for bit in self.iter() {
|
for bit in self.iter() {
|
||||||
@ -1369,9 +1403,9 @@ mod tests {
|
|||||||
b2.set(1, true);
|
b2.set(1, true);
|
||||||
b2.set(2, true);
|
b2.set(2, true);
|
||||||
assert!(b1.difference(&b2));
|
assert!(b1.difference(&b2));
|
||||||
assert!(b1[0]);
|
assert!(b1.get(0));
|
||||||
assert!(!b1[1]);
|
assert!(!b1.get(1));
|
||||||
assert!(!b1[2]);
|
assert!(!b1.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1383,9 +1417,9 @@ mod tests {
|
|||||||
b2.set(40, true);
|
b2.set(40, true);
|
||||||
b2.set(80, true);
|
b2.set(80, true);
|
||||||
assert!(b1.difference(&b2));
|
assert!(b1.difference(&b2));
|
||||||
assert!(b1[0]);
|
assert!(b1.get(0));
|
||||||
assert!(!b1[40]);
|
assert!(!b1.get(40));
|
||||||
assert!(!b1[80]);
|
assert!(!b1.get(80));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -613,7 +613,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 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]`.
|
* like `arr[idx]` when used in an immutable context.
|
||||||
*
|
*
|
||||||
* # Example
|
* # Example
|
||||||
*
|
*
|
||||||
@ -624,9 +624,9 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
|||||||
* struct Foo;
|
* struct Foo;
|
||||||
*
|
*
|
||||||
* impl Index<Foo, Foo> for Foo {
|
* impl Index<Foo, Foo> for Foo {
|
||||||
* fn index(&self, _rhs: &Foo) -> Foo {
|
* fn index<'a>(&'a self, _rhs: &Foo) -> &'a Foo {
|
||||||
* println!("Indexing!");
|
* println!("Indexing!");
|
||||||
* *self
|
* self
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
@ -636,9 +636,42 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
#[lang="index"]
|
#[lang="index"]
|
||||||
|
#[cfg(not(stage0))]
|
||||||
pub trait Index<Index,Result> {
|
pub trait Index<Index,Result> {
|
||||||
/// The method for the indexing (`Foo[Bar]`) operation
|
/// The method for the indexing (`Foo[Bar]`) operation
|
||||||
fn index(&self, index: &Index) -> Result;
|
fn index<'a>(&'a self, index: &Index) -> &'a Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The `IndexMut` trait is used to specify the functionality of indexing
|
||||||
|
* operations like `arr[idx]`, when used in a mutable context.
|
||||||
|
*
|
||||||
|
* # Example
|
||||||
|
*
|
||||||
|
* A trivial implementation of `IndexMut`. When `Foo[Foo]` happens, it ends up
|
||||||
|
* calling `index`, and therefore, `main` prints `Indexing!`.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* struct Foo;
|
||||||
|
*
|
||||||
|
* impl IndexMut<Foo, Foo> for Foo {
|
||||||
|
* fn index_mut<'a>(&'a mut self, _rhs: &Foo) -> &'a mut Foo {
|
||||||
|
* println!("Indexing!");
|
||||||
|
* self
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* fn main() {
|
||||||
|
* &mut Foo[Foo];
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
#[lang="index_mut"]
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub trait IndexMut<Index,Result> {
|
||||||
|
/// The method for the indexing (`Foo[Bar]`) operation
|
||||||
|
fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,9 @@ pub use kinds::{Copy, Send, Sized, Share};
|
|||||||
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
||||||
pub use ops::{BitAnd, BitOr, BitXor};
|
pub use ops::{BitAnd, BitOr, BitXor};
|
||||||
pub use ops::{Drop, Deref, DerefMut};
|
pub use ops::{Drop, Deref, DerefMut};
|
||||||
pub use ops::{Shl, Shr, Index};
|
pub use ops::{Shl, Shr};
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub use ops::{Index, IndexMut};
|
||||||
pub use option::{Option, Some, None};
|
pub use option::{Option, Some, None};
|
||||||
pub use result::{Result, Ok, Err};
|
pub use result::{Result, Ok, Err};
|
||||||
|
|
||||||
|
@ -234,6 +234,7 @@ lets_do_this! {
|
|||||||
ShlTraitLangItem, "shl", shl_trait;
|
ShlTraitLangItem, "shl", shl_trait;
|
||||||
ShrTraitLangItem, "shr", shr_trait;
|
ShrTraitLangItem, "shr", shr_trait;
|
||||||
IndexTraitLangItem, "index", index_trait;
|
IndexTraitLangItem, "index", index_trait;
|
||||||
|
IndexMutTraitLangItem, "index_mut", index_mut_trait;
|
||||||
|
|
||||||
UnsafeTypeLangItem, "unsafe", unsafe_type;
|
UnsafeTypeLangItem, "unsafe", unsafe_type;
|
||||||
|
|
||||||
|
@ -443,10 +443,6 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprIndex(ref base, _) => {
|
ast::ExprIndex(ref base, _) => {
|
||||||
if self.typer.is_method_call(expr.id) {
|
|
||||||
return Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty));
|
|
||||||
}
|
|
||||||
|
|
||||||
let base_cmt = if_ok!(self.cat_expr(&**base));
|
let base_cmt = if_ok!(self.cat_expr(&**base));
|
||||||
Ok(self.cat_index(expr, base_cmt, 0))
|
Ok(self.cat_index(expr, base_cmt, 0))
|
||||||
}
|
}
|
||||||
@ -759,7 +755,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
|||||||
|
|
||||||
pub fn cat_index<N:ast_node>(&self,
|
pub fn cat_index<N:ast_node>(&self,
|
||||||
elt: &N,
|
elt: &N,
|
||||||
base_cmt: cmt,
|
mut base_cmt: cmt,
|
||||||
derefs: uint)
|
derefs: uint)
|
||||||
-> cmt {
|
-> cmt {
|
||||||
//! Creates a cmt for an indexing operation (`[]`); this
|
//! Creates a cmt for an indexing operation (`[]`); this
|
||||||
@ -793,14 +789,26 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
|||||||
//! - `derefs`: the deref number to be used for
|
//! - `derefs`: the deref number to be used for
|
||||||
//! the implicit index deref, if any (see above)
|
//! the implicit index deref, if any (see above)
|
||||||
|
|
||||||
let element_ty = match ty::array_element_ty(base_cmt.ty) {
|
let method_call = typeck::MethodCall::expr(elt.id());
|
||||||
Some(ref mt) => mt.ty,
|
let method_ty = self.typer.node_method_ty(method_call);
|
||||||
None => {
|
|
||||||
self.tcx().sess.span_bug(
|
let element_ty = match method_ty {
|
||||||
elt.span(),
|
Some(method_ty) => {
|
||||||
format!("Explicit index of non-index type `{}`",
|
let ref_ty = ty::ty_fn_ret(method_ty);
|
||||||
base_cmt.ty.repr(self.tcx())).as_slice());
|
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
|
||||||
}
|
*ty::ty_fn_args(method_ty).get(0)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
match ty::array_element_ty(base_cmt.ty) {
|
||||||
|
Some(ref mt) => mt.ty,
|
||||||
|
None => {
|
||||||
|
self.tcx().sess.span_bug(
|
||||||
|
elt.span(),
|
||||||
|
format!("Explicit index of non-index type `{}`",
|
||||||
|
base_cmt.ty.repr(self.tcx())).as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return match deref_kind(self.tcx(), base_cmt.ty) {
|
return match deref_kind(self.tcx(), base_cmt.ty) {
|
||||||
|
@ -396,7 +396,7 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
|
|||||||
trans_rec_field(bcx, &**base, ident.node)
|
trans_rec_field(bcx, &**base, ident.node)
|
||||||
}
|
}
|
||||||
ast::ExprIndex(ref base, ref idx) => {
|
ast::ExprIndex(ref base, ref idx) => {
|
||||||
trans_index(bcx, expr, &**base, &**idx)
|
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
|
||||||
}
|
}
|
||||||
ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
|
ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
|
||||||
fcx.push_ast_cleanup_scope(contents.id);
|
fcx.push_ast_cleanup_scope(contents.id);
|
||||||
@ -467,7 +467,8 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>,
|
|||||||
fn trans_index<'a>(bcx: &'a Block<'a>,
|
fn trans_index<'a>(bcx: &'a Block<'a>,
|
||||||
index_expr: &ast::Expr,
|
index_expr: &ast::Expr,
|
||||||
base: &ast::Expr,
|
base: &ast::Expr,
|
||||||
idx: &ast::Expr)
|
idx: &ast::Expr,
|
||||||
|
method_call: MethodCall)
|
||||||
-> DatumBlock<'a, Expr> {
|
-> DatumBlock<'a, Expr> {
|
||||||
//! Translates `base[idx]`.
|
//! Translates `base[idx]`.
|
||||||
|
|
||||||
@ -475,43 +476,97 @@ fn trans_index<'a>(bcx: &'a Block<'a>,
|
|||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
|
|
||||||
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "index"));
|
// Check for overloaded index.
|
||||||
|
let method_ty = ccx.tcx
|
||||||
|
.method_map
|
||||||
|
.borrow()
|
||||||
|
.find(&method_call)
|
||||||
|
.map(|method| method.ty);
|
||||||
|
let elt_datum = match method_ty {
|
||||||
|
Some(method_ty) => {
|
||||||
|
let base_datum = unpack_datum!(bcx, trans(bcx, base));
|
||||||
|
|
||||||
// Translate index expression and cast to a suitable LLVM integer.
|
// Translate index expression.
|
||||||
// Rust is less strict than LLVM in this regard.
|
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
|
||||||
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
|
|
||||||
let ix_val = ix_datum.to_llscalarish(bcx);
|
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
||||||
let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
|
// invoke the user's index() method, which basically yields
|
||||||
let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
|
// a `&T` pointer. We can then proceed down the normal
|
||||||
let ix_val = {
|
// path (below) to dereference that `&T`.
|
||||||
if ix_size < int_size {
|
let val =
|
||||||
if ty::type_is_signed(expr_ty(bcx, idx)) {
|
unpack_result!(bcx,
|
||||||
SExt(bcx, ix_val, ccx.int_type)
|
trans_overloaded_op(bcx,
|
||||||
} else { ZExt(bcx, ix_val, ccx.int_type) }
|
index_expr,
|
||||||
} else if ix_size > int_size {
|
method_call,
|
||||||
Trunc(bcx, ix_val, ccx.int_type)
|
base_datum,
|
||||||
} else {
|
Some((ix_datum, idx.id)),
|
||||||
ix_val
|
None));
|
||||||
|
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
|
||||||
|
let elt_ty = match ty::deref(ref_ty, true) {
|
||||||
|
None => {
|
||||||
|
bcx.tcx().sess.span_bug(index_expr.span,
|
||||||
|
"index method didn't return a \
|
||||||
|
dereferenceable type?!")
|
||||||
|
}
|
||||||
|
Some(elt_tm) => elt_tm.ty,
|
||||||
|
};
|
||||||
|
Datum::new(val, elt_ty, LvalueExpr)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx,
|
||||||
|
base,
|
||||||
|
"index"));
|
||||||
|
|
||||||
|
// Translate index expression and cast to a suitable LLVM integer.
|
||||||
|
// Rust is less strict than LLVM in this regard.
|
||||||
|
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
|
||||||
|
let ix_val = ix_datum.to_llscalarish(bcx);
|
||||||
|
let ix_size = machine::llbitsize_of_real(bcx.ccx(),
|
||||||
|
val_ty(ix_val));
|
||||||
|
let int_size = machine::llbitsize_of_real(bcx.ccx(),
|
||||||
|
ccx.int_type);
|
||||||
|
let ix_val = {
|
||||||
|
if ix_size < int_size {
|
||||||
|
if ty::type_is_signed(expr_ty(bcx, idx)) {
|
||||||
|
SExt(bcx, ix_val, ccx.int_type)
|
||||||
|
} else { ZExt(bcx, ix_val, ccx.int_type) }
|
||||||
|
} else if ix_size > int_size {
|
||||||
|
Trunc(bcx, ix_val, ccx.int_type)
|
||||||
|
} else {
|
||||||
|
ix_val
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let vt =
|
||||||
|
tvec::vec_types(bcx,
|
||||||
|
ty::sequence_element_type(bcx.tcx(),
|
||||||
|
base_datum.ty));
|
||||||
|
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
|
||||||
|
|
||||||
|
let (base, len) = base_datum.get_vec_base_and_len(bcx);
|
||||||
|
|
||||||
|
debug!("trans_index: base {}", bcx.val_to_str(base));
|
||||||
|
debug!("trans_index: len {}", bcx.val_to_str(len));
|
||||||
|
|
||||||
|
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
|
||||||
|
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
|
||||||
|
let expected = Call(bcx,
|
||||||
|
expect,
|
||||||
|
[bounds_check, C_bool(ccx, false)],
|
||||||
|
[]);
|
||||||
|
bcx = with_cond(bcx, expected, |bcx| {
|
||||||
|
controlflow::trans_fail_bounds_check(bcx,
|
||||||
|
index_expr.span,
|
||||||
|
ix_val,
|
||||||
|
len)
|
||||||
|
});
|
||||||
|
let elt = InBoundsGEP(bcx, base, [ix_val]);
|
||||||
|
let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
|
||||||
|
Datum::new(elt, vt.unit_ty, LvalueExpr)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), base_datum.ty));
|
DatumBlock::new(bcx, elt_datum)
|
||||||
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
|
|
||||||
|
|
||||||
let (base, len) = base_datum.get_vec_base_and_len(bcx);
|
|
||||||
|
|
||||||
debug!("trans_index: base {}", bcx.val_to_str(base));
|
|
||||||
debug!("trans_index: len {}", bcx.val_to_str(len));
|
|
||||||
|
|
||||||
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
|
|
||||||
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
|
|
||||||
let expected = Call(bcx, expect, [bounds_check, C_bool(ccx, false)], []);
|
|
||||||
let bcx = with_cond(bcx, expected, |bcx| {
|
|
||||||
controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
|
|
||||||
});
|
|
||||||
let elt = InBoundsGEP(bcx, base, [ix_val]);
|
|
||||||
let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
|
|
||||||
DatumBlock::new(bcx, Datum::new(elt, vt.unit_ty, LvalueExpr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_def<'a>(bcx: &'a Block<'a>,
|
fn trans_def<'a>(bcx: &'a Block<'a>,
|
||||||
@ -1756,7 +1811,7 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
|
|||||||
Some(method_ty) => {
|
Some(method_ty) => {
|
||||||
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
||||||
// invoke the user's deref() method, which basically
|
// invoke the user's deref() method, which basically
|
||||||
// converts from the `Shaht<T>` pointer that we have into
|
// converts from the `Smaht<T>` pointer that we have into
|
||||||
// a `&T` pointer. We can then proceed down the normal
|
// a `&T` pointer. We can then proceed down the normal
|
||||||
// path (below) to dereference that `&T`.
|
// path (below) to dereference that `&T`.
|
||||||
let datum = match method_call.adjustment {
|
let datum = match method_call.adjustment {
|
||||||
|
@ -3030,6 +3030,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
|||||||
// the deref method invoked for `*a` always yields an `&T`
|
// the deref method invoked for `*a` always yields an `&T`
|
||||||
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
||||||
|
|
||||||
|
// the index method invoked for `a[i]` always yields an `&T`
|
||||||
|
ast::ExprIndex(..) => LvalueExpr,
|
||||||
|
|
||||||
// in the general case, result could be any type, use DPS
|
// in the general case, result could be any type, use DPS
|
||||||
_ => RvalueDpsExpr
|
_ => RvalueDpsExpr
|
||||||
};
|
};
|
||||||
|
@ -1629,6 +1629,76 @@ fn try_overloaded_deref(fcx: &FnCtxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_overloaded_index(fcx: &FnCtxt,
|
||||||
|
method_call: Option<MethodCall>,
|
||||||
|
expr: &ast::Expr,
|
||||||
|
base_expr: Gc<ast::Expr>,
|
||||||
|
base_ty: ty::t,
|
||||||
|
index_expr: Gc<ast::Expr>,
|
||||||
|
lvalue_pref: LvaluePreference)
|
||||||
|
-> Option<ty::mt> {
|
||||||
|
// Try `IndexMut` first, if preferred.
|
||||||
|
let method = match (lvalue_pref, fcx.tcx().lang_items.index_mut_trait()) {
|
||||||
|
(PreferMutLvalue, Some(trait_did)) => {
|
||||||
|
method::lookup_in_trait(fcx,
|
||||||
|
expr.span,
|
||||||
|
Some(&*base_expr),
|
||||||
|
token::intern("index_mut"),
|
||||||
|
trait_did,
|
||||||
|
base_ty,
|
||||||
|
[],
|
||||||
|
DontAutoderefReceiver,
|
||||||
|
IgnoreStaticMethods)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Otherwise, fall back to `Index`.
|
||||||
|
let method = match (method, fcx.tcx().lang_items.index_trait()) {
|
||||||
|
(None, Some(trait_did)) => {
|
||||||
|
method::lookup_in_trait(fcx,
|
||||||
|
expr.span,
|
||||||
|
Some(&*base_expr),
|
||||||
|
token::intern("index"),
|
||||||
|
trait_did,
|
||||||
|
base_ty,
|
||||||
|
[],
|
||||||
|
DontAutoderefReceiver,
|
||||||
|
IgnoreStaticMethods)
|
||||||
|
}
|
||||||
|
(method, _) => method,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Regardless of whether the lookup succeeds, check the method arguments
|
||||||
|
// so that we have *some* type for each argument.
|
||||||
|
let method_type = match method {
|
||||||
|
Some(ref method) => method.ty,
|
||||||
|
None => ty::mk_err()
|
||||||
|
};
|
||||||
|
check_method_argument_types(fcx,
|
||||||
|
expr.span,
|
||||||
|
method_type,
|
||||||
|
expr,
|
||||||
|
[base_expr, index_expr],
|
||||||
|
DoDerefArgs,
|
||||||
|
DontTupleArguments);
|
||||||
|
|
||||||
|
match method {
|
||||||
|
Some(method) => {
|
||||||
|
let ref_ty = ty::ty_fn_ret(method.ty);
|
||||||
|
match method_call {
|
||||||
|
Some(method_call) => {
|
||||||
|
fcx.inh.method_map.borrow_mut().insert(method_call,
|
||||||
|
method);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
ty::deref(ref_ty, true)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_method_argument_types(fcx: &FnCtxt,
|
fn check_method_argument_types(fcx: &FnCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
method_fn_ty: ty::t,
|
method_fn_ty: ty::t,
|
||||||
@ -3340,7 +3410,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
|||||||
} else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
|
} else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
|
||||||
fcx.write_ty(id, idx_t);
|
fcx.write_ty(id, idx_t);
|
||||||
} else {
|
} else {
|
||||||
let (base_t, autoderefs, field_ty) =
|
let (_, autoderefs, field_ty) =
|
||||||
autoderef(fcx, expr.span, raw_base_t, Some(base.id),
|
autoderef(fcx, expr.span, raw_base_t, Some(base.id),
|
||||||
lvalue_pref, |base_t, _| ty::index(base_t));
|
lvalue_pref, |base_t, _| ty::index(base_t));
|
||||||
match field_ty {
|
match field_ty {
|
||||||
@ -3350,27 +3420,33 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
|||||||
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let resolved = structurally_resolved_type(fcx,
|
// This is an overloaded method.
|
||||||
expr.span,
|
let base_t = structurally_resolved_type(fcx,
|
||||||
raw_base_t);
|
expr.span,
|
||||||
let ret_ty = lookup_op_method(fcx,
|
raw_base_t);
|
||||||
expr,
|
let method_call = MethodCall::expr(expr.id);
|
||||||
resolved,
|
match try_overloaded_index(fcx,
|
||||||
token::intern("index"),
|
Some(method_call),
|
||||||
tcx.lang_items.index_trait(),
|
expr,
|
||||||
[base.clone(), idx.clone()],
|
*base,
|
||||||
AutoderefReceiver,
|
base_t,
|
||||||
|| {
|
*idx,
|
||||||
fcx.type_error_message(expr.span,
|
lvalue_pref) {
|
||||||
|actual| {
|
Some(mt) => fcx.write_ty(id, mt.ty),
|
||||||
format!("cannot index a \
|
None => {
|
||||||
value of type \
|
fcx.type_error_message(expr.span,
|
||||||
`{}`", actual)
|
|actual| {
|
||||||
},
|
format!("cannot \
|
||||||
base_t,
|
index a \
|
||||||
None);
|
value of \
|
||||||
});
|
type `{}`",
|
||||||
fcx.write_ty(id, ret_ty);
|
actual)
|
||||||
|
},
|
||||||
|
base_t,
|
||||||
|
None);
|
||||||
|
fcx.write_ty(id, ty::mk_err())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@
|
|||||||
#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
|
||||||
#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor};
|
#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor};
|
||||||
#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut};
|
#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut};
|
||||||
#[doc(no_inline)] pub use ops::{Shl, Shr, Index};
|
#[doc(no_inline)] pub use ops::{Shl, Shr};
|
||||||
|
#[doc(no_inline)] #[cfg(not(stage0))] pub use ops::{Index, IndexMut};
|
||||||
#[doc(no_inline)] pub use option::{Option, Some, None};
|
#[doc(no_inline)] pub use option::{Option, Some, None};
|
||||||
#[doc(no_inline)] pub use result::{Result, Ok, Err};
|
#[doc(no_inline)] pub use result::{Result, Ok, Err};
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// 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 <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.
|
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
|
||||||
|
|
||||||
pub enum maybe<T> { just(T), nothing }
|
|
||||||
|
|
||||||
impl <T:Clone> Index<uint,T> for maybe<T> {
|
|
||||||
fn index(&self, _idx: &uint) -> T {
|
|
||||||
match self {
|
|
||||||
&just(ref t) => (*t).clone(),
|
|
||||||
¬hing => { fail!(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
// 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 <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.
|
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
|
||||||
|
|
||||||
extern crate issue2378a;
|
|
||||||
|
|
||||||
use issue2378a::maybe;
|
|
||||||
|
|
||||||
pub struct two_maybes<T> {pub a: maybe<T>, pub b: maybe<T>}
|
|
||||||
|
|
||||||
impl<T:Clone> Index<uint,(T,T)> for two_maybes<T> {
|
|
||||||
fn index(&self, idx: &uint) -> (T, T) {
|
|
||||||
(self.a[*idx], self.b[*idx])
|
|
||||||
}
|
|
||||||
}
|
|
64
src/test/compile-fail/borrowck-overloaded-index.rs
Normal file
64
src/test/compile-fail/borrowck-overloaded-index.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<String,int> for Foo {
|
||||||
|
fn index<'a>(&'a self, z: &String) -> &'a int {
|
||||||
|
if z.as_slice() == "x" {
|
||||||
|
&self.x
|
||||||
|
} else {
|
||||||
|
&self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<String,int> for Foo {
|
||||||
|
fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut int {
|
||||||
|
if z.as_slice() == "x" {
|
||||||
|
&mut self.x
|
||||||
|
} else {
|
||||||
|
&mut self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
x: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<int,int> for Bar {
|
||||||
|
fn index<'a>(&'a self, z: &int) -> &'a int {
|
||||||
|
&self.x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut f = Foo {
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
};
|
||||||
|
let mut s = "hello".to_string();
|
||||||
|
let rs = &mut s;
|
||||||
|
println!("{}", f[s]);
|
||||||
|
//~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
|
||||||
|
f[s] = 10;
|
||||||
|
//~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
|
||||||
|
let s = Bar {
|
||||||
|
x: 1,
|
||||||
|
};
|
||||||
|
s[2] = 20;
|
||||||
|
//~^ ERROR cannot assign to immutable indexed content
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -16,13 +16,13 @@ use std::collections::Bitv;
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Generate sieve of Eratosthenes for n up to 1e6
|
// Generate sieve of Eratosthenes for n up to 1e6
|
||||||
let n = 1000000u;
|
let n = 1000000u;
|
||||||
let sieve = Bitv::with_capacity(n+1, true);
|
let mut sieve = Bitv::with_capacity(n+1, true);
|
||||||
let limit: uint = (n as f32).sqrt() as uint;
|
let limit: uint = (n as f32).sqrt() as uint;
|
||||||
for i in range(2, limit+1) {
|
for i in range(2, limit+1) {
|
||||||
if sieve[i] {
|
if sieve[i] {
|
||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
while i*i + j*i <= n {
|
while i*i + j*i <= n {
|
||||||
sieve[i*i+j*i] = false;
|
sieve.set(i*i+j*i, false);
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// Copyright 2012-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 <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:issue2378a.rs
|
|
||||||
// aux-build:issue2378b.rs
|
|
||||||
|
|
||||||
extern crate issue2378a;
|
|
||||||
extern crate issue2378b;
|
|
||||||
|
|
||||||
use issue2378a::{just};
|
|
||||||
use issue2378b::{two_maybes};
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let x = two_maybes{a: just(3i), b: just(5i)};
|
|
||||||
assert_eq!(x[0u], (3, 5));
|
|
||||||
}
|
|
@ -43,8 +43,12 @@ impl ops::Not<Point> for Point {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<bool,int> for Point {
|
impl ops::Index<bool,int> for Point {
|
||||||
fn index(&self, x: &bool) -> int {
|
fn index<'a>(&'a self, x: &bool) -> &'a int {
|
||||||
if *x { self.x } else { self.y }
|
if *x {
|
||||||
|
&self.x
|
||||||
|
} else {
|
||||||
|
&self.y
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ impl<K,V> AssociationList<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K:PartialEq,V:Clone> Index<K,V> for AssociationList<K,V> {
|
impl<K:PartialEq,V:Clone> Index<K,V> for AssociationList<K,V> {
|
||||||
fn index(&self, index: &K) -> V {
|
fn index<'a>(&'a self, index: &K) -> &'a V {
|
||||||
for pair in self.pairs.iter() {
|
for pair in self.pairs.iter() {
|
||||||
if pair.key == *index {
|
if pair.key == *index {
|
||||||
return pair.value.clone();
|
return &pair.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fail!("No value found for key: {:?}", index);
|
fail!("No value found for key: {:?}", index);
|
||||||
|
53
src/test/run-pass/overloaded-index.rs
Normal file
53
src/test/run-pass/overloaded-index.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<int,int> for Foo {
|
||||||
|
fn index<'a>(&'a self, z: &int) -> &'a int {
|
||||||
|
if *z == 0 {
|
||||||
|
&self.x
|
||||||
|
} else {
|
||||||
|
&self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<int,int> for Foo {
|
||||||
|
fn index_mut<'a>(&'a mut self, z: &int) -> &'a mut int {
|
||||||
|
if *z == 0 {
|
||||||
|
&mut self.x
|
||||||
|
} else {
|
||||||
|
&mut self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut f = Foo {
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
};
|
||||||
|
assert_eq!(f[1], 2);
|
||||||
|
f[0] = 3;
|
||||||
|
assert_eq!(f[0], 3);
|
||||||
|
{
|
||||||
|
let p = &mut f[1];
|
||||||
|
*p = 4;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let p = &f[1];
|
||||||
|
assert_eq!(*p, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user