correct incorrect handling of overloaded operators, exposing various other bits of rot

This commit is contained in:
Niko Matsakis 2013-05-01 08:49:48 -04:00
parent f236b850c0
commit 5ab33a2975
9 changed files with 117 additions and 129 deletions

View file

@ -296,34 +296,34 @@ impl<T> Ord for *const T {
// Equality for region pointers
#[cfg(notest)]
impl<'self,T:Eq> Eq for &'self const T {
impl<'self,T:Eq> Eq for &'self T {
#[inline(always)]
fn eq(&self, other: & &'self const T) -> bool {
fn eq(&self, other: & &'self T) -> bool {
return *(*self) == *(*other);
}
#[inline(always)]
fn ne(&self, other: & &'self const T) -> bool {
fn ne(&self, other: & &'self T) -> bool {
return *(*self) != *(*other);
}
}
// Comparison for region pointers
#[cfg(notest)]
impl<'self,T:Ord> Ord for &'self const T {
impl<'self,T:Ord> Ord for &'self T {
#[inline(always)]
fn lt(&self, other: & &'self const T) -> bool {
fn lt(&self, other: & &'self T) -> bool {
*(*self) < *(*other)
}
#[inline(always)]
fn le(&self, other: & &'self const T) -> bool {
fn le(&self, other: & &'self T) -> bool {
*(*self) <= *(*other)
}
#[inline(always)]
fn ge(&self, other: & &'self const T) -> bool {
fn ge(&self, other: & &'self T) -> bool {
*(*self) >= *(*other)
}
#[inline(always)]
fn gt(&self, other: & &'self const T) -> bool {
fn gt(&self, other: & &'self T) -> bool {
*(*self) > *(*other)
}
}

View file

@ -68,8 +68,7 @@ struct GatherLoanCtxt {
id_range: id_range,
all_loans: @mut ~[Loan],
item_ub: ast::node_id,
repeating_ids: ~[ast::node_id],
ignore_adjustments: HashSet<ast::node_id>
repeating_ids: ~[ast::node_id]
}
pub fn gather_loans(bccx: @BorrowckCtxt,
@ -79,8 +78,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt,
id_range: id_range::max(),
all_loans: @mut ~[],
item_ub: body.node.id,
repeating_ids: ~[body.node.id],
ignore_adjustments: HashSet::new()
repeating_ids: ~[body.node.id]
};
let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr,
visit_block: gather_loans_in_block,
@ -147,13 +145,8 @@ fn gather_loans_in_expr(ex: @ast::expr,
self.id_range.add(ex.callee_id);
// If this expression is borrowed, have to ensure it remains valid:
{
let this = &mut *self; // FIXME(#5074)
if !this.ignore_adjustments.contains(&ex.id) {
for tcx.adjustments.find(&ex.id).each |&adjustments| {
this.guarantee_adjustments(ex, *adjustments);
}
}
self.guarantee_adjustments(ex, *adjustments);
}
// Special checks for various kinds of expressions:
@ -178,46 +171,20 @@ fn gather_loans_in_expr(ex: @ast::expr,
visit::visit_expr(ex, self, vt);
}
ast::expr_index(rcvr, _) |
ast::expr_binary(_, rcvr, _) |
ast::expr_unary(_, rcvr) |
ast::expr_assign_op(_, rcvr, _)
ast::expr_index(_, arg) |
ast::expr_binary(_, _, arg)
if self.bccx.method_map.contains_key(&ex.id) => {
// Receivers in method calls are always passed by ref.
// Arguments in method calls are always passed by ref.
//
// Here, in an overloaded operator, the call is this expression,
// and hence the scope of the borrow is this call.
//
// FIX? / NOT REALLY---technically we should check the other
// argument and consider the argument mode. But how annoying.
// And this problem when goes away when argument modes are
// phased out. So I elect to leave this undone.
// Currently these do not use adjustments, so we have to
// hardcode this check here (note that the receiver DOES use
// adjustments).
let scope_r = ty::re_scope(ex.id);
let rcvr_cmt = self.bccx.cat_expr(rcvr);
self.guarantee_valid(rcvr.id, rcvr.span, rcvr_cmt, m_imm, scope_r);
// FIXME (#3387): Total hack: Ignore adjustments for the left-hand
// side. Their regions will be inferred to be too large.
self.ignore_adjustments.insert(rcvr.id);
let arg_cmt = self.bccx.cat_expr(arg);
self.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
visit::visit_expr(ex, self, vt);
}
// FIXME--#3387
// ast::expr_binary(_, lhs, rhs) => {
// // Universal comparison operators like ==, >=, etc
// // take their arguments by reference.
// let lhs_ty = ty::expr_ty(self.tcx(), lhs);
// if !ty::type_is_scalar(lhs_ty) {
// let scope_r = ty::re_scope(ex.id);
// let lhs_cmt = self.bccx.cat_expr(lhs);
// self.guarantee_valid(lhs_cmt, m_imm, scope_r);
// let rhs_cmt = self.bccx.cat_expr(rhs);
// self.guarantee_valid(rhs_cmt, m_imm, scope_r);
// }
// visit::visit_expr(ex, self, vt);
// }
// see explanation attached to the `root_ub` field:
ast::expr_while(cond, ref body) => {
// during the condition, can only root for the condition

View file

@ -236,9 +236,16 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) {
// overloaded. See #3511.
let tcx = rcx.fcx.tcx();
match expr.node {
// You'd think that x += y where `+=` is overloaded would be a
// cleanup scope. You'd be... kind of right. In fact the
// handling of `+=` and friends in trans for overloaded
// operators is a hopeless mess and I can't figure out how to
// represent it. - ndm
//
// ast::expr_assign_op(*) |
ast::expr_index(*) |
ast::expr_binary(*) |
ast::expr_assign_op(*) |
ast::expr_unary(*) if has_method_map => {
tcx.region_maps.record_cleanup_scope(expr.id);
}

View file

@ -598,8 +598,8 @@ mod tests {
let arc = ~RWARC(1);
let arc2 = (*arc).clone();
do task::try || {
do arc2.write_downgrade |write_mode| {
do (&write_mode).write |one| {
do arc2.write_downgrade |mut write_mode| {
do write_mode.write |one| {
assert!(*one == 2);
}
}
@ -733,8 +733,8 @@ mod tests {
}
// Downgrader (us)
do arc.write_downgrade |write_mode| {
do (&write_mode).write_cond |state, cond| {
do arc.write_downgrade |mut write_mode| {
do write_mode.write_cond |state, cond| {
wc1.send(()); // send to another writer who will wake us up
while *state == 0 {
cond.wait();

View file

@ -1256,13 +1256,15 @@ mod tests {
match (r) {
node::Empty => return ~"",
node::Content(x) => {
let str = @mut ~"";
fn aux(str: @mut ~str, node: @node::Node) {
let mut str = ~"";
fn aux(str: &mut ~str, node: @node::Node) {
match (*node) {
node::Leaf(x) => {
*str += str::slice(
str::push_str(
str,
str::slice(
*x.content, x.byte_offset,
x.byte_offset + x.byte_len).to_owned();
x.byte_offset + x.byte_len));
}
node::Concat(ref x) => {
aux(str, x.left);
@ -1270,8 +1272,8 @@ mod tests {
}
}
}
aux(str, x);
return *str
aux(&mut str, x);
return str
}
}
}

View file

@ -22,12 +22,12 @@ type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool;
* Has worst case O(n log n) performance, best case O(n), but
* is not space efficient. This is a stable sort.
*/
pub fn merge_sort<T:Copy>(v: &const [T], le: Le<T>) -> ~[T] {
pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] {
type Slice = (uint, uint);
return merge_sort_(v, (0u, len(v)), le);
fn merge_sort_<T:Copy>(v: &const [T], slice: Slice, le: Le<T>)
fn merge_sort_<T:Copy>(v: &[T], slice: Slice, le: Le<T>)
-> ~[T] {
let begin = slice.first();
let end = slice.second();
@ -179,7 +179,7 @@ fn qsort3<T:Copy + Ord + Eq>(arr: &mut [T], left: int, right: int) {
*/
pub fn quick_sort3<T:Copy + Ord + Eq>(arr: &mut [T]) {
if arr.len() <= 1 { return; }
let len = arr.len() - 1; // FIXME(#5074) nested calls
let len = arr.len(); // FIXME(#5074) nested calls
qsort3(arr, 0, (len - 1) as int);
}
@ -263,7 +263,7 @@ fn binarysort<T:Copy + Ord>(array: &mut [T], start: uint) {
assert!(left == right);
let n = start-left;
copy_vec(array, left+1, array, left, n);
shift_vec(array, left+1, left, n);
array[left] = pivot;
start += 1;
}
@ -309,8 +309,8 @@ fn count_run_ascending<T:Copy + Ord>(array: &mut [T]) -> uint {
return run;
}
fn gallop_left<T:Copy + Ord>(key: &const T,
array: &const [T],
fn gallop_left<T:Copy + Ord>(key: &T,
array: &[T],
hint: uint)
-> uint {
let size = array.len();
@ -360,8 +360,8 @@ fn gallop_left<T:Copy + Ord>(key: &const T,
return ofs;
}
fn gallop_right<T:Copy + Ord>(key: &const T,
array: &const [T],
fn gallop_right<T:Copy + Ord>(key: &T,
array: &[T],
hint: uint)
-> uint {
let size = array.len();
@ -457,15 +457,15 @@ impl<T:Copy + Ord> MergeState<T> {
}
let k = { // constrain lifetime of slice below
let slice = vec::mut_slice(array, b1, b1+l1);
gallop_right(&const array[b2], slice, 0)
let slice = vec::slice(array, b1, b1+l1);
gallop_right(&array[b2], slice, 0)
};
b1 += k;
l1 -= k;
if l1 != 0 {
let l2 = { // constrain lifetime of slice below
let slice = vec::mut_slice(array, b2, b2+l2);
gallop_left(&const array[b1+l1-1],slice,l2-1)
let slice = vec::slice(array, b2, b2+l2);
gallop_left(&array[b1+l1-1],slice,l2-1)
};
if l2 > 0 {
if l1 <= l2 {
@ -497,11 +497,11 @@ impl<T:Copy + Ord> MergeState<T> {
dest += 1; c2 += 1; len2 -= 1;
if len2 == 0 {
copy_vec(array, dest, tmp, 0, len1);
copy_vec(array, dest, tmp.slice(0, len1));
return;
}
if len1 == 1 {
copy_vec(array, dest, array, c2, len2);
shift_vec(array, dest, c2, len2);
array[dest+len2] <-> tmp[c1];
return;
}
@ -539,10 +539,12 @@ impl<T:Copy + Ord> MergeState<T> {
loop {
assert!(len1 > 1 && len2 != 0);
let tmp_view = vec::const_slice(tmp, c1, c1+len1);
count1 = gallop_right(&const array[c2], tmp_view, 0);
count1 = {
let tmp_view = vec::slice(tmp, c1, c1+len1);
gallop_right(&array[c2], tmp_view, 0)
};
if count1 != 0 {
copy_vec(array, dest, tmp, c1, count1);
copy_vec(array, dest, tmp.slice(c1, c1+count1));
dest += count1; c1 += count1; len1 -= count1;
if len1 <= 1 { break_outer = true; break; }
}
@ -550,10 +552,12 @@ impl<T:Copy + Ord> MergeState<T> {
dest += 1; c2 += 1; len2 -= 1;
if len2 == 0 { break_outer = true; break; }
let tmp_view = vec::const_slice(array, c2, c2+len2);
count2 = gallop_left(&const tmp[c1], tmp_view, 0);
count2 = {
let tmp_view = vec::slice(array, c2, c2+len2);
gallop_left(&tmp[c1], tmp_view, 0)
};
if count2 != 0 {
copy_vec(array, dest, array, c2, count2);
shift_vec(array, dest, c2, count2);
dest += count2; c2 += count2; len2 -= count2;
if len2 == 0 { break_outer = true; break; }
}
@ -573,14 +577,14 @@ impl<T:Copy + Ord> MergeState<T> {
if len1 == 1 {
assert!(len2 > 0);
copy_vec(array, dest, array, c2, len2);
shift_vec(array, dest, c2, len2);
array[dest+len2] <-> tmp[c1];
} else if len1 == 0 {
fail!(~"Comparison violates its contract!");
} else {
assert!(len2 == 0);
assert!(len1 > 1);
copy_vec(array, dest, tmp, c1, len1);
copy_vec(array, dest, tmp.slice(c1, c1+len1));
}
}
@ -603,13 +607,13 @@ impl<T:Copy + Ord> MergeState<T> {
dest -= 1; c1 -= 1; len1 -= 1;
if len1 == 0 {
copy_vec(array, dest-(len2-1), tmp, 0, len2);
copy_vec(array, dest-(len2-1), tmp.slice(0, len2));
return;
}
if len2 == 1 {
dest -= len1;
c1 -= len1;
copy_vec(array, dest+1, array, c1+1, len1);
shift_vec(array, dest+1, c1+1, len1);
array[dest] <-> tmp[c2];
return;
}
@ -650,12 +654,12 @@ impl<T:Copy + Ord> MergeState<T> {
{ // constrain scope of tmp_view:
let tmp_view = vec::mut_slice (array, base1, base1+len1);
count1 = len1 - gallop_right(
&const tmp[c2], tmp_view, len1-1);
&tmp[c2], tmp_view, len1-1);
}
if count1 != 0 {
dest -= count1; c1 -= count1; len1 -= count1;
copy_vec(array, dest+1, array, c1+1, count1);
shift_vec(array, dest+1, c1+1, count1);
if len1 == 0 { break_outer = true; break; }
}
@ -666,14 +670,14 @@ impl<T:Copy + Ord> MergeState<T> {
let count2;
{ // constrain scope of tmp_view
let tmp_view = vec::mut_slice(tmp, 0, len2);
count2 = len2 - gallop_left(&const array[c1],
count2 = len2 - gallop_left(&array[c1],
tmp_view,
len2-1);
}
if count2 != 0 {
dest -= count2; c2 -= count2; len2 -= count2;
copy_vec(array, dest+1, tmp, c2+1, count2);
copy_vec(array, dest+1, tmp.slice(c2+1, c2+1+count2));
if len2 <= 1 { break_outer = true; break; }
}
array[dest] <-> array[c1];
@ -695,14 +699,14 @@ impl<T:Copy + Ord> MergeState<T> {
assert!(len1 > 0);
dest -= len1;
c1 -= len1;
copy_vec(array, dest+1, array, c1+1, len1);
shift_vec(array, dest+1, c1+1, len1);
array[dest] <-> tmp[c2];
} else if len2 == 0 {
fail!(~"Comparison violates its contract!");
} else {
assert!(len1 == 0);
assert!(len2 != 0);
copy_vec(array, dest-(len2-1), tmp, 0, len2);
copy_vec(array, dest-(len2-1), tmp.slice(0, len2));
}
}
@ -738,21 +742,25 @@ impl<T:Copy + Ord> MergeState<T> {
#[inline(always)]
fn copy_vec<T:Copy>(dest: &mut [T],
s1: uint,
from: &const [T],
s2: uint,
len: uint) {
assert!(s1+len <= dest.len() && s2+len <= from.len());
from: &[T]) {
assert!(s1+from.len() <= dest.len());
let mut slice = ~[];
for uint::range(s2, s2+len) |i| {
slice.push(from[i]);
}
for slice.eachi |i, v| {
for from.eachi |i, v| {
dest[s1+i] = *v;
}
}
#[inline(always)]
fn shift_vec<T:Copy>(dest: &mut [T],
s1: uint,
s2: uint,
len: uint) {
assert!(s1+len <= dest.len());
let tmp = dest.slice(s2, s2+len).to_vec();
copy_vec(dest, s1, tmp);
}
#[cfg(test)]
mod test_qsort3 {
use sort::*;
@ -764,8 +772,7 @@ mod test_qsort3 {
quick_sort3::<int>(v1);
let mut i = 0;
while i < len {
// debug!(v2[i]);
assert!((v2[i] == v1[i]));
assert_eq!(v2[i], v1[i]);
i += 1;
}
}
@ -1036,7 +1043,7 @@ mod big_tests {
tabulate_managed(low, high);
}
fn multiplyVec<T:Copy>(arr: &const [T], num: uint) -> ~[T] {
fn multiplyVec<T:Copy>(arr: &[T], num: uint) -> ~[T] {
let size = arr.len();
let res = do vec::from_fn(num) |i| {
arr[i % size]
@ -1052,7 +1059,7 @@ mod big_tests {
}
fn tabulate_unique(lo: uint, hi: uint) {
fn isSorted<T:Ord>(arr: &const [T]) {
fn isSorted<T:Ord>(arr: &[T]) {
for uint::range(0, arr.len()-1) |i| {
if arr[i] > arr[i+1] {
fail!(~"Array not sorted");
@ -1123,7 +1130,7 @@ mod big_tests {
}
fn tabulate_managed(lo: uint, hi: uint) {
fn isSorted<T:Ord>(arr: &const [@T]) {
fn isSorted<T:Ord>(arr: &[@T]) {
for uint::range(0, arr.len()-1) |i| {
if arr[i] > arr[i+1] {
fail!(~"Array not sorted");

View file

@ -69,7 +69,14 @@ pub mod list;
pub mod priority_queue;
pub mod rope;
pub mod smallintmap;
#[cfg(stage0)]
#[path="sort_stage0.rs"]
pub mod sort;
#[cfg(not(stage0))]
pub mod sort;
pub mod dlist;
pub mod treemap;

View file

@ -8,18 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-test #3387
struct foo(~uint);
impl Add<foo, foo> for foo {
fn add(f: &foo) -> foo {
foo(~(**self + **(*f)))
fn add(&self, f: &foo) -> foo {
foo(~(***self + **(*f)))
}
}
fn main() {
let x = foo(~3);
let _y = x + x;
//~^ ERROR moving out of immutable local variable prohibited due to outstanding loan
let _y = x + {x}; // the `{x}` forces a move to occur
//~^ ERROR cannot move out of `x`
}

View file

@ -17,13 +17,13 @@ trait MyIter {
}
impl<'self> MyIter for &'self [int] {
fn test_imm(&self) { assert!(self[0] == 1) }
fn test_const(&const self) { assert!(self[0] == 1) }
fn test_imm(&self) { assert_eq!(self[0], 1) }
fn test_const(&const self) { assert_eq!(self[0], 1) }
}
impl<'self> MyIter for &'self str {
fn test_imm(&self) { assert!(*self == "test") }
fn test_const(&const self) { assert!(*self == "test") }
fn test_imm(&self) { assert_eq!(*self, "test") }
fn test_const(&const self) { assert_eq!(self[0], 't') }
}
pub fn main() {