From 3c19f1bca83be3f4abef378d0a4cd852c8615164 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 27 Jun 2013 14:20:42 +0200 Subject: [PATCH 1/8] Refactored int/uint range code in preparation for change to range_rev semantics. Also added unit tests of range code to test refactoring. The num-range-rev.rs test will need to be updated when the range_rev semantics change. --- src/libstd/num/int_macros.rs | 88 +++++++++++++++++---- src/libstd/num/uint_macros.rs | 93 +++++++++++++++++----- src/test/run-pass/num-range-rev.rs | 114 +++++++++++++++++++++++++++ src/test/run-pass/num-range.rs | 119 +++++++++++++++++++++++++++++ 4 files changed, 381 insertions(+), 33 deletions(-) create mode 100644 src/test/run-pass/num-range-rev.rs create mode 100644 src/test/run-pass/num-range.rs diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 75e0bbcb71b04..4fd30be80e66e 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -29,28 +29,38 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = (-1 as $T) << (bits - 1); pub static max_value: $T = min_value - 1 as $T; +enum Range { Closed, HalfOpen } + +#[inline] /// -/// Iterate over the range [`lo`..`hi`) +/// Iterate through a range with a given step value. /// -/// # Arguments +/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed; +/// otherwise `term` denotes the half-open interval `[stop-step,stop)`. +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// `x_j == start + step*j`, and `x_n` lies in the interval `term`. /// -/// * `lo` - lower bound, inclusive -/// * `hi` - higher bound, exclusive -/// -/// # Examples -/// ~~~ -/// let mut sum = 0; -/// for int::range(1, 5) |i| { -/// sum += i; -/// } -/// assert!(sum == 10); -/// ~~~ +/// If no such nonnegative integer `n` exists, then the iteration range +/// is empty. /// -#[inline] -pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool { +fn range_step_core(start: $T, stop: $T, step: $T, r: Range, it: &fn($T) -> bool) -> bool { let mut i = start; if step == 0 { fail!(~"range_step called with step == 0"); + } else if step == (1 as $T) { // elide bounds check to tighten loop + while i < stop { + if !it(i) { return false; } + // no need for overflow check; + // cannot have i + 1 > max_value because i < stop <= max_value + i += (1 as $T); + } + } else if step == (-1 as $T) { // elide bounds check to tighten loop + while i > stop { + if !it(i) { return false; } + // no need for underflow check; + // cannot have i - 1 < min_value because i > stop >= min_value + i -= (1 as $T); + } } else if step > 0 { // ascending while i < stop { if !it(i) { return false; } @@ -66,9 +76,55 @@ pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool { i += step; } } - return true; + match r { + HalfOpen => return true, + Closed => return (i != stop || it(i)) + } +} + +#[inline] +/// +/// Iterate through the range [`start`..`stop`) with a given step value. +/// +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// * `x_i == start + step*i`, and +/// * `n` is the greatest nonnegative integer such that `x_n < stop` +/// +/// (If no such `n` exists, then the iteration range is empty.) +/// +/// # Arguments +/// +/// * `start` - lower bound, inclusive +/// * `stop` - higher bound, exclusive +/// +/// # Examples +/// ~~~ +/// let mut sum = 0; +/// for int::range(1, 5) |i| { +/// sum += i; +/// } +/// assert!(sum == 10); +/// ~~~ +/// +pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool { + range_step_core(start, stop, step, HalfOpen, it) +} + +#[inline] +/// +/// Iterate through a range with a given step value. +/// +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// `x_i == start + step*i` and `x_n <= last < step + x_n`. +/// +/// (If no such nonnegative integer `n` exists, then the iteration +/// range is empty.) +/// +pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) -> bool { + range_step_core(start, last, step, Closed, it) } + #[inline] /// Iterate over the range [`lo`..`hi`) pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool { diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index de1b997b14b52..09397ecfd7768 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -30,32 +30,46 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = 0 as $T; pub static max_value: $T = 0 as $T - 1 as $T; +enum Range { Closed, HalfOpen } + #[inline] -/** - * Iterate through a range with a given step value. - * - * # Examples - * ~~~ {.rust} - * let nums = [1,2,3,4,5,6,7]; - * - * for uint::range_step(0, nums.len() - 1, 2) |i| { - * println(fmt!("%d & %d", nums[i], nums[i+1])); - * } - * ~~~ - */ -pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool { +/// +/// Iterate through a range with a given step value. +/// +/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed; +/// otherwise `term` denotes the half-open interval `[stop-step,stop)`. +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// `x_j == start + step*j`, and `x_n` lies in the interval `term`. +/// +/// If no such nonnegative integer `n` exists, then the iteration range +/// is empty. +/// +fn range_step_core(start: $T, stop: $T, step: $T_SIGNED, r: Range, it: &fn($T) -> bool) -> bool { let mut i = start; if step == 0 { fail!("range_step called with step == 0"); - } - if step >= 0 { + } else if step == (1 as $T_SIGNED) { // elide bounds check to tighten loop + while i < stop { + if !it(i) { return false; } + // no need for overflow check; + // cannot have i + 1 > max_value because i < stop <= max_value + i += (1 as $T); + } + } else if step == (-1 as $T_SIGNED) { // elide bounds check to tighten loop + while i > stop { + if !it(i) { return false; } + // no need for underflow check; + // cannot have i - 1 < min_value because i > stop >= min_value + i -= (1 as $T); + } + } else if step > 0 { // ascending while i < stop { if !it(i) { return false; } // avoiding overflow. break if i + step > max_value if i > max_value - (step as $T) { return true; } i += step as $T; } - } else { + } else { // descending while i > stop { if !it(i) { return false; } // avoiding underflow. break if i + step < min_value @@ -63,7 +77,52 @@ pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> i -= -step as $T; } } - return true; + match r { + HalfOpen => return true, + Closed => return (i != stop || it(i)) + } +} + +#[inline] +/// +/// Iterate through the range [`start`..`stop`) with a given step value. +/// +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// - `x_i == start + step*i`, and +/// - `n` is the greatest nonnegative integer such that `x_n < stop` +/// +/// (If no such `n` exists, then the iteration range is empty.) +/// +/// # Arguments +/// +/// * `start` - lower bound, inclusive +/// * `stop` - higher bound, exclusive +/// +/// # Examples +/// ~~~ {.rust} +/// let nums = [1,2,3,4,5,6,7]; +/// +/// for uint::range_step(0, nums.len() - 1, 2) |i| { +/// println(fmt!("%d & %d", nums[i], nums[i+1])); +/// } +/// ~~~ +/// +pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool { + range_step_core(start, stop, step, HalfOpen, it) +} + +#[inline] +/// +/// Iterate through a range with a given step value. +/// +/// Iterates through the range `[x_0, x_1, ..., x_n]` where +/// `x_i == start + step*i` and `x_n <= last < step + x_n`. +/// +/// (If no such nonnegative integer `n` exists, then the iteration +/// range is empty.) +/// +pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool { + range_step_core(start, last, step, Closed, it) } #[inline] diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs new file mode 100644 index 0000000000000..e65c793a7b452 --- /dev/null +++ b/src/test/run-pass/num-range-rev.rs @@ -0,0 +1,114 @@ +// Copyright 2013 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. + +use std::int; +use std::uint; + +fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { + uint::range(lo, hi, it) +} + +fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool { + int::range(lo, hi, it) +} + +fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool { + uint::range_rev(hi, lo, it) +} + +fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool { + int::range_rev(hi, lo, it) +} + +fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool { + int::range_step(a, b, step, it) +} + +fn uint_range_step(a: uint, b: uint, step: int, it: &fn(uint) -> bool) -> bool { + uint::range_step(a, b, step, it) +} + + +pub fn main() { + // int and uint have same result for + // Sum{100 > i >= 2} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99 + let mut sum = 0u; + for uint_range_rev(99, 1) |i| { + sum += i; + } + assert_eq!(sum, 4949); + + let mut sum = 0i; + for int_range_rev(99, 1) |i| { + sum += i; + } + assert_eq!(sum, 4949); + + + // elements are visited in correct order + let primes = [2,3,5,7,11]; + let mut prod = 1i; + for uint_range_rev(4, 0) |i| { + println(fmt!("uint 4 downto 0: %u", i)); + prod *= int::pow(primes[i], i); + } + assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3); + let mut prod = 1i; + for int_range_rev(4, 0) |i| { + println(fmt!("int 4 downto 0: %d", i)); + prod *= int::pow(primes[i], i as uint); + } + assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3); + + + // range and range_rev are symmetric. + let mut sum_up = 0u; + for uint_range(10, 30) |i| { + sum_up += i; + } + let mut sum_down = 0u; + for uint_range_rev(29, 9) |i| { + sum_down += i; + } + assert_eq!(sum_up, sum_down); + + let mut sum_up = 0; + for int_range(-20, 10) |i| { + sum_up += i; + } + let mut sum_down = 0; + for int_range_rev(9, -21) |i| { + sum_down += i; + } + assert_eq!(sum_up, sum_down); + + + // empty ranges + for int_range_rev(10, 10) |_| { + fail!("range should be empty when start == stop"); + } + + for uint_range_rev(0, 1) |_| { + // fail!("range should be empty when start-1 underflows"); + } + + // range iterations do not wrap/underflow + let mut uflo_loop_visited = ~[]; + for int_range_step(int::min_value+15, int::min_value, -4) |x| { + uflo_loop_visited.push(x - int::min_value); + } + assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]); + + let mut uflo_loop_visited = ~[]; + for uint_range_step(uint::min_value+15, uint::min_value, -4) |x| { + uflo_loop_visited.push(x - uint::min_value); + } + assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]); +} diff --git a/src/test/run-pass/num-range.rs b/src/test/run-pass/num-range.rs new file mode 100644 index 0000000000000..7c1f905a049b6 --- /dev/null +++ b/src/test/run-pass/num-range.rs @@ -0,0 +1,119 @@ +// Copyright 2013 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. + +use std::int; +use std::uint; + +fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { + uint::range(lo, hi, it) +} + +fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool { + int::range(lo, hi, it) +} + +fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool { + int::range_step(a, b, step, it) +} + +fn uint_range_step(a: uint, b: uint, s: int, it: &fn(uint) -> bool) -> bool { + uint::range_step(a, b, s, it) +} + +pub fn main() { + println(fmt!("num-range start")); + // int and uint have same result for + // Sum{2 <= i < 100} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99 + let mut sum = 0u; + for uint_range(2, 100) |i| { + sum += i; + } + assert_eq!(sum, 4949); + + let mut sum = 0i; + for int_range(2, 100) |i| { + sum += i; + } + assert_eq!(sum, 4949); + + + // elements are visited in correct order + let primes = [2,3,5,7]; + let mut prod = 1i; + for uint_range(0, 4) |i| { + prod *= int::pow(primes[i], i); + } + assert_eq!(prod, 1*3*5*5*7*7*7); + let mut prod = 1i; + for int_range(0, 4) |i| { + prod *= int::pow(primes[i], i as uint); + } + assert_eq!(prod, 1*3*5*5*7*7*7); + + + // empty ranges + for int_range(10, 10) |_| { + fail!("range should be empty when start == stop"); + } + + for uint_range(10, 10) |_| { + fail!("range should be empty when start == stop"); + } + + + // range iterations do not wrap/overflow + let mut oflo_loop_visited = ~[]; + for uint_range_step(uint::max_value-15, uint::max_value, 4) |x| { + oflo_loop_visited.push(uint::max_value - x); + } + assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]); + + let mut oflo_loop_visited = ~[]; + for int_range_step(int::max_value-15, int::max_value, 4) |x| { + oflo_loop_visited.push(int::max_value - x); + } + assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]); + + + // range_step never passes nor visits the stop element + for int_range_step(0, 21, 3) |x| { + assert!(x < 21); + } + + // range_step_inclusive will never pass stop element, and may skip it. + let mut saw21 = false; + for uint::range_step_inclusive(0, 21, 4) |x| { + assert!(x <= 21); + if x == 21 { saw21 = true; } + } + assert!(!saw21); + let mut saw21 = false; + for int::range_step_inclusive(0, 21, 4) |x| { + assert!(x <= 21); + if x == 21 { saw21 = true; } + } + assert!(!saw21); + + // range_step_inclusive will never pass stop element, but may visit it. + let mut saw21 = false; + for uint::range_step_inclusive(0, 21, 3) |x| { + assert!(x <= 21); + println(fmt!("saw: %u", x)); + if x == 21 { saw21 = true; } + } + assert!(saw21); + let mut saw21 = false; + for int::range_step_inclusive(0, 21, 3) |x| { + assert!(x <= 21); + if x == 21 { saw21 = true; } + } + assert!(saw21); + +} From db0a13b9865510ec07f7597e11009eabc2676afc Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 1 Jul 2013 12:30:14 +0200 Subject: [PATCH 2/8] Switch over to new range_rev semantics; fix #5270. --- src/libextra/smallintmap.rs | 4 ++-- src/libstd/num/int_macros.rs | 7 ++++--- src/libstd/num/uint_macros.rs | 7 ++++--- src/libstd/run.rs | 2 +- src/libstd/trie.rs | 2 +- src/test/run-pass/num-range-rev.rs | 18 +++++++++--------- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index d952374ee5ccc..329d3a454b45a 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -159,8 +159,8 @@ impl SmallIntMap { /// Visit all key-value pairs in reverse order pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { for uint::range_rev(self.v.len(), 0) |i| { - match self.v[i - 1] { - Some(ref elt) => if !it(i - 1, elt) { return false; }, + match self.v[i] { + Some(ref elt) => if !it(i, elt) { return false; }, None => () } } diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 4fd30be80e66e..cef32b5c7e445 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -132,9 +132,10 @@ pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool { } #[inline] -/// Iterate over the range [`hi`..`lo`) +/// Iterate over the range (`hi`..`lo`] pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - range_step(hi, lo, -1 as $T, it) + if hi == min_value { return true; } + range_step_inclusive(hi-1, lo, -1 as $T, it) } impl Num for $T {} @@ -897,7 +898,7 @@ mod tests { for range(0,3) |i| { l.push(i); } - for range_rev(13,10) |i| { + for range_rev(14,11) |i| { l.push(i); } for range_step(20,26,2) |i| { diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 09397ecfd7768..54c1327fa9303 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -132,9 +132,10 @@ pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool { } #[inline] -/// Iterate over the range [`hi`..`lo`) +/// Iterate over the range (`hi`..`lo`] pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - range_step(hi, lo, -1 as $T_SIGNED, it) + if hi == min_value { return true; } + range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it) } impl Num for $T {} @@ -662,7 +663,7 @@ mod tests { for range(0,3) |i| { l.push(i); } - for range_rev(13,10) |i| { + for range_rev(14,11) |i| { l.push(i); } for range_step(20,26,2) |i| { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 17dc604a17858..883870db1e673 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -669,7 +669,7 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); } // close all other fds - for int::range_rev(getdtablesize() as int - 1, 2) |fd| { + for int::range_rev(getdtablesize() as int, 3) |fd| { close(fd as c_int); } diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 8ce02d59ab15c..50552fd754788 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -261,7 +261,7 @@ impl TrieNode { fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx - 1] { + match self.children[idx] { Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs index e65c793a7b452..7262339e431d9 100644 --- a/src/test/run-pass/num-range-rev.rs +++ b/src/test/run-pass/num-range-rev.rs @@ -40,13 +40,13 @@ pub fn main() { // int and uint have same result for // Sum{100 > i >= 2} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99 let mut sum = 0u; - for uint_range_rev(99, 1) |i| { + for uint_range_rev(100, 2) |i| { sum += i; } assert_eq!(sum, 4949); let mut sum = 0i; - for int_range_rev(99, 1) |i| { + for int_range_rev(100, 2) |i| { sum += i; } assert_eq!(sum, 4949); @@ -55,17 +55,17 @@ pub fn main() { // elements are visited in correct order let primes = [2,3,5,7,11]; let mut prod = 1i; - for uint_range_rev(4, 0) |i| { + for uint_range_rev(5, 0) |i| { println(fmt!("uint 4 downto 0: %u", i)); prod *= int::pow(primes[i], i); } - assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3); + assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1); let mut prod = 1i; - for int_range_rev(4, 0) |i| { + for int_range_rev(5, 0) |i| { println(fmt!("int 4 downto 0: %d", i)); prod *= int::pow(primes[i], i as uint); } - assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3); + assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1); // range and range_rev are symmetric. @@ -74,7 +74,7 @@ pub fn main() { sum_up += i; } let mut sum_down = 0u; - for uint_range_rev(29, 9) |i| { + for uint_range_rev(30, 10) |i| { sum_down += i; } assert_eq!(sum_up, sum_down); @@ -84,7 +84,7 @@ pub fn main() { sum_up += i; } let mut sum_down = 0; - for int_range_rev(9, -21) |i| { + for int_range_rev(10, -20) |i| { sum_down += i; } assert_eq!(sum_up, sum_down); @@ -96,7 +96,7 @@ pub fn main() { } for uint_range_rev(0, 1) |_| { - // fail!("range should be empty when start-1 underflows"); + fail!("range should be empty when start-1 underflows"); } // range iterations do not wrap/underflow From 3896d46c0a6b99ef166bdc29220ef6c85ad8bc8d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 11 Jul 2013 16:56:49 +0200 Subject: [PATCH 3/8] Fix #5270: another test I did not update properly. --- src/libstd/trie.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 50552fd754788..f4597f4b08e9e 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -462,7 +462,7 @@ mod tests { m.insert(x, x / 2); } - let mut n = uint::max_value - 9999; + let mut n = uint::max_value - 10000; for m.each |k, v| { if n == uint::max_value - 5000 { break } assert!(n < uint::max_value - 5000); @@ -499,7 +499,7 @@ mod tests { m.insert(x, x / 2); } - let mut n = uint::max_value; + let mut n = uint::max_value - 1; for m.each_reverse |k, v| { if n == uint::max_value - 5000 { break } assert!(n > uint::max_value - 5000); From 877bba91d54457c104ff0bf67fd46a499a451cf6 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 16 Jul 2013 04:27:54 -0400 Subject: [PATCH 4/8] Permit C-style enums in vector repeat length expressions (N.B. values only, not type signatures) --- src/librustc/middle/const_eval.rs | 58 +++++++++++++++++++++-- src/librustc/middle/kind.rs | 2 +- src/librustc/middle/trans/tvec.rs | 4 +- src/librustc/middle/ty.rs | 47 +++++++++++------- src/librustc/middle/typeck/astconv.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 20 ++++++-- src/test/run-pass/enum-vec-initializer.rs | 24 ++++++++++ 7 files changed, 127 insertions(+), 30 deletions(-) create mode 100644 src/test/run-pass/enum-vec-initializer.rs diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index af39dea6d79e1..2cf99e07dc9f1 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -165,10 +165,58 @@ pub fn classify(e: &expr, pub fn lookup_const(tcx: ty::ctxt, e: &expr) -> Option<@expr> { match tcx.def_map.find(&e.id) { Some(&ast::def_static(def_id, false)) => lookup_const_by_id(tcx, def_id), + Some(&ast::def_variant(enum_def, variant_def)) => lookup_variant_by_id(tcx, + enum_def, + variant_def), _ => None } } +pub fn lookup_variant_by_id(tcx: ty::ctxt, + enum_def: ast::def_id, + variant_def: ast::def_id) + -> Option<@expr> { + fn variant_expr(variants: &[ast::variant], id: ast::node_id) -> Option<@expr> { + for variants.iter().advance |variant| { + if variant.node.id == id { + return variant.node.disr_expr; + } + } + None + } + + if ast_util::is_local(enum_def) { + match tcx.items.find(&enum_def.node) { + None => None, + Some(&ast_map::node_item(it, _)) => match it.node { + item_enum(ast::enum_def { variants: ref variants }, _) => { + variant_expr(*variants, variant_def.node) + } + _ => None + }, + Some(_) => None + } + } else { + let maps = astencode::Maps { + root_map: @mut HashMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), + write_guard_map: @mut HashSet::new(), + capture_map: @mut HashMap::new() + }; + match csearch::maybe_get_item_ast(tcx, enum_def, + |a, b, c, d| astencode::decode_inlined_item(a, b, maps, /*bar*/ copy c, d)) { + csearch::found(ast::ii_item(item)) => match item.node { + item_enum(ast::enum_def { variants: ref variants }, _) => { + variant_expr(*variants, variant_def.node) + } + _ => None + }, + _ => None + } + } +} + pub fn lookup_const_by_id(tcx: ty::ctxt, def_id: ast::def_id) -> Option<@expr> { @@ -237,13 +285,13 @@ pub enum const_val { } pub fn eval_const_expr(tcx: middle::ty::ctxt, e: &expr) -> const_val { - match eval_const_expr_partial(tcx, e) { + match eval_const_expr_partial(&tcx, e) { Ok(r) => r, Err(s) => tcx.sess.span_fatal(e.span, s) } } -pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: &expr) +pub fn eval_const_expr_partial(tcx: &T, e: &expr) -> Result { use middle::ty; fn fromb(b: bool) -> Result { Ok(const_int(b as i64)) } @@ -360,7 +408,7 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: &expr) } } expr_cast(base, _) => { - let ety = ty::expr_ty(tcx, e); + let ety = tcx.expr_ty(e); let base = eval_const_expr_partial(tcx, base); match /*bad*/copy base { Err(_) => base, @@ -390,8 +438,8 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: &expr) } } expr_path(_) => { - match lookup_const(tcx, e) { - Some(actual_e) => eval_const_expr_partial(tcx, actual_e), + match lookup_const(tcx.ty_ctxt(), e) { + Some(actual_e) => eval_const_expr_partial(&tcx.ty_ctxt(), actual_e), None => Err(~"Non-constant path in constant expr") } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index a9454d1b23096..ae2a27ed6ed7b 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -309,7 +309,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt)) { "explicit copy requires a copyable argument"); } expr_repeat(element, count_expr, _) => { - let count = ty::eval_repeat_count(cx.tcx, count_expr); + let count = ty::eval_repeat_count(&cx.tcx, count_expr); if count > 1 { let element_ty = ty::expr_ty(cx.tcx, element); check_copy(cx, element_ty, element.span, diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 8fff23c649848..561c9a3399a04 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -417,7 +417,7 @@ pub fn write_content(bcx: block, return expr::trans_into(bcx, element, Ignore); } SaveIn(lldest) => { - let count = ty::eval_repeat_count(bcx.tcx(), count_expr); + let count = ty::eval_repeat_count(&bcx.tcx(), count_expr); if count == 0 { return bcx; } @@ -509,7 +509,7 @@ pub fn elements_required(bcx: block, content_expr: &ast::expr) -> uint { }, ast::expr_vec(ref es, _) => es.len(), ast::expr_repeat(_, count_expr, _) => { - ty::eval_repeat_count(bcx.tcx(), count_expr) + ty::eval_repeat_count(&bcx.tcx(), count_expr) } _ => bcx.tcx().sess.span_bug(content_expr.span, "Unexpected evec content") diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8e23f5431bcee..eb69798d0cce8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4230,42 +4230,57 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { return t_norm; } +pub trait ExprTyProvider { + pub fn expr_ty(&self, ex: &ast::expr) -> t; + pub fn ty_ctxt(&self) -> ctxt; +} + +impl ExprTyProvider for ctxt { + pub fn expr_ty(&self, ex: &ast::expr) -> t { + expr_ty(*self, ex) + } + + pub fn ty_ctxt(&self) -> ctxt { + *self + } +} + // Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count(tcx: ctxt, count_expr: &ast::expr) -> uint { +pub fn eval_repeat_count(tcx: &T, count_expr: &ast::expr) -> uint { match const_eval::eval_const_expr_partial(tcx, count_expr) { Ok(ref const_val) => match *const_val { const_eval::const_int(count) => if count < 0 { - tcx.sess.span_err(count_expr.span, - "expected positive integer for \ - repeat count but found negative integer"); + tcx.ty_ctxt().sess.span_err(count_expr.span, + "expected positive integer for \ + repeat count but found negative integer"); return 0; } else { return count as uint }, const_eval::const_uint(count) => return count as uint, const_eval::const_float(count) => { - tcx.sess.span_err(count_expr.span, - "expected positive integer for \ - repeat count but found float"); + tcx.ty_ctxt().sess.span_err(count_expr.span, + "expected positive integer for \ + repeat count but found float"); return count as uint; } const_eval::const_str(_) => { - tcx.sess.span_err(count_expr.span, - "expected positive integer for \ - repeat count but found string"); + tcx.ty_ctxt().sess.span_err(count_expr.span, + "expected positive integer for \ + repeat count but found string"); return 0; } const_eval::const_bool(_) => { - tcx.sess.span_err(count_expr.span, - "expected positive integer for \ - repeat count but found boolean"); + tcx.ty_ctxt().sess.span_err(count_expr.span, + "expected positive integer for \ + repeat count but found boolean"); return 0; } }, Err(*) => { - tcx.sess.span_err(count_expr.span, - "expected constant integer for repeat count \ - but found variable"); + tcx.ty_ctxt().sess.span_err(count_expr.span, + "expected constant integer for repeat count \ + but found variable"); return 0; } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index d8185022e416d..1186f8cecabc5 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -479,7 +479,7 @@ pub fn ast_ty_to_ty( } } ast::ty_fixed_length_vec(ref a_mt, e) => { - match const_eval::eval_const_expr_partial(tcx, e) { + match const_eval::eval_const_expr_partial(&tcx, e) { Ok(ref r) => { match *r { const_eval::const_int(i) => diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4caf0b62a546d..396fae68f737c 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -83,7 +83,7 @@ use middle::pat_util; use middle::lint::unreachable_code; use middle::ty::{FnSig, VariantInfo_}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; -use middle::ty::{substs, param_ty}; +use middle::ty::{substs, param_ty, ExprTyProvider}; use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; @@ -290,6 +290,16 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, } } +impl ExprTyProvider for FnCtxt { + pub fn expr_ty(&self, ex: &ast::expr) -> ty::t { + self.expr_ty(ex) + } + + pub fn ty_ctxt(&self) -> ty::ctxt { + self.ccx.tcx + } +} + pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) { let visit = visit::mk_simple_visitor(@visit::SimpleVisitor { visit_item: |a| check_item(ccx, a), @@ -797,7 +807,7 @@ impl FnCtxt { pat.repr(self.tcx()) } - pub fn expr_ty(&self, ex: @ast::expr) -> ty::t { + pub fn expr_ty(&self, ex: &ast::expr) -> ty::t { match self.inh.node_types.find(&ex.id) { Some(&t) => t, None => { @@ -2250,8 +2260,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } ast::expr_repeat(element, count_expr, mutbl) => { - let _ = ty::eval_repeat_count(tcx, count_expr); check_expr_with_hint(fcx, count_expr, ty::mk_uint()); + let _ = ty::eval_repeat_count(fcx, count_expr); let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); let mutability = match vst { ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => { @@ -2730,8 +2740,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, typ); } ast::expr_repeat(element, count_expr, mutbl) => { - let count = ty::eval_repeat_count(tcx, count_expr); check_expr_with_hint(fcx, count_expr, ty::mk_uint()); + let count = ty::eval_repeat_count(fcx, count_expr); let t: ty::t = fcx.infcx().next_ty_var(); check_expr_has_type(fcx, element, t); let element_ty = fcx.expr_ty(element); @@ -3126,7 +3136,7 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, // that the expression is in an form that eval_const_expr can // handle, so we may still get an internal compiler error - match const_eval::eval_const_expr_partial(ccx.tcx, e) { + match const_eval::eval_const_expr_partial(&ccx.tcx, e) { Ok(const_eval::const_int(val)) => { *disr_val = val as int; } diff --git a/src/test/run-pass/enum-vec-initializer.rs b/src/test/run-pass/enum-vec-initializer.rs new file mode 100644 index 0000000000000..ae590ad7d1f71 --- /dev/null +++ b/src/test/run-pass/enum-vec-initializer.rs @@ -0,0 +1,24 @@ +// 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. + +enum Flopsy { + Bunny = 2 +} + +static BAR:uint = Bunny as uint; +static BAR2:uint = BAR; + +fn main() { + let v = [0, .. Bunny as uint]; + let v = [0, .. BAR]; + let v = [0, .. BAR2]; + static BAR3:uint = BAR2; + let v = [0, .. BAR3]; +} \ No newline at end of file From 712ac836c63c3ae98daf9fb98b7b96ed73347848 Mon Sep 17 00:00:00 2001 From: Austin King Date: Tue, 16 Jul 2013 12:47:01 -0700 Subject: [PATCH 5/8] Rename Option swap_unwrap to take_unwrap. Fixes Issue#7764 --- src/libextra/dlist.rs | 6 +++--- src/libextra/net/ip.rs | 2 +- src/libextra/sync.rs | 8 ++++---- src/libextra/treemap.rs | 12 ++++++------ src/libstd/option.rs | 14 +++++++------- src/libstd/rt/sched.rs | 10 +++++----- src/libstd/rt/task.rs | 2 +- src/libstd/rt/tube.rs | 2 +- src/libstd/rt/uv/async.rs | 2 +- src/libstd/rt/uv/idle.rs | 2 +- src/libstd/rt/uv/net.rs | 10 +++++----- src/libstd/rt/uv/timer.rs | 2 +- src/libstd/task/spawn.rs | 6 +++--- src/test/bench/msgsend-ring-mutex-arcs.rs | 4 ++-- src/test/bench/msgsend-ring-rw-arcs.rs | 4 ++-- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 9eacddd90028b..35600df4f9dd0 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -173,11 +173,11 @@ impl Deque for DList { let tail_own = match tail.prev.resolve() { None => { self.list_tail = Rawlink::none(); - self.list_head.swap_unwrap() + self.list_head.take_unwrap() }, Some(tail_prev) => { self.list_tail = tail.prev; - tail_prev.next.swap_unwrap() + tail_prev.next.take_unwrap() } }; Some(tail_own.value) @@ -465,7 +465,7 @@ impl<'self, A> ListInsertion for MutDListIterator<'self, A> { Some(prev) => prev, }; let mut ins_node = ~Node{value: elt, next: None, prev: Rawlink::none()}; - let node_own = prev_node.next.swap_unwrap(); + let node_own = prev_node.next.take_unwrap(); ins_node.next = link_with_prev(node_own, Rawlink::some(ins_node)); prev_node.next = link_with_prev(ins_node, Rawlink::some(prev_node)); self.list.length += 1; diff --git a/src/libextra/net/ip.rs b/src/libextra/net/ip.rs index 6876b3510b6ca..11e3106e4b5a9 100644 --- a/src/libextra/net/ip.rs +++ b/src/libextra/net/ip.rs @@ -116,7 +116,7 @@ pub fn get_addr(node: &str, iotask: &iotask) let (output_po, output_ch) = stream(); let mut output_ch = Some(SharedChan::new(output_ch)); do str::as_buf(node) |node_ptr, len| { - let output_ch = output_ch.swap_unwrap(); + let output_ch = output_ch.take_unwrap(); debug!("slice len %?", len); let handle = create_uv_getaddrinfo_t(); let handle_ptr: *uv_getaddrinfo_t = &handle; diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index b9d25451a8a95..632f5d7827d4c 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -260,7 +260,7 @@ impl<'self> Condvar<'self> { signal_waitqueue(&state.waiters); } // Enqueue ourself to be woken up by a signaller. - let SignalEnd = SignalEnd.swap_unwrap(); + let SignalEnd = SignalEnd.take_unwrap(); state.blocked[condvar_id].tail.send(SignalEnd); } else { out_of_bounds = Some(state.blocked.len()); @@ -281,7 +281,7 @@ impl<'self> Condvar<'self> { // Unconditionally "block". (Might not actually block if a // signaller already sent -- I mean 'unconditionally' in contrast // with acquire().) - let _ = comm::recv_one(WaitEnd.swap_unwrap()); + let _ = comm::recv_one(WaitEnd.take_unwrap()); } // This is needed for a failing condition variable to reacquire the @@ -353,7 +353,7 @@ impl<'self> Condvar<'self> { } } do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") { - let queue = queue.swap_unwrap(); + let queue = queue.take_unwrap(); broadcast_waitqueue(&queue) } } @@ -1436,7 +1436,7 @@ mod tests { do x.write_downgrade |xwrite| { let mut xopt = Some(xwrite); do y.write_downgrade |_ywrite| { - y.downgrade(xopt.swap_unwrap()); + y.downgrade(xopt.take_unwrap()); error!("oops, y.downgrade(x) should have failed!"); } } diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index f1fe7acb00f83..bd13c8619be1d 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -552,7 +552,7 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, // Remove left horizontal link by rotating right fn skew(node: &mut ~TreeNode) { if node.left.map_default(false, |x| x.level == node.level) { - let mut save = node.left.swap_unwrap(); + let mut save = node.left.take_unwrap(); swap(&mut node.left, &mut save.right); // save.right now None swap(node, &mut save); node.right = Some(save); @@ -564,7 +564,7 @@ fn skew(node: &mut ~TreeNode) { fn split(node: &mut ~TreeNode) { if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) { - let mut save = node.right.swap_unwrap(); + let mut save = node.right.take_unwrap(); swap(&mut node.right, &mut save.left); // save.left now None save.level += 1; swap(node, &mut save); @@ -643,7 +643,7 @@ fn remove(node: &mut Option<~TreeNode>, Equal => { if save.left.is_some() { if save.right.is_some() { - let mut left = save.left.swap_unwrap(); + let mut left = save.left.take_unwrap(); if left.right.is_some() { heir_swap(save, &mut left.right); } else { @@ -653,13 +653,13 @@ fn remove(node: &mut Option<~TreeNode>, save.left = Some(left); (remove(&mut save.left, key), true) } else { - let new = save.left.swap_unwrap(); + let new = save.left.take_unwrap(); let ~TreeNode{value, _} = replace(save, new); - *save = save.left.swap_unwrap(); + *save = save.left.take_unwrap(); (Some(value), true) } } else if save.right.is_some() { - let new = save.right.swap_unwrap(); + let new = save.right.take_unwrap(); let ~TreeNode{value, _} = replace(save, new); (Some(value), true) } else { diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 222952a6dc143..b0811674a7bfa 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -203,14 +203,14 @@ impl Option { /// Apply a function to the contained value or do nothing pub fn mutate(&mut self, f: &fn(T) -> T) { if self.is_some() { - *self = Some(f(self.swap_unwrap())); + *self = Some(f(self.take_unwrap())); } } /// Apply a function to the contained value or set it to a default pub fn mutate_default(&mut self, def: T, f: &fn(T) -> T) { if self.is_some() { - *self = Some(f(self.swap_unwrap())); + *self = Some(f(self.take_unwrap())); } else { *self = Some(def); } @@ -293,8 +293,8 @@ impl Option { * Fails if the value equals `None`. */ #[inline] - pub fn swap_unwrap(&mut self) -> T { - if self.is_none() { fail!("option::swap_unwrap none") } + pub fn take_unwrap(&mut self) -> T { + if self.is_none() { fail!("option::take_unwrap none") } util::replace(self, None).unwrap() } @@ -460,7 +460,7 @@ fn test_option_dance() { let mut y = Some(5); let mut y2 = 0; for x.iter().advance |_x| { - y2 = y.swap_unwrap(); + y2 = y.take_unwrap(); } assert_eq!(y2, 5); assert!(y.is_none()); @@ -468,8 +468,8 @@ fn test_option_dance() { #[test] #[should_fail] #[ignore(cfg(windows))] fn test_option_too_much_dance() { let mut y = Some(util::NonCopyable); - let _y2 = y.swap_unwrap(); - let _y3 = y.swap_unwrap(); + let _y2 = y.take_unwrap(); + let _y3 = y.take_unwrap(); } #[test] diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 6e9aef7773051..4e4145ddc161f 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -328,7 +328,7 @@ impl Scheduler { /// Given an input Coroutine sends it back to its home scheduler. fn send_task_home(task: ~Task) { let mut task = task; - let mut home = task.home.swap_unwrap(); + let mut home = task.home.take_unwrap(); match home { Sched(ref mut home_handle) => { home_handle.send(PinnedTask(task)); @@ -418,7 +418,7 @@ impl Scheduler { do self.deschedule_running_task_and_then |sched, dead_task| { let mut dead_task = dead_task; - let coroutine = dead_task.coroutine.swap_unwrap(); + let coroutine = dead_task.coroutine.take_unwrap(); coroutine.recycle(&mut sched.stack_pool); } @@ -506,7 +506,7 @@ impl Scheduler { this.metrics.context_switches_task_to_sched += 1; unsafe { - let blocked_task = this.current_task.swap_unwrap(); + let blocked_task = this.current_task.take_unwrap(); let f_fake_region = transmute::<&fn(&mut Scheduler, ~Task), &fn(&mut Scheduler, ~Task)>(f); let f_opaque = ClosureConverter::from_fn(f_fake_region); @@ -538,7 +538,7 @@ impl Scheduler { rtdebug!("switching tasks"); this.metrics.context_switches_task_to_task += 1; - let old_running_task = this.current_task.swap_unwrap(); + let old_running_task = this.current_task.take_unwrap(); let f_fake_region = unsafe { transmute::<&fn(&mut Scheduler, ~Task), &fn(&mut Scheduler, ~Task)>(f) @@ -576,7 +576,7 @@ impl Scheduler { assert!(self.cleanup_job.is_some()); - let cleanup_job = self.cleanup_job.swap_unwrap(); + let cleanup_job = self.cleanup_job.take_unwrap(); match cleanup_job { DoNothing => { } GiveTask(task, f) => (f.to_fn())(self, task) diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 17d0d59660f1b..449438b920551 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -127,7 +127,7 @@ impl Task { // Wait for children. Possibly report the exit status. let local_success = !self.unwinder.unwinding; - let join_latch = self.join_latch.swap_unwrap(); + let join_latch = self.join_latch.take_unwrap(); match self.on_exit { Some(ref on_exit) => { let success = join_latch.wait(local_success); diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs index 013eb438c3657..f61eee8859b1a 100644 --- a/src/libstd/rt/tube.rs +++ b/src/libstd/rt/tube.rs @@ -53,7 +53,7 @@ impl Tube { if (*state).blocked_task.is_some() { // There's a waiting task. Wake it up rtdebug!("waking blocked tube"); - let task = (*state).blocked_task.swap_unwrap(); + let task = (*state).blocked_task.take_unwrap(); let sched = Local::take::(); sched.resume_task_immediately(task); } diff --git a/src/libstd/rt/uv/async.rs b/src/libstd/rt/uv/async.rs index f3d1024024ff8..81428509e33e5 100644 --- a/src/libstd/rt/uv/async.rs +++ b/src/libstd/rt/uv/async.rs @@ -62,7 +62,7 @@ impl AsyncWatcher { let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle); { let data = watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); + data.close_cb.take_unwrap()(); } watcher.drop_watcher_data(); unsafe { uvll::free_handle(handle as *c_void); } diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index a3630c9b9bf8d..28b101f686d4c 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -73,7 +73,7 @@ impl IdleWatcher { let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); { let data = idle_watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); + data.close_cb.take_unwrap()(); } idle_watcher.drop_watcher_data(); uvll::idle_delete(handle); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 6d096f9885a7d..09c748ec04782 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -209,7 +209,7 @@ impl StreamWatcher { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = stream_watcher.get_watcher_data().write_cb.swap_unwrap(); + let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap(); let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -233,7 +233,7 @@ impl StreamWatcher { extern fn close_cb(handle: *uvll::uv_stream_t) { let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - stream_watcher.get_watcher_data().close_cb.swap_unwrap()(); + stream_watcher.get_watcher_data().close_cb.take_unwrap()(); stream_watcher.drop_watcher_data(); unsafe { free_handle(handle as *c_void) } } @@ -301,7 +301,7 @@ impl TcpWatcher { let connect_request: ConnectRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = connect_request.stream(); connect_request.delete(); - let cb = stream_watcher.get_watcher_data().connect_cb.swap_unwrap(); + let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap(); let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -438,7 +438,7 @@ impl UdpWatcher { let send_request: UdpSendRequest = NativeHandle::from_native_handle(req); let mut udp_watcher = send_request.handle(); send_request.delete(); - let cb = udp_watcher.get_watcher_data().udp_send_cb.swap_unwrap(); + let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap(); let status = status_to_maybe_uv_error(udp_watcher.native_handle(), status); cb(udp_watcher, status); } @@ -456,7 +456,7 @@ impl UdpWatcher { extern fn close_cb(handle: *uvll::uv_udp_t) { let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - udp_watcher.get_watcher_data().close_cb.swap_unwrap()(); + udp_watcher.get_watcher_data().close_cb.take_unwrap()(); udp_watcher.drop_watcher_data(); unsafe { free_handle(handle as *c_void) } } diff --git a/src/libstd/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs index 14465eb7dfd3a..bc5399327a032 100644 --- a/src/libstd/rt/uv/timer.rs +++ b/src/libstd/rt/uv/timer.rs @@ -70,7 +70,7 @@ impl TimerWatcher { let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle); { let data = watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); + data.close_cb.take_unwrap()(); } watcher.drop_watcher_data(); unsafe { diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 206d19e175fe9..bf09a533ebe12 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -302,7 +302,7 @@ fn each_ancestor(list: &mut AncestorList, fn with_parent_tg(parent_group: &mut Option, blk: &fn(TaskGroupInner) -> U) -> U { // If this trips, more likely the problem is 'blk' failed inside. - let tmp_arc = parent_group.swap_unwrap(); + let tmp_arc = parent_group.take_unwrap(); let result = do access_group(&tmp_arc) |tg_opt| { blk(tg_opt) }; *parent_group = Some(tmp_arc); result @@ -609,7 +609,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { }; if opts.notify_chan.is_some() { - let notify_chan = opts.notify_chan.swap_unwrap(); + let notify_chan = opts.notify_chan.take_unwrap(); let notify_chan = Cell::new(notify_chan); let on_exit: ~fn(bool) = |success| { notify_chan.take().send( @@ -647,7 +647,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { let notify_chan = if opts.notify_chan.is_none() { None } else { - Some(opts.notify_chan.swap_unwrap()) + Some(opts.notify_chan.take_unwrap()) }; let child_wrapper = make_child_wrapper(new_task, child_tg, diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index 2bd53f81b0581..0bf492ae55f0c 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -60,8 +60,8 @@ fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { // Send/Receive lots of messages. for uint::range(0u, count) |j| { //error!("task %?, iter %?", i, j); - let mut num_chan2 = num_chan.swap_unwrap(); - let mut num_port2 = num_port.swap_unwrap(); + let mut num_chan2 = num_chan.take_unwrap(); + let mut num_port2 = num_port.take_unwrap(); send(&num_chan2, i * j); num_chan = Some(num_chan2); let _n = recv(&num_port2); diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs index b5b5b685d87c4..a5f96b35999e2 100644 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ b/src/test/bench/msgsend-ring-rw-arcs.rs @@ -56,8 +56,8 @@ fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { // Send/Receive lots of messages. for uint::range(0u, count) |j| { //error!("task %?, iter %?", i, j); - let mut num_chan2 = num_chan.swap_unwrap(); - let mut num_port2 = num_port.swap_unwrap(); + let mut num_chan2 = num_chan.take_unwrap(); + let mut num_port2 = num_port.take_unwrap(); send(&num_chan2, i * j); num_chan = Some(num_chan2); let _n = recv(&num_port2); From 40f74341f3ba2cee2afedb31014ee14432d700cd Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 16 Jul 2013 17:42:28 -0700 Subject: [PATCH 6/8] test: new codegen tests, rename hello. --- src/test/codegen/iterate-over-array.cc | 17 +++++++++++++++++ src/test/codegen/iterate-over-array.rs | 10 ++++++++++ src/test/codegen/scalar-function-call.cc | 10 ++++++++++ src/test/codegen/scalar-function-call.rs | 8 ++++++++ src/test/codegen/small-dense-int-switch.cc | 11 +++++++++++ src/test/codegen/small-dense-int-switch.rs | 9 +++++++++ .../{hello.cc => stack-alloc-string-slice.cc} | 0 .../{hello.rs => stack-alloc-string-slice.rs} | 0 8 files changed, 65 insertions(+) create mode 100644 src/test/codegen/iterate-over-array.cc create mode 100644 src/test/codegen/iterate-over-array.rs create mode 100644 src/test/codegen/scalar-function-call.cc create mode 100644 src/test/codegen/scalar-function-call.rs create mode 100644 src/test/codegen/small-dense-int-switch.cc create mode 100644 src/test/codegen/small-dense-int-switch.rs rename src/test/codegen/{hello.cc => stack-alloc-string-slice.cc} (100%) rename src/test/codegen/{hello.rs => stack-alloc-string-slice.rs} (100%) diff --git a/src/test/codegen/iterate-over-array.cc b/src/test/codegen/iterate-over-array.cc new file mode 100644 index 0000000000000..7eca21b13d70b --- /dev/null +++ b/src/test/codegen/iterate-over-array.cc @@ -0,0 +1,17 @@ +#include +#include + +struct slice { + int const *p; + size_t len; +}; + +extern "C" +size_t test(slice s) { + size_t y = 0; + for (int i = 0; i < s.len; ++i) { + assert(i < s.len); + y += s.p[i]; + } + return y; +} diff --git a/src/test/codegen/iterate-over-array.rs b/src/test/codegen/iterate-over-array.rs new file mode 100644 index 0000000000000..cf54e6eafbaf1 --- /dev/null +++ b/src/test/codegen/iterate-over-array.rs @@ -0,0 +1,10 @@ +#[no_mangle] +fn test(x: &[int]) -> int { + let mut y = 0; + let mut i = 0; + while (i < x.len()) { + y += x[i]; + i += 1; + } + y +} diff --git a/src/test/codegen/scalar-function-call.cc b/src/test/codegen/scalar-function-call.cc new file mode 100644 index 0000000000000..91ed882f68a9f --- /dev/null +++ b/src/test/codegen/scalar-function-call.cc @@ -0,0 +1,10 @@ +#include + +size_t foo(size_t x) { + return x * x; +} + +extern "C" +void test() { + size_t x = foo(10); +} diff --git a/src/test/codegen/scalar-function-call.rs b/src/test/codegen/scalar-function-call.rs new file mode 100644 index 0000000000000..7e4a566749ba6 --- /dev/null +++ b/src/test/codegen/scalar-function-call.rs @@ -0,0 +1,8 @@ +fn foo(x: int) -> int { + x * x +} + +#[no_mangle] +fn test() { + let x = foo(10); +} diff --git a/src/test/codegen/small-dense-int-switch.cc b/src/test/codegen/small-dense-int-switch.cc new file mode 100644 index 0000000000000..87bc5bf852eb4 --- /dev/null +++ b/src/test/codegen/small-dense-int-switch.cc @@ -0,0 +1,11 @@ +#include + +extern "C" +size_t test(size_t x, size_t y) { + switch (x) { + case 1: return y; + case 2: return y*2; + case 4: return y*3; + default: return 11; + } +} diff --git a/src/test/codegen/small-dense-int-switch.rs b/src/test/codegen/small-dense-int-switch.rs new file mode 100644 index 0000000000000..6840dc7411b34 --- /dev/null +++ b/src/test/codegen/small-dense-int-switch.rs @@ -0,0 +1,9 @@ +#[no_mangle] +fn test(x: int, y: int) -> int { + match x { + 1 => y, + 2 => y*2, + 4 => y*3, + _ => 11 + } +} diff --git a/src/test/codegen/hello.cc b/src/test/codegen/stack-alloc-string-slice.cc similarity index 100% rename from src/test/codegen/hello.cc rename to src/test/codegen/stack-alloc-string-slice.cc diff --git a/src/test/codegen/hello.rs b/src/test/codegen/stack-alloc-string-slice.rs similarity index 100% rename from src/test/codegen/hello.rs rename to src/test/codegen/stack-alloc-string-slice.rs From 81c576cd5bbae5207694121ca8c21098a847c153 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Jul 2013 07:19:43 -0400 Subject: [PATCH 7/8] Issue #7444 - Borrowck permits moved values to be captured --- src/librustc/middle/borrowck/check_loans.rs | 18 ++++++++---------- .../typeck/infer/region_inference/mod.rs | 1 - .../borrowck-move-moved-value-into-closure.rs | 10 ++++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/borrowck-move-moved-value-into-closure.rs diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index a455bdc436cad..4fe9f15c7c889 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -639,15 +639,14 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, span: span) { let cap_vars = this.bccx.capture_map.get(&closure_id); for cap_vars.iter().advance |cap_var| { + let var_id = ast_util::def_id_of_def(cap_var.def).node; + let var_path = @LpVar(var_id); + this.check_if_path_is_moved(closure_id, span, + MovedInCapture, var_path); match cap_var.mode { - moves::CapRef | moves::CapCopy => { - let var_id = ast_util::def_id_of_def(cap_var.def).node; - let lp = @LpVar(var_id); - this.check_if_path_is_moved(closure_id, span, - MovedInCapture, lp); - } + moves::CapRef | moves::CapCopy => {} moves::CapMove => { - check_by_move_capture(this, closure_id, cap_var); + check_by_move_capture(this, closure_id, cap_var, var_path); } } } @@ -655,9 +654,8 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, fn check_by_move_capture(this: @mut CheckLoanCtxt, closure_id: ast::node_id, - cap_var: &moves::CaptureVar) { - let var_id = ast_util::def_id_of_def(cap_var.def).node; - let move_path = @LpVar(var_id); + cap_var: &moves::CaptureVar, + move_path: @LoanPath) { let move_err = this.analyze_move_out_from(closure_id, move_path); match move_err { MoveOk => {} diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index c3b35aba5181b..2342b60ace05b 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -385,7 +385,6 @@ impl RegionVarBindings { pub fn tainted(&mut self, snapshot: uint, r0: Region) -> ~[Region] { /*! - * * Computes all regions that have been related to `r0` in any * way since the snapshot `snapshot` was taken---`r0` itself * will be the first entry. This is used when checking whether diff --git a/src/test/compile-fail/borrowck-move-moved-value-into-closure.rs b/src/test/compile-fail/borrowck-move-moved-value-into-closure.rs new file mode 100644 index 0000000000000..5e789e99c0559 --- /dev/null +++ b/src/test/compile-fail/borrowck-move-moved-value-into-closure.rs @@ -0,0 +1,10 @@ +fn call_f(f: ~fn:Send() -> int) -> int { + f() +} + +fn main() { + let t = ~3; + + call_f(|| { *t + 1 }); + call_f(|| { *t + 1 }); //~ ERROR capture of moved value +} From 782853c65846be185c9b8bf930e1b47b78f6fdf6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Jul 2013 09:01:29 -0400 Subject: [PATCH 8/8] Issue #7444 - Update neg test and pos test for move by capture --- src/test/compile-fail/borrowck-move-by-capture.rs | 4 +++- src/test/run-pass/borrowck-move-by-capture-ok.rs | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/borrowck-move-by-capture-ok.rs diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index 4ee824d1d49ad..ecb18993d9300 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -4,8 +4,10 @@ pub fn main() { let _f: @fn() -> int = || *foo + 5; //~^ ERROR cannot move `foo` + // FIXME(#2202) - Due to the way that borrowck treats closures, + // you get two error reports here. let bar = ~3; let _g = || { //~ ERROR capture of moved value - let _h: @fn() -> int = || *bar; + let _h: @fn() -> int = || *bar; //~ ERROR capture of moved value }; } diff --git a/src/test/run-pass/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck-move-by-capture-ok.rs new file mode 100644 index 0000000000000..095e2ba6fea4b --- /dev/null +++ b/src/test/run-pass/borrowck-move-by-capture-ok.rs @@ -0,0 +1,5 @@ +pub fn main() { + let bar = ~3; + let h: @fn() -> int = || *bar; + assert_eq!(h(), 3); +}