1
Fork 0

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

View file

@ -68,8 +68,7 @@ struct GatherLoanCtxt {
id_range: id_range, id_range: id_range,
all_loans: @mut ~[Loan], all_loans: @mut ~[Loan],
item_ub: ast::node_id, item_ub: ast::node_id,
repeating_ids: ~[ast::node_id], repeating_ids: ~[ast::node_id]
ignore_adjustments: HashSet<ast::node_id>
} }
pub fn gather_loans(bccx: @BorrowckCtxt, pub fn gather_loans(bccx: @BorrowckCtxt,
@ -79,8 +78,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt,
id_range: id_range::max(), id_range: id_range::max(),
all_loans: @mut ~[], all_loans: @mut ~[],
item_ub: body.node.id, item_ub: body.node.id,
repeating_ids: ~[body.node.id], repeating_ids: ~[body.node.id]
ignore_adjustments: HashSet::new()
}; };
let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr,
visit_block: gather_loans_in_block, 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); self.id_range.add(ex.callee_id);
// If this expression is borrowed, have to ensure it remains valid: // If this expression is borrowed, have to ensure it remains valid:
{ for tcx.adjustments.find(&ex.id).each |&adjustments| {
let this = &mut *self; // FIXME(#5074) self.guarantee_adjustments(ex, *adjustments);
if !this.ignore_adjustments.contains(&ex.id) {
for tcx.adjustments.find(&ex.id).each |&adjustments| {
this.guarantee_adjustments(ex, *adjustments);
}
}
} }
// Special checks for various kinds of expressions: // 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); visit::visit_expr(ex, self, vt);
} }
ast::expr_index(rcvr, _) | ast::expr_index(_, arg) |
ast::expr_binary(_, rcvr, _) | ast::expr_binary(_, _, arg)
ast::expr_unary(_, rcvr) |
ast::expr_assign_op(_, rcvr, _)
if self.bccx.method_map.contains_key(&ex.id) => { 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, // Currently these do not use adjustments, so we have to
// and hence the scope of the borrow is this call. // hardcode this check here (note that the receiver DOES use
// // adjustments).
// FIX? / NOT REALLY---technically we should check the other let scope_r = ty::re_scope(ex.id);
// argument and consider the argument mode. But how annoying. let arg_cmt = self.bccx.cat_expr(arg);
// And this problem when goes away when argument modes are self.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
// phased out. So I elect to leave this undone. visit::visit_expr(ex, self, vt);
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);
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: // see explanation attached to the `root_ub` field:
ast::expr_while(cond, ref body) => { ast::expr_while(cond, ref body) => {
// during the condition, can only root for the condition // 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. // overloaded. See #3511.
let tcx = rcx.fcx.tcx(); let tcx = rcx.fcx.tcx();
match expr.node { 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_index(*) |
ast::expr_binary(*) | ast::expr_binary(*) |
ast::expr_assign_op(*) |
ast::expr_unary(*) if has_method_map => { ast::expr_unary(*) if has_method_map => {
tcx.region_maps.record_cleanup_scope(expr.id); tcx.region_maps.record_cleanup_scope(expr.id);
} }

View file

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

View file

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

View file

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

View file

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

View file

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