From 5c08237456c3d6b4c9553ebe2f13eba5b97a4e09 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 28 Jul 2013 09:31:37 -0700 Subject: [PATCH 01/48] option.get -> option.unwrap --- src/compiletest/runtest.rs | 5 ++--- src/libextra/workcache.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5c1cc78d678f..0d1c5c8eb435 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -162,9 +162,8 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { round += 1; } - let mut expected = - match props.pp_exact { - Some(ref file) => { + let mut expected = match props.pp_exact { + Some(ref file) => { let filepath = testfile.dir_path().push_rel(file); io::read_whole_file_str(&filepath).unwrap() } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 0256519abb7e..b4ba8acae476 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -221,7 +221,7 @@ fn digest>(t: &T) -> ~str { fn digest_file(path: &Path) -> ~str { let mut sha = ~Sha1::new(); let s = io::read_whole_file_str(path); - (*sha).input_str(*s.get_ref()); + (*sha).input_str(s.unwrap()); (*sha).result_str() } @@ -378,7 +378,7 @@ fn test() { let pth = Path("foo.c"); { let r = io::file_writer(&pth, [io::Create]); - r.get_ref().write_str("int main() { return 0; }"); + r.unwrap().write_str("int main() { return 0; }"); } let cx = Context::new(RWArc::new(Database::new(Path("db.json"))), From 9218aaa00ed0883d3a082f8753a206fb6d03dac9 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 4 Aug 2013 16:05:25 -0700 Subject: [PATCH 02/48] std: add result.map_move, result.map_err_move --- src/libextra/num/bigint.rs | 2 +- src/librustc/middle/ty.rs | 8 ++-- src/librustc/middle/typeck/check/vtable.rs | 4 +- src/libstd/local_data.rs | 12 ++--- src/libstd/result.rs | 56 ++++++++++++++++++++-- src/libstd/rt/task.rs | 4 +- 6 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index bced00902c95..890f5e40e970 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -2028,7 +2028,7 @@ mod bigint_tests { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map(|&n| IntConvertible::from_int::(n)); + let ans = ans.map_move(|n| IntConvertible::from_int::(n)); assert_eq!(FromStrRadix::from_str_radix(s, 10), ans); } check("10", Some(10)); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a53bdff85f9d..3f4db29ef7e7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4443,15 +4443,15 @@ pub fn count_traits_and_supertraits(tcx: ctxt, } pub fn get_tydesc_ty(tcx: ctxt) -> Result { - do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| { - tcx.intrinsic_defs.find_copy(tydesc_lang_item) + do tcx.lang_items.require(TyDescStructLangItem).map_move |tydesc_lang_item| { + tcx.intrinsic_defs.find_copy(&tydesc_lang_item) .expect("Failed to resolve TyDesc") } } pub fn get_opaque_ty(tcx: ctxt) -> Result { - do tcx.lang_items.require(OpaqueStructLangItem).map |opaque_lang_item| { - tcx.intrinsic_defs.find_copy(opaque_lang_item) + do tcx.lang_items.require(OpaqueStructLangItem).map_move |opaque_lang_item| { + tcx.intrinsic_defs.find_copy(&opaque_lang_item) .expect("Failed to resolve Opaque") } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index abb97f0d1c7b..700d96727eae 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -131,9 +131,7 @@ fn lookup_vtables_for_param(vcx: &VtableContext, // ty is the value supplied for the type parameter A... let mut param_result = ~[]; - do ty::each_bound_trait_and_supertraits( - tcx, type_param_bounds.trait_bounds) |trait_ref| - { + do ty::each_bound_trait_and_supertraits(tcx, type_param_bounds.trait_bounds) |trait_ref| { // ...and here trait_ref is each bound that was declared on A, // expressed in terms of the type parameters. diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index c2a60e1c0e9c..a73809d202c4 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -110,16 +110,16 @@ fn test_tls_multitask() { set(my_key, @~"parent data"); do task::spawn { // TLS shouldn't carry over. - assert!(get(my_key, |k| k.map(|&k| *k)).is_none()); + assert!(get(my_key, |k| k.map_move(|k| *k)).is_none()); set(my_key, @~"child data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"child data"); // should be cleaned up for us } // Must work multiple times - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); } #[test] @@ -127,7 +127,7 @@ fn test_tls_overwrite() { static my_key: Key<@~str> = &Key; set(my_key, @~"first data"); set(my_key, @~"next data"); // Shouldn't leak. - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"next data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data"); } #[test] diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 91f42edf0aec..e62ae3885eb9 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -149,6 +149,40 @@ impl Result { } } + /// Call a method based on a previous result + /// + /// If `self` is `Ok` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is + /// `Err` then it is immediately returned. This function can be used to + /// compose the results of two functions. + /// + /// Example: + /// + /// let res = do read_file(file).map_move |buf| { + /// parse_bytes(buf) + /// } + #[inline] + pub fn map_move(self, op: &fn(T) -> U) -> Result { + match self { + Ok(t) => Ok(op(t)), + Err(e) => Err(e) + } + } + + /// Call a method based on a previous result + /// + /// If `self` is `Err` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is + /// `Ok` then it is immediately returned. This function can be used to pass + /// through a successful result while handling an error. + #[inline] + pub fn map_err_move(self, op: &fn(E) -> F) -> Result { + match self { + Ok(t) => Ok(t), + Err(e) => Err(op(e)) + } + } + /// Call a method based on a previous result /// /// If `self` is `Ok` then the value is extracted and passed to `op` @@ -312,7 +346,9 @@ pub fn iter_vec2(ss: &[S], ts: &[T], #[cfg(test)] mod tests { use super::*; + use either; + use str::OwnedStr; pub fn op1() -> Result { Ok(666) } @@ -359,14 +395,26 @@ mod tests { #[test] pub fn test_impl_map() { - assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b")); - assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a")); + assert_eq!(Ok::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Ok(~"ba")); + assert_eq!(Err::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Err(~"a")); } #[test] pub fn test_impl_map_err() { - assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a")); - assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b")); + assert_eq!(Ok::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Ok(~"a")); + assert_eq!(Err::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Err(~"ba")); + } + + #[test] + pub fn test_impl_map_move() { + assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Ok(~"ab")); + assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Err(~"a")); + } + + #[test] + pub fn test_impl_map_err_move() { + assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Ok(~"a")); + assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Err(~"ab")); } #[test] diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 4c5e4bdc3c1d..e732ef67b5b1 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -465,10 +465,10 @@ mod test { do run_in_newsched_task() { static key: local_data::Key<@~str> = &local_data::Key; local_data::set(key, @~"data"); - assert!(*local_data::get(key, |k| k.map(|&k| *k)).unwrap() == ~"data"); + assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data"); static key2: local_data::Key<@~str> = &local_data::Key; local_data::set(key2, @~"data"); - assert!(*local_data::get(key2, |k| k.map(|&k| *k)).unwrap() == ~"data"); + assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data"); } } From 1e490813b017f99cb4385fe846d645efe5d62b62 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 4 Aug 2013 14:59:36 -0700 Subject: [PATCH 03/48] core: option.map_consume -> option.map_move --- src/compiletest/compiletest.rs | 14 +++++----- src/libextra/dlist.rs | 20 ++++++------- src/libextra/num/bigint.rs | 4 +-- src/libextra/smallintmap.rs | 2 +- src/libextra/term.rs | 4 +-- src/libextra/test.rs | 8 +++--- src/libextra/treemap.rs | 2 +- src/librust/rust.rs | 2 +- src/librustc/driver/driver.rs | 3 +- src/librustc/front/config.rs | 10 +++++-- src/librustc/lib/llvm.rs | 2 +- src/librustc/metadata/cstore.rs | 2 +- src/librustc/metadata/decoder.rs | 12 ++++---- src/librustc/middle/borrowck/mod.rs | 10 ++++--- src/librustc/middle/const_eval.rs | 4 +-- src/librustc/middle/lang_items.rs | 2 +- src/librustc/middle/liveness.rs | 12 ++++---- src/librustc/middle/region.rs | 5 ++-- src/librustc/middle/resolve.rs | 2 +- src/librustc/middle/trans/base.rs | 6 ++-- src/librustc/middle/trans/cabi_mips.rs | 2 +- src/librustc/middle/trans/common.rs | 3 +- src/librustc/middle/trans/context.rs | 2 +- src/librustc/middle/trans/meth.rs | 4 +-- src/librustc/middle/ty.rs | 7 +++-- src/librustc/middle/typeck/astconv.rs | 4 +-- src/librustc/middle/typeck/check/_match.rs | 20 ++++++------- src/librustc/middle/typeck/check/mod.rs | 17 ++++++----- .../middle/typeck/check/regionmanip.rs | 8 +++--- src/librustc/middle/typeck/collect.rs | 10 +++---- src/librustc/middle/typeck/infer/mod.rs | 13 +++++---- src/librustc/rustc.rs | 11 ++++---- src/librustdoc/config.rs | 10 +++---- src/librustdoc/tystr_pass.rs | 4 +-- src/librusti/rusti.rs | 2 +- src/libstd/hashmap.rs | 4 +-- src/libstd/iterator.rs | 8 +++--- src/libstd/option.rs | 28 +++++++++---------- src/libstd/os.rs | 4 +-- src/libstd/result.rs | 8 +++--- src/libstd/rt/comm.rs | 4 +-- src/libstd/rt/kill.rs | 4 +-- src/libstd/rt/sched.rs | 4 +-- src/libstd/str.rs | 2 +- src/libstd/task/spawn.rs | 6 ++-- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/attr.rs | 2 +- src/libsyntax/diagnostic.rs | 2 +- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/fold.rs | 22 +++++++-------- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- 53 files changed, 176 insertions(+), 175 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 4e4261e8b2bb..4262aba9a859 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -109,8 +109,8 @@ pub fn parse_config(args: ~[~str]) -> config { compile_lib_path: getopts::opt_str(matches, "compile-lib-path"), run_lib_path: getopts::opt_str(matches, "run-lib-path"), rustc_path: opt_path(matches, "rustc-path"), - clang_path: getopts::opt_maybe_str(matches, "clang-path").map(|s| Path(*s)), - llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map(|s| Path(*s)), + clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)), + llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)), src_base: opt_path(matches, "src-base"), build_base: opt_path(matches, "build-base"), aux_base: opt_path(matches, "aux-base"), @@ -123,14 +123,14 @@ pub fn parse_config(args: ~[~str]) -> config { } else { None }, - logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)), - save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map(|s| Path(*s)), + logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)), + save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)), ratchet_metrics: - getopts::opt_maybe_str(matches, "ratchet-metrics").map(|s| Path(*s)), + getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)), ratchet_noise_percent: getopts::opt_maybe_str(matches, - "ratchet-noise-percent").map(|s| - f64::from_str(*s).unwrap()), + "ratchet-noise-percent").map_move(|s| + f64::from_str(s).unwrap()), runtool: getopts::opt_maybe_str(matches, "runtool"), rustcflags: getopts::opt_maybe_str(matches, "rustcflags"), jit: getopts::opt_present(matches, "jit"), diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 75487a44f260..b0839a55795b 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -164,7 +164,7 @@ impl DList { /// Remove the first Node and return it, or None if the list is empty #[inline] fn pop_front_node(&mut self) -> Option<~Node> { - do self.list_head.take().map_consume |mut front_node| { + do self.list_head.take().map_move |mut front_node| { self.length -= 1; match front_node.next.take() { Some(node) => self.list_head = link_with_prev(node, Rawlink::none()), @@ -190,7 +190,7 @@ impl DList { /// Remove the last Node and return it, or None if the list is empty #[inline] fn pop_back_node(&mut self) -> Option<~Node> { - do self.list_tail.resolve().map_consume_default(None) |tail| { + do self.list_tail.resolve().map_move_default(None) |tail| { self.length -= 1; self.list_tail = tail.prev; match tail.prev.resolve() { @@ -237,7 +237,7 @@ impl Deque for DList { /// /// O(1) fn pop_front(&mut self) -> Option { - self.pop_front_node().map_consume(|~Node{value, _}| value) + self.pop_front_node().map_move(|~Node{value, _}| value) } /// Add an element last in the list @@ -251,7 +251,7 @@ impl Deque for DList { /// /// O(1) fn pop_back(&mut self) -> Option { - self.pop_back_node().map_consume(|~Node{value, _}| value) + self.pop_back_node().map_move(|~Node{value, _}| value) } } @@ -267,7 +267,7 @@ impl DList { /// If the list is empty, do nothing. #[inline] pub fn rotate_forward(&mut self) { - do self.pop_back_node().map_consume |tail| { + do self.pop_back_node().map_move |tail| { self.push_front_node(tail) }; } @@ -277,7 +277,7 @@ impl DList { /// If the list is empty, do nothing. #[inline] pub fn rotate_backward(&mut self) { - do self.pop_front_node().map_consume |head| { + do self.pop_front_node().map_move |head| { self.push_back_node(head) }; } @@ -463,7 +463,7 @@ impl<'self, A> DoubleEndedIterator<&'self A> for DListIterator<'self, A> { if self.nelem == 0 { return None; } - do self.tail.resolve().map_consume |prev| { + do self.tail.resolve().map_move |prev| { self.nelem -= 1; self.tail = prev.prev; &prev.value @@ -477,7 +477,7 @@ impl<'self, A> Iterator<&'self mut A> for MutDListIterator<'self, A> { if self.nelem == 0 { return None; } - do self.head.resolve().map_consume |next| { + do self.head.resolve().map_move |next| { self.nelem -= 1; self.head = match next.next { Some(ref mut node) => Rawlink::some(&mut **node), @@ -499,7 +499,7 @@ impl<'self, A> DoubleEndedIterator<&'self mut A> for MutDListIterator<'self, A> if self.nelem == 0 { return None; } - do self.tail.resolve().map_consume |prev| { + do self.tail.resolve().map_move |prev| { self.nelem -= 1; self.tail = prev.prev; &mut prev.value @@ -553,7 +553,7 @@ impl<'self, A> ListInsertion for MutDListIterator<'self, A> { if self.nelem == 0 { return None } - self.head.resolve().map_consume(|head| &mut head.value) + self.head.resolve().map_move(|head| &mut head.value) } } diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 890f5e40e970..c3737d44e385 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -548,7 +548,7 @@ impl BigUint { pub fn new(v: ~[BigDigit]) -> BigUint { // omit trailing zeros - let new_len = v.rposition(|n| *n != 0).map_default(0, |p| *p + 1); + let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1); if new_len == v.len() { return BigUint { data: v }; } let mut v = v; @@ -1145,7 +1145,7 @@ impl BigInt { start = 1; } return BigUint::parse_bytes(buf.slice(start, buf.len()), radix) - .map_consume(|bu| BigInt::from_biguint(sign, bu)); + .map_move(|bu| BigInt::from_biguint(sign, bu)); } pub fn to_uint(&self) -> uint { diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index 3f62317eb890..e5116f19afa5 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -203,7 +203,7 @@ impl SmallIntMap { { let values = replace(&mut self.v, ~[]); values.consume_iter().enumerate().filter_map(|(i, v)| { - v.map_consume(|v| (i, v)) + v.map_move(|v| (i, v)) }) } } diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 1cfb4f4afa62..2173eb838e5e 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -127,7 +127,7 @@ impl Terminal { let inf = ti.unwrap(); let nc = if inf.strings.find_equiv(&("setaf")).is_some() && inf.strings.find_equiv(&("setab")).is_some() { - inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n) + inf.numbers.find_equiv(&("colors")).map_move_default(0, |&n| n) } else { 0 }; return Ok(Terminal {out: out, ti: inf, num_colors: nc}); @@ -220,7 +220,7 @@ impl Terminal { cap = self.ti.strings.find_equiv(&("op")); } } - let s = do cap.map_consume_default(Err(~"can't find terminfo capability `sgr0`")) |op| { + let s = do cap.map_move_default(Err(~"can't find terminfo capability `sgr0`")) |op| { expand(*op, [], &mut Variables::new()) }; if s.is_ok() { diff --git a/src/libextra/test.rs b/src/libextra/test.rs index e87be1462267..761cb1bd76f9 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -238,20 +238,20 @@ pub fn parse_opts(args: &[~str]) -> OptRes { let run_ignored = getopts::opt_present(&matches, "ignored"); let logfile = getopts::opt_maybe_str(&matches, "logfile"); - let logfile = logfile.map(|s| Path(*s)); + let logfile = logfile.map_move(|s| Path(s)); let run_benchmarks = getopts::opt_present(&matches, "bench"); let run_tests = ! run_benchmarks || getopts::opt_present(&matches, "test"); let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics"); - let ratchet_metrics = ratchet_metrics.map(|s| Path(*s)); + let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s)); let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent"); - let ratchet_noise_percent = ratchet_noise_percent.map(|s| f64::from_str(*s).unwrap()); + let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| f64::from_str(s).unwrap()); let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics"); - let save_metrics = save_metrics.map(|s| Path(*s)); + let save_metrics = save_metrics.map_move(|s| Path(s)); let test_opts = TestOpts { filter: filter, diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 487ad050e786..ab7d47255dac 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -394,7 +394,7 @@ impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> { /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. #[inline] fn next(&mut self) -> Option<&'self T> { - do self.iter.next().map |&(value, _)| { value } + do self.iter.next().map_move |(value, _)| { value } } } diff --git a/src/librust/rust.rs b/src/librust/rust.rs index 1ac8146bb589..010486cdf855 100644 --- a/src/librust/rust.rs +++ b/src/librust/rust.rs @@ -130,7 +130,7 @@ fn rustc_help() { fn find_cmd(command_string: &str) -> Option { do COMMANDS.iter().find_ |command| { command.cmd == command_string - }.map_consume(|x| *x) + }.map_move(|x| *x) } fn cmd_help(args: &[~str]) -> ValidUsage { diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 2c642d54253b..61ab826e9ee5 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -669,8 +669,7 @@ pub fn build_session_options(binary: @str, } else if opt_present(matches, "emit-llvm") { link::output_type_bitcode } else { link::output_type_exe }; - let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot"); - let sysroot_opt = sysroot_opt.map(|m| @Path(*m)); + let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m)); let target_opt = getopts::opt_maybe_str(matches, "target"); let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature"); let save_temps = getopts::opt_present(matches, "save-temps"); diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index d8b59d579c81..d6584846655d 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -61,7 +61,9 @@ fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod { filter_item(cx, *a).chain(|x| fld.fold_item(x)) }.collect(); let filtered_view_items = do m.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + do filter_view_item(cx, a).map_move |x| { + fld.fold_view_item(x) + } }.collect(); ast::_mod { view_items: filtered_view_items, @@ -83,7 +85,9 @@ fn fold_foreign_mod( ) -> ast::foreign_mod { let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect(); let filtered_view_items = do nm.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + do filter_view_item(cx, a).map_move |x| { + fld.fold_view_item(x) + } }.collect(); ast::foreign_mod { sort: nm.sort, @@ -138,7 +142,7 @@ fn fold_block( filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt)) }.collect(); let filtered_view_items = do b.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + filter_view_item(cx, a).map(|x| fld.fold_view_item(*x)) }.collect(); ast::Block { view_items: filtered_view_items, diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 356cdaf754ee..90db3f8edb0a 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2159,7 +2159,7 @@ impl TypeNames { } pub fn find_type(&self, s: &str) -> Option { - self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x)) + self.named_types.find_equiv(&s).map_move(|x| Type::from_ref(*x)) } // We have a depth count, because we seem to make infinite types. diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 33623a40cfb2..a5f541412ded 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -133,7 +133,7 @@ pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore, pub fn find_extern_mod_stmt_cnum(cstore: &CStore, emod_id: ast::NodeId) -> Option { - cstore.extern_mod_crate_map.find(&emod_id).map_consume(|x| *x) + cstore.extern_mod_crate_map.find(&emod_id).map_move(|x| *x) } #[deriving(Clone)] diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c3097d1aa665..8d3571260184 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -198,8 +198,8 @@ fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id { } fn get_provided_source(d: ebml::Doc, cdata: cmd) -> Option { - do reader::maybe_get_doc(d, tag_item_method_provided_source).map |doc| { - translate_def_id(cdata, reader::with_doc_data(*doc, parse_def_id)) + do reader::maybe_get_doc(d, tag_item_method_provided_source).map_move |doc| { + translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id)) } } @@ -265,10 +265,10 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, } fn item_ty_region_param(item: ebml::Doc) -> Option { - reader::maybe_get_doc(item, tag_region_param).map(|doc| { - let mut decoder = reader::Decoder(*doc); + do reader::maybe_get_doc(item, tag_region_param).map_move |doc| { + let mut decoder = reader::Decoder(doc); Decodable::decode(&mut decoder) - }) + } } fn item_ty_param_count(item: ebml::Doc) -> uint { @@ -415,7 +415,7 @@ pub fn get_impl_trait(cdata: cmd, tcx: ty::ctxt) -> Option<@ty::TraitRef> { let item_doc = lookup_item(id, cdata.data); - do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |&tp| { + do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map_move |tp| { @doc_trait_ref(tp, tcx, cdata) } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3db90ed5d749..d410021063c2 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -286,13 +286,15 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { } mc::cat_deref(cmt_base, _, _) => { - opt_loan_path(cmt_base).map( - |&lp| @LpExtend(lp, cmt.mutbl, LpDeref)) + do opt_loan_path(cmt_base).map_move |lp| { + @LpExtend(lp, cmt.mutbl, LpDeref) + } } mc::cat_interior(cmt_base, ik) => { - opt_loan_path(cmt_base).map( - |&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik))) + do opt_loan_path(cmt_base).map_move |lp| { + @LpExtend(lp, cmt.mutbl, LpInterior(ik)) + } } mc::cat_downcast(cmt_base) | diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 77e81709a03d..3b56764f2fca 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -493,9 +493,9 @@ pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option Option { - compare_lit_exprs(tcx, a, b).map(|&val| val == 0) + compare_lit_exprs(tcx, a, b).map_move(|val| val == 0) } pub fn lit_eq(a: &lit, b: &lit) -> Option { - compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map(|&val| val == 0) + compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map_move(|val| val == 0) } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 0dfad430f4d6..42bc435a58a9 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -393,7 +393,7 @@ impl<'self> LanguageItemCollector<'self> { return; // Didn't match. } - let item_index = self.item_refs.find(&value).map(|x| **x); + let item_index = self.item_refs.find(&value).map_move(|x| *x); // prevent borrow checker from considering ^~~~~~~~~~~ // self to be borrowed (annoying) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 0387f344796e..b39616304906 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -607,9 +607,9 @@ impl Liveness { match expr.node { expr_path(_) => { let def = self.tcx.def_map.get_copy(&expr.id); - moves::moved_variable_node_id_from_def(def).map( - |rdef| self.variable(*rdef, expr.span) - ) + do moves::moved_variable_node_id_from_def(def).map_move |rdef| { + self.variable(rdef, expr.span) + } } _ => None } @@ -623,9 +623,9 @@ impl Liveness { -> Option { match self.tcx.def_map.find(&node_id) { Some(&def) => { - moves::moved_variable_node_id_from_def(def).map( - |rdef| self.variable(*rdef, span) - ) + do moves::moved_variable_node_id_from_def(def).map_move |rdef| { + self.variable(rdef, span) + } } None => { self.tcx.sess.span_bug( diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2d121209118f..4da22be4428e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -111,7 +111,7 @@ impl RegionMaps { pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - self.scope_map.find(&id).map(|&x| *x) + self.scope_map.find(&id).map_move(|x| *x) } pub fn encl_scope(&self, id: ast::NodeId) -> ast::NodeId { @@ -579,8 +579,7 @@ impl DetermineRpCtxt { /// the new variance is joined with the old variance. pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) { assert!(id != 0); - let old_variance = self.region_paramd_items.find(&id). - map_consume(|x| *x); + let old_variance = self.region_paramd_items.find(&id).map_move(|x| *x); let joined_variance = match old_variance { None => variance, Some(v) => join_variance(v, variance) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 625dcd5d9cc4..da0ba1558c9b 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3358,7 +3358,7 @@ impl Resolver { // item, it's ok match def { def_ty_param(did, _) - if self.def_map.find(&did.node).map_consume(|x| *x) + if self.def_map.find(&did.node).map_move(|x| *x) == Some(def_typaram_binder(item_id)) => { // ok } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 2efed8f36d7f..dcaa141cbc28 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -92,7 +92,7 @@ pub use middle::trans::context::task_llcx; static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key; pub fn with_insn_ctxt(blk: &fn(&[&'static str])) { - let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k)); + let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k)); if opt.is_some() { blk(*opt.unwrap()); } @@ -108,7 +108,7 @@ pub struct _InsnCtxt { _x: () } impl Drop for _InsnCtxt { fn drop(&self) { do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { + do c.map_move |ctx| { let mut ctx = (*ctx).clone(); ctx.pop(); @ctx @@ -120,7 +120,7 @@ impl Drop for _InsnCtxt { pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: %s", s); do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { + do c.map_move |ctx| { let mut ctx = (*ctx).clone(); ctx.push(s); @ctx diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index fe1c288d1773..f5fb68a70578 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -159,7 +159,7 @@ fn struct_ty(ty: Type, padding: Option, coerce: bool) -> Type { let size = ty_size(ty) * 8; - let mut fields = padding.map_default(~[], |p| ~[*p]); + let mut fields = padding.map_move_default(~[], |p| ~[p]); if coerce { fields = vec::append(fields, coerce_to_int(size)); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f303e7b82759..240696ec1908 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1010,8 +1010,7 @@ pub fn node_id_type_params(bcx: @mut Block, id: ast::NodeId) -> ~[ty::t] { pub fn node_vtables(bcx: @mut Block, id: ast::NodeId) -> Option { let raw_vtables = bcx.ccx().maps.vtable_map.find(&id); - raw_vtables.map( - |&vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts)) + raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts)) } pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res) diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 802163583d6a..56ba1ae1694b 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -241,7 +241,7 @@ impl Drop for CrateContext { static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key; pub fn task_llcx() -> ContextRef { - let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k)); + let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k)); *opt.expect("task-local LLVMContextRef wasn't ever set!") } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index b67d88c07e1e..9be01ef1db94 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -162,7 +162,7 @@ pub fn trans_method_callee(bcx: @mut Block, data: Method(MethodData { llfn: callee_fn.llfn, llself: val, - temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), + temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v), self_ty: node_id_type(bcx, this.id), self_mode: mentry.self_mode, }) @@ -339,7 +339,7 @@ pub fn trans_monomorphized_callee(bcx: @mut Block, data: Method(MethodData { llfn: llfn_val, llself: llself_val, - temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), + temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v), self_ty: node_id_type(bcx, base.id), self_mode: mentry.self_mode, }) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3f4db29ef7e7..849c35cdd2c0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3557,7 +3557,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool { pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option { - cx.provided_method_sources.find(&id).map(|x| **x) + cx.provided_method_sources.find(&id).map_move(|x| *x) } pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@Method] { @@ -3710,8 +3710,9 @@ fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option { Some(&ast_map::node_item(item, _)) => { match item.node { ast::item_struct(struct_def, _) => { - struct_def.ctor_id.map(|ctor_id| - ast_util::local_def(*ctor_id)) + do struct_def.ctor_id.map_move |ctor_id| { + ast_util::local_def(ctor_id) + } } _ => cx.sess.bug("called struct_ctor_id on non-struct") } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 53853e4fe1a7..750bd506f3e4 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -621,9 +621,9 @@ fn ty_of_method_or_bare_fn( in_binding_rscope(rscope, RegionParamNames(bound_lifetime_names.clone())); - let opt_transformed_self_ty = opt_self_info.map(|&self_info| { + let opt_transformed_self_ty = do opt_self_info.map_move |self_info| { transform_self_ty(this, &rb, self_info) - }); + }; let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None)); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7caed3906015..d8a9350e695d 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, None => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"a structure pattern", None); fcx.write_error(pat.id); @@ -201,9 +201,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, _ => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"an enum or structure pattern", None); fcx.write_error(pat.id); @@ -535,9 +535,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { _ => ty::terr_mismatch }; fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); fcx.write_error(pat.id); } } @@ -584,9 +584,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.infcx().type_error_message_str_with_expected( pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"a vector pattern", None); @@ -642,9 +642,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str_with_expected( span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ea8a11fc7b38..4a4834c9a03b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -364,8 +364,8 @@ pub fn check_fn(ccx: @mut CrateCtxt, |br| ty::re_free(ty::FreeRegion {scope_id: body.id, bound_region: br})); let opt_self_info = - opt_self_info.map( - |si| SelfInfo {self_ty: opt_self_ty.unwrap(), ..*si}); + opt_self_info.map_move( + |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si}); (isr, opt_self_info, fn_sig) }; @@ -536,7 +536,7 @@ pub fn check_method(ccx: @mut CrateCtxt, { let method_def_id = local_def(method.id); let method_ty = ty::method(ccx.tcx, method_def_id); - let opt_self_info = method_ty.transformed_self_ty.map(|&ty| { + let opt_self_info = method_ty.transformed_self_ty.map_move(|ty| { SelfInfo {self_ty: ty, self_id: method.self_id, span: method.explicit_self.span} @@ -557,7 +557,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, for p in fields.iter() { let (id, sp) = *p; - let orig_sp = field_names.find(&id).map_consume(|x| *x); + let orig_sp = field_names.find(&id).map_move(|x| *x); match orig_sp { Some(orig_sp) => { tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration", @@ -601,7 +601,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { check_bare_fn(ccx, decl, body, it.id, None); } ast::item_impl(_, _, _, ref ms) => { - let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = ccx.tcx.region_paramd_items.find(&it.id).map_move(|x| *x); debug!("item_impl %s with id %d rp %?", ccx.tcx.sess.str_of(it.ident), it.id, rp); for m in ms.iter() { @@ -1877,8 +1877,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, for field in ast_fields.iter() { let mut expected_field_type = ty::mk_err(); - let pair = class_field_map.find(&field.ident). - map_consume(|x| *x); + let pair = class_field_map.find(&field.ident).map_move(|x| *x); match pair { None => { tcx.sess.span_err( @@ -1962,7 +1961,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, if class_id.crate == ast::LOCAL_CRATE { region_parameterized = tcx.region_paramd_items.find(&class_id.node). - map_consume(|x| *x); + map_move(|x| *x); match tcx.items.find(&class_id.node) { Some(&ast_map::node_item(@ast::item { node: ast::item_struct(_, ref generics), @@ -2050,7 +2049,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let raw_type; if enum_id.crate == ast::LOCAL_CRATE { region_parameterized = - tcx.region_paramd_items.find(&enum_id.node).map_consume(|x| *x); + tcx.region_paramd_items.find(&enum_id.node).map_move(|x| *x); match tcx.items.find(&enum_id.node) { Some(&ast_map::node_item(@ast::item { node: ast::item_enum(_, ref generics), diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 2685055bd84a..cb4827104b62 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -40,9 +40,9 @@ pub fn replace_bound_regions_in_fn_sig( debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \ all_tys=%?)", - opt_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), + opt_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)), ppaux::fn_sig_to_str(tcx, fn_sig), - all_tys.map(|&t| ppaux::ty_to_str(tcx, t))); + all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); let _i = indenter(); let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { @@ -52,12 +52,12 @@ pub fn replace_bound_regions_in_fn_sig( let new_fn_sig = ty::fold_sig(fn_sig, |t| { replace_bound_regions(tcx, isr, t) }); - let new_self_ty = opt_self_ty.map(|&t| replace_bound_regions(tcx, isr, t)); + let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, *t)); debug!("result of replace_bound_regions_in_fn_sig: \ new_self_ty=%?, \ fn_sig=%s", - new_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), + new_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)), ppaux::fn_sig_to_str(tcx, &new_fn_sig)); return (isr, new_self_ty, new_fn_sig); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 2bef2c08bb22..907a076b1a1e 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -198,7 +198,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); + let region_paramd = tcx.region_paramd_items.find(&trait_id).map_move(|x| *x); match tcx.items.get_copy(&trait_id) { ast_map::node_item(@ast::item { node: ast::item_trait(ref generics, _, ref ms), @@ -817,7 +817,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); debug!("convert: item %s with id %d rp %?", tcx.sess.str_of(it.ident), it.id, rp); match it.node { @@ -1020,7 +1020,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { Some(&def) => return def, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); match it.node { ast::item_trait(ref generics, _, _) => { let self_ty = ty::mk_self(tcx, def_id); @@ -1049,7 +1049,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) Some(&tpt) => return tpt, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); match it.node { ast::item_static(ref t, _, _) => { let typ = ccx.to_ty(&empty_rscope, t); @@ -1086,7 +1086,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) None => { } } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); let tpt = { diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 854ee835cc7d..7fa7daf61490 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -716,12 +716,13 @@ impl InferCtxt { err: Option<&ty::type_err>) { debug!("hi! expected_ty = %?, actual_ty = %s", expected_ty, actual_ty); - let error_str = err.map_default(~"", |t_err| - fmt!(" (%s)", - ty::type_err_to_str(self.tcx, *t_err))); - let resolved_expected = expected_ty.map(|&e_ty| - { self.resolve_type_vars_if_possible(e_ty) }); - if !resolved_expected.map_default(false, |&e| { ty::type_is_error(e) }) { + let error_str = do err.map_move_default(~"") |t_err| { + fmt!(" (%s)", ty::type_err_to_str(self.tcx, t_err)) + }; + let resolved_expected = do expected_ty.map_move |e_ty| { + self.resolve_type_vars_if_possible(e_ty) + }; + if !resolved_expected.map_move_default(false, |e| { ty::type_is_error(e) }) { match resolved_expected { None => self.tcx.sess.span_err(sp, fmt!("%s%s", mk_msg(None, actual_ty), error_str)), diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 46414a7a5e23..222433787f0a 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -249,13 +249,12 @@ pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) { let sopts = build_session_options(binary, matches, demitter); let sess = build_session(sopts, demitter); - let odir = getopts::opt_maybe_str(matches, "out-dir"); - let odir = odir.map(|o| Path(*o)); - let ofile = getopts::opt_maybe_str(matches, "o"); - let ofile = ofile.map(|o| Path(*o)); + let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o)); + let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o)); let cfg = build_configuration(sess, binary, &input); - let pretty = getopts::opt_default(matches, "pretty", "normal").map( - |a| parse_pretty(sess, *a)); + let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| { + parse_pretty(sess, a) + }; match pretty { Some::(ppm) => { pretty_print_input(sess, cfg, &input, ppm); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index d387bbea592d..3598eb7c0fb9 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -140,7 +140,7 @@ fn config_from_opts( let result = result::Ok(config); let result = do result.chain |config| { let output_dir = getopts::opt_maybe_str(matches, opt_output_dir()); - let output_dir = output_dir.map(|s| Path(*s)); + let output_dir = output_dir.map_move(|s| Path(s)); result::Ok(Config { output_dir: output_dir.unwrap_or_default(config.output_dir.clone()), .. config @@ -148,8 +148,8 @@ fn config_from_opts( }; let result = do result.chain |config| { let output_format = getopts::opt_maybe_str(matches, opt_output_format()); - do output_format.map_default(result::Ok(config.clone())) |output_format| { - do parse_output_format(*output_format).chain |output_format| { + do output_format.map_move_default(result::Ok(config.clone())) |output_format| { + do parse_output_format(output_format).chain |output_format| { result::Ok(Config { output_format: output_format, .. config.clone() @@ -160,8 +160,8 @@ fn config_from_opts( let result = do result.chain |config| { let output_style = getopts::opt_maybe_str(matches, opt_output_style()); - do output_style.map_default(result::Ok(config.clone())) |output_style| { - do parse_output_style(*output_style).chain |output_style| { + do output_style.map_move_default(result::Ok(config.clone())) |output_style| { + do parse_output_style(output_style).chain |output_style| { result::Ok(Config { output_style: output_style, .. config.clone() diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 684b4e9d198d..0d7ec34243da 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -260,9 +260,9 @@ fn fold_impl( }, _) => { let bounds = pprust::generics_to_str(generics, extract::interner()); let bounds = if bounds.is_empty() { None } else { Some(bounds) }; - let trait_types = opt_trait_type.map_default(~[], |p| { + let trait_types = do opt_trait_type.map_default(~[]) |p| { ~[pprust::path_to_str(&p.path, extract::interner())] - }); + }; (bounds, trait_types, Some(pprust::ty_to_str( diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 86290ea65b56..bbcff4e2a359 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -203,7 +203,7 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str], } } } - result = do blk.expr.map_consume |e| { + result = do blk.expr.map_move |e| { do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); } }; } diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index fbc471c0ae05..3484a5e7d6e8 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -238,7 +238,7 @@ impl HashMap { let len_buckets = self.buckets.len(); let bucket = self.buckets[idx].take(); - let value = do bucket.map_consume |bucket| { + let value = do bucket.map_move |bucket| { bucket.value }; @@ -479,7 +479,7 @@ impl HashMap { impl HashMap { /// Like `find`, but returns a copy of the value. pub fn find_copy(&self, k: &K) -> Option { - self.find(k).map_consume(|v| (*v).clone()) + self.find(k).map_move(|v| (*v).clone()) } /// Like `get`, but returns a copy of the value. diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index e86f4d7a85e6..47e8eac27f01 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -674,7 +674,7 @@ impl> IteratorUtil for T { Some((y, y_val)) } } - }).map_consume(|(x, _)| x) + }).map_move(|(x, _)| x) } #[inline] @@ -689,7 +689,7 @@ impl> IteratorUtil for T { Some((y, y_val)) } } - }).map_consume(|(x, _)| x) + }).map_move(|(x, _)| x) } } @@ -1383,7 +1383,7 @@ impl<'self, A, T: Iterator, B, U: Iterator> Iterator for return Some(x) } } - match self.iter.next().map_consume(|x| (self.f)(x)) { + match self.iter.next().map_move(|x| (self.f)(x)) { None => return self.backiter.chain_mut_ref(|it| it.next()), next => self.frontiter = next, } @@ -1415,7 +1415,7 @@ impl<'self, y => return y } } - match self.iter.next_back().map_consume(|x| (self.f)(x)) { + match self.iter.next_back().map_move(|x| (self.f)(x)) { None => return self.frontiter.chain_mut_ref(|it| it.next_back()), next => self.backiter = next, } diff --git a/src/libstd/option.rs b/src/libstd/option.rs index ea1bddcdb4b9..e43ff65da5e5 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -208,6 +208,12 @@ impl Option { match *self { Some(ref mut x) => Some(f(x)), None => None } } + /// Applies a function to the contained value or returns a default + #[inline] + pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { + match *self { None => def, Some(ref t) => f(t) } + } + /// Maps a `Some` value from one type to another by a mutable reference, /// or returns a default value. #[inline] @@ -218,21 +224,15 @@ impl Option { /// As `map`, but consumes the option and gives `f` ownership to avoid /// copying. #[inline] - pub fn map_consume(self, f: &fn(v: T) -> U) -> Option { - match self { None => None, Some(v) => Some(f(v)) } - } - - /// Applies a function to the contained value or returns a default - #[inline] - pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { - match *self { None => def, Some(ref t) => f(t) } + pub fn map_move(self, f: &fn(T) -> U) -> Option { + match self { Some(x) => Some(f(x)), None => None } } /// As `map_default`, but consumes the option and gives `f` /// ownership to avoid copying. #[inline] - pub fn map_consume_default(self, def: U, f: &fn(v: T) -> U) -> U { - match self { None => def, Some(v) => f(v) } + pub fn map_move_default(self, def: U, f: &fn(T) -> U) -> U { + match self { None => def, Some(t) => f(t) } } /// Take the value out of the option, leaving a `None` in its place. @@ -241,18 +241,18 @@ impl Option { util::replace(self, None) } - /// As `map_consume`, but swaps a None into the original option rather + /// As `map_move`, but swaps a None into the original option rather /// than consuming it by-value. #[inline] pub fn take_map(&mut self, blk: &fn(T) -> U) -> Option { - self.take().map_consume(blk) + self.take().map_move(blk) } - /// As `map_consume_default`, but swaps a None into the original option + /// As `map_move_default`, but swaps a None into the original option /// rather than consuming it by-value. #[inline] pub fn take_map_default (&mut self, def: U, blk: &fn(T) -> U) -> U { - self.take().map_consume_default(def, blk) + self.take().map_move_default(def, blk) } /// Apply a function to the contained value or do nothing. diff --git a/src/libstd/os.rs b/src/libstd/os.rs index b0e1f35b4a01..f246a61a4d58 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -498,9 +498,7 @@ pub fn self_exe_path() -> Option { } } - do load_self().map |pth| { - Path(*pth).dir_path() - } + load_self().map_move(|path| Path(path).dir_path()) } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index e62ae3885eb9..3e429c6116d4 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -407,14 +407,14 @@ mod tests { #[test] pub fn test_impl_map_move() { - assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Ok(~"ab")); - assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Err(~"a")); + assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + "b"), Ok(~"ab")); + assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + "b"), Err(~"a")); } #[test] pub fn test_impl_map_err_move() { - assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Ok(~"a")); - assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Err(~"ab")); + assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Ok(~"a")); + assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Err(~"ab")); } #[test] diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index a060059f5fc9..0cf223f30291 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -159,7 +159,7 @@ impl ChanOne { // Port is blocked. Wake it up. let recvr = BlockedTask::cast_from_uint(task_as_state); if do_resched { - do recvr.wake().map_consume |woken_task| { + do recvr.wake().map_move |woken_task| { Scheduler::run_task(woken_task); }; } else { @@ -381,7 +381,7 @@ impl Drop for ChanOne { // The port is blocked waiting for a message we will never send. Wake it. assert!((*this.packet()).payload.is_none()); let recvr = BlockedTask::cast_from_uint(task_as_state); - do recvr.wake().map_consume |woken_task| { + do recvr.wake().map_move |woken_task| { Scheduler::run_task(woken_task); }; } diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 3372c13b8770..d90ad07650d2 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -402,7 +402,7 @@ impl KillHandle { || { // Prefer to check tombstones that were there first, // being "more fair" at the expense of tail-recursion. - others.take().map_consume_default(true, |f| f()) && { + others.take().map_move_default(true, |f| f()) && { let mut inner = this.take().unwrap(); (!inner.any_child_failed) && inner.child_tombstones.take_map_default(true, |f| f()) @@ -424,7 +424,7 @@ impl KillHandle { let others = Cell::new(other_tombstones); // :( || { // Prefer fairness to tail-recursion, as in above case. - others.take().map_consume_default(true, |f| f()) && + others.take().map_move_default(true, |f| f()) && f.take()() } } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 1a75f2569b59..c2c12c6e3c07 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -325,7 +325,7 @@ impl Scheduler { /// As enqueue_task, but with the possibility for the blocked task to /// already have been killed. pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) { - do blocked_task.wake().map_consume |task| { + do blocked_task.wake().map_move |task| { self.enqueue_task(task); }; } @@ -533,7 +533,7 @@ impl Scheduler { sched.enqueue_blocked_task(last_task); } }; - opt.map_consume(Local::put); + opt.map_move(Local::put); } // The primary function for changing contexts. In the current diff --git a/src/libstd/str.rs b/src/libstd/str.rs index b4057b85cbfe..a327b687a75d 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1849,7 +1849,7 @@ impl<'self> StrSlice<'self> for &'self str { } else { self.matches_index_iter(needle) .next() - .map_consume(|(start, _end)| start) + .map_move(|(start, _end)| start) } } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 527b20b0e902..7486a78837c5 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -500,7 +500,7 @@ impl RuntimeGlue { OldTask(ptr) => rt::rust_task_kill_other(ptr), NewTask(handle) => { let mut handle = handle; - do handle.kill().map_consume |killed_task| { + do handle.kill().map_move |killed_task| { let killed_task = Cell::new(killed_task); do Local::borrow:: |sched| { sched.enqueue_task(killed_task.take()); @@ -682,7 +682,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { // Child task runs this code. // If child data is 'None', the enlist is vacuously successful. - let enlist_success = do child_data.take().map_consume_default(true) |child_data| { + let enlist_success = do child_data.take().map_move_default(true) |child_data| { let child_data = Cell::new(child_data); // :( do Local::borrow:: |me| { let (child_tg, ancestors, is_main) = child_data.take(); @@ -854,7 +854,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { // Even if the below code fails to kick the child off, we must // send Something on the notify channel. - let notifier = notify_chan.map_consume(|c| AutoNotify(c)); + let notifier = notify_chan.map_move(|c| AutoNotify(c)); if enlist_many(OldTask(child), &child_arc, &mut ancestors) { let group = @@mut Taskgroup(child_arc, ancestors, is_main, notifier); diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 84e6544f7809..ba167fe67148 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -888,7 +888,7 @@ pub fn new_sctable_internal() -> SCTable { // fetch the SCTable from TLS, create one if it doesn't yet exist. pub fn get_sctable() -> @mut SCTable { static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key; - match local_data::get(sctable_key, |k| k.map(|&k| *k)) { + match local_data::get(sctable_key, |k| k.map_move(|k| *k)) { None => { let new_table = @@mut new_sctable_internal(); local_data::set(sctable_key,new_table); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d39cb2f507ca..9edd41152f7f 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -83,7 +83,7 @@ impl AttrMetaMethods for MetaItem { } pub fn name_str_pair(&self) -> Option<(@str, @str)> { - self.value_str().map_consume(|s| (self.name(), s)) + self.value_str().map_move(|s| (self.name(), s)) } } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 8b5014366413..2b6cb91a5df1 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -192,7 +192,7 @@ fn print_maybe_styled(msg: &str, color: term::attr::Attr) { let stderr = io::stderr(); if stderr.get_type() == io::Screen { - let t = match local_data::get(tls_terminal, |v| v.map_consume(|&k|k)) { + let t = match local_data::get(tls_terminal, |v| v.map_move(|k| *k)) { None => { let t = term::Terminal::new(stderr); let tls = @match t { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ed5ca3e402a..efaf6b8e001f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -479,7 +479,7 @@ impl MapChain{ ConsMapChain(ref map,_) => map }; // strip one layer of indirection off the pointer. - map.find(key).map(|r| {**r}) + map.find(key).map_move(|r| {*r}) } // insert the binding into the top-level map diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index c373a3894884..d81dca005b0a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -591,7 +591,7 @@ impl AstBuilder for @ExtCtxt { fn expr_if(&self, span: span, cond: @ast::expr, then: @ast::expr, els: Option<@ast::expr>) -> @ast::expr { - let els = els.map(|x| self.expr_block(self.block_expr(*x))); + let els = els.map_move(|x| self.expr_block(self.block_expr(x))); self.expr(span, ast::expr_if(cond, self.block_expr(then), els)) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7ffed13940e8..0a5bc0007203 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -417,7 +417,7 @@ fn noop_fold_stmt(s: &stmt_, fld: @ast_fold) -> Option { fn noop_fold_arm(a: &arm, fld: @ast_fold) -> arm { arm { pats: a.pats.map(|x| fld.fold_pat(*x)), - guard: a.guard.map(|x| fld.fold_expr(*x)), + guard: a.guard.map_move(|x| fld.fold_expr(x)), body: fld.fold_block(&a.body), } } @@ -429,7 +429,7 @@ pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ { pat_ident( binding_mode, fld.fold_path(pth), - sub.map(|x| fld.fold_pat(*x)) + sub.map_move(|x| fld.fold_pat(x)) ) } pat_lit(e) => pat_lit(fld.fold_expr(e)), @@ -459,7 +459,7 @@ pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ { pat_vec(ref before, ref slice, ref after) => { pat_vec( before.map(|x| fld.fold_pat(*x)), - slice.map(|x| fld.fold_pat(*x)), + slice.map_move(|x| fld.fold_pat(x)), after.map(|x| fld.fold_pat(*x)) ) } @@ -551,7 +551,7 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_if( fld.fold_expr(cond), fld.fold_block(tr), - fl.map(|x| fld.fold_expr(*x)) + fl.map_move(|x| fld.fold_expr(x)) ) } expr_while(cond, ref body) => { @@ -565,7 +565,7 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_loop(ref body, opt_ident) => { expr_loop( fld.fold_block(body), - opt_ident.map(|x| fld.fold_ident(*x)) + opt_ident.map_move(|x| fld.fold_ident(x)) ) } expr_match(expr, ref arms) => { @@ -608,13 +608,13 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_path(ref pth) => expr_path(fld.fold_path(pth)), expr_self => expr_self, expr_break(ref opt_ident) => { - expr_break(opt_ident.map(|x| fld.fold_ident(*x))) + expr_break(opt_ident.map_move(|x| fld.fold_ident(x))) } expr_again(ref opt_ident) => { - expr_again(opt_ident.map(|x| fld.fold_ident(*x))) + expr_again(opt_ident.map_move(|x| fld.fold_ident(x))) } expr_ret(ref e) => { - expr_ret(e.map(|x| fld.fold_expr(*x))) + expr_ret(e.map_move(|x| fld.fold_expr(x))) } expr_log(lv, e) => { expr_log( @@ -634,7 +634,7 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ { expr_struct( fld.fold_path(path), fields.map(|x| fold_field(*x)), - maybe_expr.map(|x| fld.fold_expr(*x)) + maybe_expr.map_move(|x| fld.fold_expr(x)) ) }, expr_paren(ex) => expr_paren(fld.fold_expr(ex)) @@ -731,7 +731,7 @@ fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { fold_variant_arg(/*bad*/ (*x).clone()) }) } - struct_variant_kind(struct_def) => { + struct_variant_kind(ref struct_def) => { kind = struct_variant_kind(@ast::struct_def { fields: struct_def.fields.iter() .transform(|f| fld.fold_struct_field(*f)).collect(), @@ -776,7 +776,7 @@ fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local { is_mutbl: l.is_mutbl, ty: fld.fold_ty(&l.ty), pat: fld.fold_pat(l.pat), - init: l.init.map(|e| fld.fold_expr(*e)), + init: l.init.map_move(|e| fld.fold_expr(e)), id: fld.new_id(l.id), span: fld.new_span(l.span), } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a0932729930e..4902c4587ac3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1313,7 +1313,7 @@ impl Parser { // If the path might have bounds on it, they should be parsed before // the parameters, e.g. module::TraitName:B1+B2 - before_tps.map_consume(|callback| callback()); + before_tps.map_move(|callback| callback()); // Parse the (obsolete) trailing region parameter, if any, which will // be written "foo/&x" diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 39668e5c8b29..fd491c1e890a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -486,7 +486,7 @@ fn mk_fresh_ident_interner() -> @ident_interner { pub fn get_ident_interner() -> @ident_interner { static key: local_data::Key<@@::parse::token::ident_interner> = &local_data::Key; - match local_data::get(key, |k| k.map(|&k| *k)) { + match local_data::get(key, |k| k.map_move(|k| *k)) { Some(interner) => *interner, None => { let interner = mk_fresh_ident_interner(); From 19e17f54a02e484f1ab4fd809caa0aaf3f3d14bc Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 4 Aug 2013 16:30:51 -0700 Subject: [PATCH 04/48] std: removed option.take_map{,_default} --- src/libstd/option.rs | 14 -------------- src/libstd/rt/kill.rs | 10 +++++----- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/libstd/option.rs b/src/libstd/option.rs index e43ff65da5e5..66b30d8dd031 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -241,20 +241,6 @@ impl Option { util::replace(self, None) } - /// As `map_move`, but swaps a None into the original option rather - /// than consuming it by-value. - #[inline] - pub fn take_map(&mut self, blk: &fn(T) -> U) -> Option { - self.take().map_move(blk) - } - - /// As `map_move_default`, but swaps a None into the original option - /// rather than consuming it by-value. - #[inline] - pub fn take_map_default (&mut self, def: U, blk: &fn(T) -> U) -> U { - self.take().map_move_default(def, blk) - } - /// Apply a function to the contained value or do nothing. /// Returns true if the contained value was mutated. pub fn mutate(&mut self, f: &fn(T) -> T) -> bool { diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index d90ad07650d2..789c7531eca8 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -405,7 +405,7 @@ impl KillHandle { others.take().map_move_default(true, |f| f()) && { let mut inner = this.take().unwrap(); (!inner.any_child_failed) && - inner.child_tombstones.take_map_default(true, |f| f()) + inner.child_tombstones.take().map_move_default(true, |f| f()) } } } @@ -493,7 +493,7 @@ impl Death { { use util; util::ignore(group); } // Step 1. Decide if we need to collect child failures synchronously. - do self.on_exit.take_map |on_exit| { + do self.on_exit.take().map_move |on_exit| { if success { // We succeeded, but our children might not. Need to wait for them. let mut inner = self.kill_handle.take_unwrap().unwrap(); @@ -501,7 +501,7 @@ impl Death { success = false; } else { // Lockless access to tombstones protected by unwrap barrier. - success = inner.child_tombstones.take_map_default(true, |f| f()); + success = inner.child_tombstones.take().map_move_default(true, |f| f()); } } on_exit(success); @@ -510,12 +510,12 @@ impl Death { // Step 2. Possibly alert possibly-watching parent to failure status. // Note that as soon as parent_handle goes out of scope, the parent // can successfully unwrap its handle and collect our reported status. - do self.watching_parent.take_map |mut parent_handle| { + do self.watching_parent.take().map_move |mut parent_handle| { if success { // Our handle might be None if we had an exit callback, and // already unwrapped it. But 'success' being true means no // child failed, so there's nothing to do (see below case). - do self.kill_handle.take_map |own_handle| { + do self.kill_handle.take().map_move |own_handle| { own_handle.reparent_children_to(&mut parent_handle); }; } else { From 17c12bbd1b2fdfc958f12527538acb787cc2d89a Mon Sep 17 00:00:00 2001 From: Mihnea Dobrescu-Balaur Date: Wed, 7 Aug 2013 09:46:09 -0700 Subject: [PATCH 05/48] Add frequency count to extra::stat. #8281 --- src/libextra/stats.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 68d5af43688a..9238034cba33 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -10,6 +10,7 @@ use sort; use std::cmp; +use std::hashmap; use std::io; use std::num; @@ -352,6 +353,16 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { w.write_str(histr); } +/// Returns a HashMap with the number of occurences of every element in the +/// sequence that the iterator exposes. +pub fn freq_count, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap { + let mut map = hashmap::HashMap::new::(); + for elem in iter { + map.insert_or_update_with(elem, 1, |_, count| *count += 1); + } + map +} + // Test vectors generated from R, using the script src/etc/stat-test-vectors.r. #[cfg(test)] From eb6143257dd5a6848be4e073fc756ae705156241 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 12:14:03 -0700 Subject: [PATCH 06/48] std::rt: 2MB stacks again --- src/libstd/rt/task.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index e732ef67b5b1..2da44c2f3320 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -326,7 +326,7 @@ impl Drop for Task { impl Coroutine { pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - static MIN_STACK_SIZE: uint = 3000000; // XXX: Too much stack + static MIN_STACK_SIZE: uint = 2000000; // XXX: Too much stack let start = Coroutine::build_start_wrapper(start); let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); From f82da818a7ea94f4bbb1a1ea15073b51805fd582 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 12:43:33 -0700 Subject: [PATCH 07/48] std::rt: Pull RUST_MIN_STACK from the environment --- src/libstd/rt/env.rs | 28 ++++++++++++++++++++++++++++ src/libstd/rt/mod.rs | 1 + src/libstd/rt/task.rs | 6 +++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 1d7ff1731490..6e671742fb6f 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -10,7 +10,12 @@ //! Runtime environment settings +use from_str::FromStr; use libc::{size_t, c_char, c_int}; +use option::{Some, None}; +use os; + +// OLD RT stuff pub struct Environment { /// The number of threads to use by default @@ -47,3 +52,26 @@ pub fn get() -> &Environment { extern { fn rust_get_rt_env() -> &Environment; } + +// NEW RT stuff + +// Note that these are all accessed without any synchronization. +// They are expected to be initialized once then left alone. + +static mut MIN_STACK: uint = 2000000; + +pub fn init() { + unsafe { + match os::getenv("RUST_MIN_STACK") { + Some(s) => match FromStr::from_str(s) { + Some(i) => MIN_STACK = i, + None => () + }, + None => () + } + } +} + +pub fn min_stack() -> uint { + unsafe { MIN_STACK } +} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 760ca8a9adad..5b22eace56f8 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -212,6 +212,7 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) { // Need to propagate the unsafety to `start`. unsafe { args::init(argc, argv); + env::init(); logging::init(crate_map); rust_update_gc_metadata(crate_map); } diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 2da44c2f3320..aa6d51a480b2 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -20,6 +20,7 @@ use libc::{c_void, uintptr_t}; use ptr; use prelude::*; use option::{Option, Some, None}; +use rt::env; use rt::kill::Death; use rt::local::Local; use rt::logging::StdErrLogger; @@ -326,10 +327,9 @@ impl Drop for Task { impl Coroutine { pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - static MIN_STACK_SIZE: uint = 2000000; // XXX: Too much stack - + let stack_size = env::min_stack(); let start = Coroutine::build_start_wrapper(start); - let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); + let mut stack = stack_pool.take_segment(stack_size); let initial_context = Context::new(start, &mut stack); Coroutine { current_stack_segment: stack, From ae1ed4fd78273502153083f1514a1fcd7c929886 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 13:10:08 -0700 Subject: [PATCH 08/48] std: Allow spawners to specify stack size --- src/libstd/rt/local.rs | 11 ++++++----- src/libstd/rt/mod.rs | 7 +++---- src/libstd/rt/sched.rs | 14 +++++++------- src/libstd/rt/task.rs | 37 +++++++++++++++++++++++-------------- src/libstd/rt/test.rs | 15 +++++++-------- src/libstd/task/mod.rs | 12 ++++++++---- src/libstd/task/spawn.rs | 14 +++++++------- 7 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 131507196b1f..7154066e7b74 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -126,6 +126,7 @@ impl Local for IoFactoryObject { #[cfg(test)] mod test { + use option::None; use unstable::run_in_bare_thread; use rt::test::*; use super::*; @@ -137,7 +138,7 @@ mod test { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); @@ -149,11 +150,11 @@ mod test { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); @@ -166,7 +167,7 @@ mod test { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); unsafe { @@ -182,7 +183,7 @@ mod test { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let res = do Local::borrow:: |_task| { diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 5b22eace56f8..147c75e5c41e 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -331,8 +331,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // In the case where we do not use a main_thread scheduler we // run the main task in one of our threads. - let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, - main.take()); + let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take()); main_task.death.on_exit = Some(on_exit.take()); let main_task_cell = Cell::new(main_task); @@ -352,7 +351,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let sched_cell = Cell::new(sched); let thread = do Thread::start { let mut sched = sched_cell.take(); - let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || { + let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || { rtdebug!("boostraping a non-primary scheduler"); }; sched.bootstrap(bootstrap_task); @@ -369,7 +368,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let mut main_sched = main_sched.unwrap(); let home = Sched(main_sched.make_handle()); - let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, + let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None, home, main.take()); main_task.death.on_exit = Some(on_exit.take()); rtdebug!("boostrapping main_task"); diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index c2c12c6e3c07..990e1a4a3de9 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -833,7 +833,7 @@ mod test { let mut sched = ~new_test_uv_sched(); let sched_handle = sched.make_handle(); - let mut task = ~do Task::new_root_homed(&mut sched.stack_pool, + let mut task = ~do Task::new_root_homed(&mut sched.stack_pool, None, Sched(sched_handle)) { unsafe { *task_ran_ptr = true }; assert!(Task::on_appropriate_sched()); @@ -893,21 +893,21 @@ mod test { // 3) task not homed, sched requeues // 4) task not home, send home - let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool, + let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None, Sched(t1_handle)) || { rtassert!(Task::on_appropriate_sched()); }; rtdebug!("task1 id: **%u**", borrow::to_uint(task1)); - let task2 = ~do Task::new_root(&mut normal_sched.stack_pool) { + let task2 = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtassert!(Task::on_appropriate_sched()); }; - let task3 = ~do Task::new_root(&mut normal_sched.stack_pool) { + let task3 = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtassert!(Task::on_appropriate_sched()); }; - let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool, + let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None, Sched(t4_handle)) { rtassert!(Task::on_appropriate_sched()); }; @@ -923,7 +923,7 @@ mod test { let port = Cell::new(port); let chan = Cell::new(chan); - let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool) { + let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtdebug!("*about to submit task2*"); Scheduler::run_task(task2.take()); rtdebug!("*about to submit task4*"); @@ -938,7 +938,7 @@ mod test { rtdebug!("normal task: %u", borrow::to_uint(normal_task)); - let special_task = ~do Task::new_root(&mut special_sched.stack_pool) { + let special_task = ~do Task::new_root(&mut special_sched.stack_pool, None) { rtdebug!("*about to submit task1*"); Scheduler::run_task(task1.take()); rtdebug!("*about to submit task3*"); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index aa6d51a480b2..364439a45260 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -86,12 +86,13 @@ impl Task { // A helper to build a new task using the dynamically found // scheduler and task. Only works in GreenTask context. - pub fn build_homed_child(f: ~fn(), home: SchedHome) -> ~Task { + pub fn build_homed_child(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); do Local::borrow:: |running_task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~running_task.new_child_homed(&mut sched.stack_pool, + stack_size, home.take(), f.take()); running_task.sched = Some(sched); @@ -99,25 +100,26 @@ impl Task { } } - pub fn build_child(f: ~fn()) -> ~Task { - Task::build_homed_child(f, AnySched) + pub fn build_child(stack_size: Option, f: ~fn()) -> ~Task { + Task::build_homed_child(stack_size, f, AnySched) } - pub fn build_homed_root(f: ~fn(), home: SchedHome) -> ~Task { + pub fn build_homed_root(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); do Local::borrow:: |running_task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~Task::new_root_homed(&mut sched.stack_pool, - home.take(), - f.take()); + stack_size, + home.take(), + f.take()); running_task.sched = Some(sched); new_task } } - pub fn build_root(f: ~fn()) -> ~Task { - Task::build_homed_root(f, AnySched) + pub fn build_root(stack_size: Option, f: ~fn()) -> ~Task { + Task::build_homed_root(stack_size, f, AnySched) } pub fn new_sched_task() -> Task { @@ -138,17 +140,20 @@ impl Task { } pub fn new_root(stack_pool: &mut StackPool, + stack_size: Option, start: ~fn()) -> Task { - Task::new_root_homed(stack_pool, AnySched, start) + Task::new_root_homed(stack_pool, stack_size, AnySched, start) } pub fn new_child(&mut self, stack_pool: &mut StackPool, + stack_size: Option, start: ~fn()) -> Task { - self.new_child_homed(stack_pool, AnySched, start) + self.new_child_homed(stack_pool, stack_size, AnySched, start) } pub fn new_root_homed(stack_pool: &mut StackPool, + stack_size: Option, home: SchedHome, start: ~fn()) -> Task { Task { @@ -161,7 +166,7 @@ impl Task { death: Death::new(), destroyed: false, name: None, - coroutine: Some(Coroutine::new(stack_pool, start)), + coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(~home)) } @@ -169,6 +174,7 @@ impl Task { pub fn new_child_homed(&mut self, stack_pool: &mut StackPool, + stack_size: Option, home: SchedHome, start: ~fn()) -> Task { Task { @@ -182,7 +188,7 @@ impl Task { death: self.death.new_child(), destroyed: false, name: None, - coroutine: Some(Coroutine::new(stack_pool, start)), + coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(~home)) } @@ -326,8 +332,11 @@ impl Drop for Task { impl Coroutine { - pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - let stack_size = env::min_stack(); + pub fn new(stack_pool: &mut StackPool, stack_size: Option, start: ~fn()) -> Coroutine { + let stack_size = match stack_size { + Some(size) => size, + None => env::min_stack() + }; let start = Coroutine::build_start_wrapper(start); let mut stack = stack_pool.take_segment(stack_size); let initial_context = Context::new(start, &mut stack); diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 8b5215ae9694..792ea5eb33f5 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -57,7 +57,7 @@ pub fn run_in_newsched_task_core(f: ~fn()) { exit_handle.take().send(Shutdown); rtassert!(exit_status); }; - let mut task = ~Task::new_root(&mut sched.stack_pool, f); + let mut task = ~Task::new_root(&mut sched.stack_pool, None, f); task.death.on_exit = Some(on_exit); sched.bootstrap(task); @@ -190,8 +190,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { rtassert!(exit_status); }; - let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, - f.take()); + let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, f.take()); main_task.death.on_exit = Some(on_exit); let mut threads = ~[]; @@ -209,7 +208,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { while !scheds.is_empty() { let mut sched = scheds.pop(); - let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || { + let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || { rtdebug!("bootstrapping non-primary scheduler"); }; let bootstrap_task_cell = Cell::new(bootstrap_task); @@ -232,12 +231,12 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { /// Test tasks will abort on failure instead of unwinding pub fn spawntask(f: ~fn()) { - Scheduler::run_task(Task::build_child(f)); + Scheduler::run_task(Task::build_child(None, f)); } /// Create a new task and run it right now. Aborts on failure pub fn spawntask_later(f: ~fn()) { - Scheduler::run_task_later(Task::build_child(f)); + Scheduler::run_task_later(Task::build_child(None, f)); } pub fn spawntask_random(f: ~fn()) { @@ -259,7 +258,7 @@ pub fn spawntask_try(f: ~fn()) -> Result<(),()> { let chan = Cell::new(chan); let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status); - let mut new_task = Task::build_root(f); + let mut new_task = Task::build_root(None, f); new_task.death.on_exit = Some(on_exit); Scheduler::run_task(new_task); @@ -285,7 +284,7 @@ pub fn spawntask_thread(f: ~fn()) -> Thread { pub fn with_test_task(blk: ~fn(~Task) -> ~Task) { do run_in_bare_thread { let mut sched = ~new_test_uv_sched(); - let task = blk(~Task::new_root(&mut sched.stack_pool, ||{})); + let task = blk(~Task::new_root(&mut sched.stack_pool, None, ||{})); cleanup_task(task); } } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 225a4b8cfd29..4b5543b81865 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -142,7 +142,8 @@ pub struct TaskOpts { indestructible: bool, notify_chan: Option>, name: Option<~str>, - sched: SchedOpts + sched: SchedOpts, + stack_size: Option } /** @@ -197,7 +198,8 @@ impl TaskBuilder { indestructible: self.opts.indestructible, notify_chan: notify_chan, name: name, - sched: self.opts.sched + sched: self.opts.sched, + stack_size: self.opts.stack_size }, gen_body: gen_body, can_not_copy: None, @@ -351,7 +353,8 @@ impl TaskBuilder { indestructible: x.opts.indestructible, notify_chan: notify_chan, name: name, - sched: x.opts.sched + sched: x.opts.sched, + stack_size: x.opts.stack_size }; let f = match gen_body { Some(gen) => { @@ -422,7 +425,8 @@ pub fn default_task_opts() -> TaskOpts { name: None, sched: SchedOpts { mode: DefaultScheduler, - } + }, + stack_size: None } } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 7486a78837c5..2d0a2d98e9fc 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -713,9 +713,9 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let mut task = unsafe { if opts.sched.mode != SingleThreaded { if opts.watched { - Task::build_child(child_wrapper) + Task::build_child(opts.stack_size, child_wrapper) } else { - Task::build_root(child_wrapper) + Task::build_root(opts.stack_size, child_wrapper) } } else { // Creating a 1:1 task:thread ... @@ -736,16 +736,16 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { // Pin the new task to the new scheduler let new_task = if opts.watched { - Task::build_homed_child(child_wrapper, Sched(new_sched_handle)) + Task::build_homed_child(opts.stack_size, child_wrapper, Sched(new_sched_handle)) } else { - Task::build_homed_root(child_wrapper, Sched(new_sched_handle)) + Task::build_homed_root(opts.stack_size, child_wrapper, Sched(new_sched_handle)) }; // Create a task that will later be used to join with the new scheduler // thread when it is ready to terminate let (thread_port, thread_chan) = oneshot(); let thread_port_cell = Cell::new(thread_port); - let join_task = do Task::build_child() { + let join_task = do Task::build_child(None) { rtdebug!("running join task"); let thread_port = thread_port_cell.take(); let thread: Thread = thread_port.recv(); @@ -762,8 +762,8 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let mut orig_sched_handle = orig_sched_handle_cell.take(); let join_task = join_task_cell.take(); - let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || { - rtdebug!("bootstrapping a 1:1 scheduler"); + let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool, None) || { + rtdebug!("boostrapping a 1:1 scheduler"); }; new_sched.bootstrap(bootstrap_task); From 0929eb4ac8bfe00c5b3430fac3a07dcf64b51d02 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 13:10:34 -0700 Subject: [PATCH 09/48] rustc: Use 4MB stacks. Needed for unoptimized builds apparently. --- src/librustc/rustc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 222433787f0a..1dfca0ba0e89 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -298,10 +298,18 @@ bug and need to present an error. */ pub fn monitor(f: ~fn(diagnostic::Emitter)) { use std::comm::*; + + // XXX: This is a hack for newsched since it doesn't support split stacks. + // rustc needs a lot of stack! + static STACK_SIZE: uint = 4000000; + let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_capture = ch.clone(); - match do task::try || { + let mut task_builder = task::task(); + task_builder.supervised(); + task_builder.opts.stack_size = Some(STACK_SIZE); + match do task_builder.try { let ch = ch_capture.clone(); let ch_capture = ch.clone(); // The 'diagnostics emitter'. Every error, warning, etc. should From 84d17445f836ff731cd2e8a7e575a17e419b3d5b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 18:15:07 -0700 Subject: [PATCH 10/48] rustpkg: Disable test_uninstall Seems to not work --- src/librustpkg/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 828be5dce127..9fea86621297 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -998,6 +998,7 @@ fn test_rustpkg_test() { } #[test] +#[ignore(reason = "test not yet implemented")] fn test_uninstall() { let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); let _output = command_line_test([~"info", ~"foo"], &workspace); From 44403f77d1792d05a064d10d9fbc18b9badf92f1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 21:11:25 -0700 Subject: [PATCH 11/48] test: xfail a bunch of tests that are incorrectly reading os::args()[1] --- src/test/bench/shootout-fannkuch-redux.rs | 2 ++ src/test/bench/shootout-fasta-redux.rs | 2 ++ src/test/bench/shootout-mandelbrot.rs | 2 ++ src/test/bench/shootout-nbody.rs | 2 ++ src/test/bench/shootout-spectralnorm.rs | 2 ++ 5 files changed, 10 insertions(+) diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 9d4d31b89692..48372c6d03b2 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; use std::vec::MutableVector; diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 44b1a28c12b3..1f1ce86404b6 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::cast::transmute; use std::from_str::FromStr; use std::libc::{FILE, STDOUT_FILENO, c_int, fdopen, fputc, fputs, fwrite, size_t}; diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index cf43f470e717..72007d2b50a9 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::cast::transmute; use std::from_str::FromStr; use std::libc::{STDOUT_FILENO, c_int, fdopen, fputc}; diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 6a9c5ea89e4f..0f43d5027a91 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index ecf54bf16473..d7f5e5781e0e 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; use std::vec; From b240524e5af72ba7f1b20d6e8640250c7c070a07 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 21:15:02 -0700 Subject: [PATCH 12/48] test: Fix deadlock in task-perf-linked-failure --- src/test/bench/task-perf-linked-failure.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/bench/task-perf-linked-failure.rs b/src/test/bench/task-perf-linked-failure.rs index 15808427f4a8..7788005775f7 100644 --- a/src/test/bench/task-perf-linked-failure.rs +++ b/src/test/bench/task-perf-linked-failure.rs @@ -34,7 +34,10 @@ fn grandchild_group(num_tasks: uint) { for _ in range(0, num_tasks) { let ch = ch.clone(); - do task::spawn { // linked + let mut t = task::task(); + t.linked(); + t.unwatched(); + do t.spawn { // linked ch.send(()); let (p, _c) = stream::<()>(); p.recv(); // block forever From ad8010fdf20da90cf3ca06a278a6b9b9bda048fd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 22:39:48 -0700 Subject: [PATCH 13/48] xfail debug-info/option-like-enum Don't understand why this broke. --- src/test/debug-info/option-like-enum.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/debug-info/option-like-enum.rs b/src/test/debug-info/option-like-enum.rs index 6d3b157d63e8..3bf3507faba7 100644 --- a/src/test/debug-info/option-like-enum.rs +++ b/src/test/debug-info/option-like-enum.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test broken in newrt? // compile-flags:-Z extra-debug-info // debugger:break zzz From b735e6b1041125f3237ff1f807455b2017f13e42 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Aug 2013 13:25:09 -0700 Subject: [PATCH 14/48] doc: Fix deadlocks in tutorial due to yield bustage --- doc/tutorial-tasks.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b5677a261c45..d9e4b9b399d2 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -492,7 +492,8 @@ either task fails, it kills the other one. ~~~ # use std::task; -# fn sleep_forever() { loop { task::yield() } } +# use std::comm::oneshot; +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } # do task::try { do spawn { do spawn { @@ -513,9 +514,10 @@ before returning. Hence: ~~~ # use std::comm::{stream, Chan, Port}; +# use std::comm::oneshot; # use std::task::{spawn, try}; # use std::task; -# fn sleep_forever() { loop { task::yield() } } +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } # do task::try { let (receiver, sender): (Port, Chan) = stream(); do spawn { // Bidirectionally linked @@ -543,7 +545,8 @@ an intermediate generation has already exited: ~~~ # use std::task; -# fn sleep_forever() { loop { task::yield() } } +# use std::comm::oneshot; +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } # fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } } # do task::try:: { do task::spawn_supervised { From ce95b01014391f29a655d165d9e6d31449ceb835 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Aug 2013 14:32:30 -0700 Subject: [PATCH 15/48] Disable linked failure tests The implementation currently contains a race that leads to segfaults. --- doc/tutorial-tasks.md | 16 ++++++++-------- src/libextra/arc.rs | 1 + src/libextra/sync.rs | 2 ++ src/libstd/rt/kill.rs | 6 ++++++ src/libstd/task/mod.rs | 19 +++++++++++++++++++ src/test/run-fail/extern-fail.rs | 1 + src/test/run-fail/linked-failure.rs | 1 + src/test/run-fail/linked-failure2.rs | 1 + src/test/run-fail/linked-failure3.rs | 1 + src/test/run-fail/linked-failure4.rs | 1 + src/test/run-fail/spawnfail.rs | 1 + src/test/run-fail/task-comm-recv-block.rs | 1 + src/test/run-pass/issue-3168.rs | 1 + src/test/run-pass/lots-a-fail.rs | 1 + src/test/run-pass/send-iloop.rs | 1 + src/test/run-pass/task-killjoin-rsrc.rs | 1 + src/test/run-pass/task-killjoin.rs | 1 + 17 files changed, 48 insertions(+), 8 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index d9e4b9b399d2..d190c332e663 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -424,7 +424,7 @@ there is no way to "catch" the exception. All tasks are, by default, _linked_ to each other. That means that the fates of all tasks are intertwined: if one fails, so do all the others. -~~~ +~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::task; # fn do_some_work() { loop { task::yield() } } @@ -447,7 +447,7 @@ pattern-match on a result to check whether it's an `Ok` result with an `int` field (representing a successful result) or an `Err` result (representing termination with an error). -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # fn some_condition() -> bool { false } # fn calculate_result() -> int { 0 } @@ -490,7 +490,7 @@ proceed). Hence, you will need different _linked failure modes_. By default, task failure is _bidirectionally linked_, which means that if either task fails, it kills the other one. -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # use std::comm::oneshot; # fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } @@ -512,7 +512,7 @@ function `task::try`, which we saw previously, uses `spawn_supervised` internally, with additional logic to wait for the child task to finish before returning. Hence: -~~~ +~~~{.xfail-test .linked-failure} # use std::comm::{stream, Chan, Port}; # use std::comm::oneshot; # use std::task::{spawn, try}; @@ -543,7 +543,7 @@ also fail. Supervised task failure propagates across multiple generations even if an intermediate generation has already exited: -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # use std::comm::oneshot; # fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } @@ -563,7 +563,7 @@ fail!(); // Will kill grandchild even if child has already exited Finally, tasks can be configured to not propagate failure to each other at all, using `task::spawn_unlinked` for _isolated failure_. -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # fn random() -> uint { 100 } # fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } } @@ -591,7 +591,7 @@ that repeatedly receives a `uint` message, converts it to a string, and sends the string in response. The child terminates when it receives `0`. Here is the function that implements the child task: -~~~~ +~~~{.xfail-test .linked-failure} # use extra::comm::DuplexStream; # use std::uint; fn stringifier(channel: &DuplexStream<~str, uint>) { @@ -614,7 +614,7 @@ response itself is simply the stringified version of the received value, Here is the code for the parent task: -~~~~ +~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::uint; # use extra::comm::DuplexStream; diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index cb4468f48ecb..17f4cbbd1527 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -611,6 +611,7 @@ mod tests { } } } + #[test] #[should_fail] #[ignore(cfg(windows))] fn test_arc_condvar_poison() { unsafe { diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 63e371899a9b..4172c715adb9 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -935,6 +935,7 @@ mod tests { // child task must have finished by the time try returns do m.lock { } } + #[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_mutex_killed_cond() { // Getting killed during cond wait must not corrupt the mutex while @@ -961,6 +962,7 @@ mod tests { assert!(!woken); } } + #[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_mutex_killed_broadcast() { use std::unstable::finally::Finally; diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 789c7531eca8..fbc9d1d2445a 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -614,6 +614,7 @@ mod test { // Test cases don't care about the spare killed flag. fn make_kill_handle() -> KillHandle { let (h,_) = KillHandle::new(); h } + #[ignore(reason = "linked failure")] #[test] fn no_tombstone_success() { do run_in_newsched_task { @@ -819,6 +820,7 @@ mod test { } } + #[ignore(reason = "linked failure")] #[test] fn block_and_get_killed() { do with_test_task |mut task| { @@ -830,6 +832,7 @@ mod test { } } + #[ignore(reason = "linked failure")] #[test] fn block_already_killed() { do with_test_task |mut task| { @@ -839,6 +842,7 @@ mod test { } } + #[ignore(reason = "linked failure")] #[test] fn block_unkillably_and_get_killed() { do with_test_task |mut task| { @@ -856,6 +860,7 @@ mod test { } } + #[ignore(reason = "linked failure")] #[test] fn block_on_pipe() { // Tests the "killable" path of casting to/from uint. @@ -869,6 +874,7 @@ mod test { } } + #[ignore(reason = "linked failure")] #[test] fn block_unkillably_on_pipe() { // Tests the "indestructible" path of casting to/from uint. diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 4b5543b81865..2e0c9c1d1ad1 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -659,6 +659,7 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_kill_unkillable_task() { use rt::test::*; @@ -679,6 +680,7 @@ fn test_kill_unkillable_task() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_kill_rekillable_task() { use rt::test::*; @@ -720,6 +722,7 @@ fn test_cant_dup_task_builder() { #[cfg(test)] fn block_forever() { let (po, _ch) = stream::<()>(); po.recv(); } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port use rt::test::run_in_newsched_task; @@ -738,6 +741,7 @@ fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port po.recv(); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails use rt::test::run_in_newsched_task; @@ -745,6 +749,7 @@ fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails do spawn_unlinked { fail!(); } } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails use rt::test::run_in_newsched_task; @@ -754,6 +759,7 @@ fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails do 16.times { task::yield(); } } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_sup_fail_down() { use rt::test::run_in_newsched_task; @@ -766,6 +772,7 @@ fn test_spawn_unlinked_sup_fail_down() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_up() { // child fails; parent fails use rt::test::run_in_newsched_task; @@ -786,6 +793,7 @@ fn test_spawn_linked_sup_fail_up() { // child fails; parent fails assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_down() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -802,6 +810,7 @@ fn test_spawn_linked_sup_fail_down() { // parent fails; child fails assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails use rt::test::run_in_newsched_task; @@ -814,6 +823,7 @@ fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -826,6 +836,7 @@ fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -844,6 +855,7 @@ fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails // A couple bonus linked failure tests - testing for failure propagation even // when the middle task exits successfully early before kill signals are sent. +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_grandchild() { use rt::test::run_in_newsched_task; @@ -860,6 +872,7 @@ fn test_spawn_failure_propagate_grandchild() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_secondborn() { use rt::test::run_in_newsched_task; @@ -876,6 +889,7 @@ fn test_spawn_failure_propagate_secondborn() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_nephew_or_niece() { use rt::test::run_in_newsched_task; @@ -892,6 +906,7 @@ fn test_spawn_failure_propagate_nephew_or_niece() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_propagate_sibling() { use rt::test::run_in_newsched_task; @@ -1195,6 +1210,7 @@ fn test_avoid_copying_the_body_unlinked() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] #[should_fail] @@ -1230,6 +1246,7 @@ fn test_unkillable() { po.recv(); } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] #[should_fail] @@ -1296,6 +1313,7 @@ fn test_simple_newsched_spawn() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_watched() { use rt::test::run_in_newsched_task; @@ -1318,6 +1336,7 @@ fn test_spawn_watched() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_indestructible() { use rt::test::run_in_newsched_task; diff --git a/src/test/run-fail/extern-fail.rs b/src/test/run-fail/extern-fail.rs index a281e9863649..a65db3ee5154 100644 --- a/src/test/run-fail/extern-fail.rs +++ b/src/test/run-fail/extern-fail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:explicit failure // Testing that runtime failure doesn't cause callbacks to abort abnormally. // Instead the failure will be delivered after the callbacks return. diff --git a/src/test/run-fail/linked-failure.rs b/src/test/run-fail/linked-failure.rs index 41a9d7ddcea1..52dfb8aef13d 100644 --- a/src/test/run-fail/linked-failure.rs +++ b/src/test/run-fail/linked-failure.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:1 == 2 extern mod extra; diff --git a/src/test/run-fail/linked-failure2.rs b/src/test/run-fail/linked-failure2.rs index 0269e3959868..d4049f6753ee 100644 --- a/src/test/run-fail/linked-failure2.rs +++ b/src/test/run-fail/linked-failure2.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:fail use std::comm; diff --git a/src/test/run-fail/linked-failure3.rs b/src/test/run-fail/linked-failure3.rs index 1203f74322fe..f40eae20bc0b 100644 --- a/src/test/run-fail/linked-failure3.rs +++ b/src/test/run-fail/linked-failure3.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:fail use std::comm; diff --git a/src/test/run-fail/linked-failure4.rs b/src/test/run-fail/linked-failure4.rs index 766b43f211f4..94e41f1ae682 100644 --- a/src/test/run-fail/linked-failure4.rs +++ b/src/test/run-fail/linked-failure4.rs @@ -9,6 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:1 == 2 use std::comm; diff --git a/src/test/run-fail/spawnfail.rs b/src/test/run-fail/spawnfail.rs index de085a6f3add..12dab8e25b78 100644 --- a/src/test/run-fail/spawnfail.rs +++ b/src/test/run-fail/spawnfail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // error-pattern:explicit extern mod extra; diff --git a/src/test/run-fail/task-comm-recv-block.rs b/src/test/run-fail/task-comm-recv-block.rs index 8302b96ca3ef..bd51ce38ec0e 100644 --- a/src/test/run-fail/task-comm-recv-block.rs +++ b/src/test/run-fail/task-comm-recv-block.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:goodfail use std::comm; diff --git a/src/test/run-pass/issue-3168.rs b/src/test/run-pass/issue-3168.rs index 609849bffb48..f4e2a9f36a07 100644 --- a/src/test/run-pass/issue-3168.rs +++ b/src/test/run-pass/issue-3168.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-fast // xfail-win32 #7999 diff --git a/src/test/run-pass/lots-a-fail.rs b/src/test/run-pass/lots-a-fail.rs index cec0a7a756c9..13296131236a 100644 --- a/src/test/run-pass/lots-a-fail.rs +++ b/src/test/run-pass/lots-a-fail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 leaks extern mod extra; diff --git a/src/test/run-pass/send-iloop.rs b/src/test/run-pass/send-iloop.rs index e27f35d1851d..a647e5849a8e 100644 --- a/src/test/run-pass/send-iloop.rs +++ b/src/test/run-pass/send-iloop.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 extern mod extra; diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index c811e548f3fb..b8a1aa433a30 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // A port of task-killjoin to use a class with a dtor to manage diff --git a/src/test/run-pass/task-killjoin.rs b/src/test/run-pass/task-killjoin.rs index c94e00251d28..5382ac776713 100644 --- a/src/test/run-pass/task-killjoin.rs +++ b/src/test/run-pass/task-killjoin.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // Create a task that is supervised by another task, join the supervised task From 52a37b63f4acab98c48159accccd9d6e885aeec1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Aug 2013 21:20:03 -0700 Subject: [PATCH 16/48] rusti: Disable tests Segfaulted on one of the bots. Maybe out of stack? --- src/librusti/rusti.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 6b61b099d23b..bb863df33481 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -579,16 +579,19 @@ mod tests { } fn run_program(_: &str) {} + #[ignore] #[test] fn super_basic() { run_program(""); } + #[ignore] #[test] fn regression_5937() { run_program("use std::hashmap;"); } + #[ignore] #[test] fn regression_5784() { run_program("let a = 3;"); @@ -604,6 +607,7 @@ mod tests { "); } + #[ignore] #[test] fn inferred_integers_usable() { run_program("let a = 2;\n()\n"); @@ -614,6 +618,7 @@ mod tests { "); } + #[ignore] #[test] fn local_variables_allow_shadowing() { run_program(" @@ -623,6 +628,7 @@ mod tests { "); } + #[ignore] #[test] fn string_usable() { run_program(" @@ -634,6 +640,7 @@ mod tests { "); } + #[ignore] #[test] fn vectors_usable() { run_program(" @@ -646,6 +653,7 @@ mod tests { "); } + #[ignore] #[test] fn structs_usable() { run_program(" @@ -655,6 +663,7 @@ mod tests { "); } + #[ignore] #[test] fn mutable_variables_work() { run_program(" @@ -667,6 +676,7 @@ mod tests { "); } + #[ignore] #[test] fn functions_saved() { run_program(" @@ -677,6 +687,7 @@ mod tests { "); } + #[ignore] #[test] fn modules_saved() { run_program(" @@ -685,6 +696,7 @@ mod tests { "); } + #[ignore] #[test] fn multiple_functions() { run_program(" @@ -694,6 +706,7 @@ mod tests { "); } + #[ignore] #[test] fn multiple_items_same_name() { run_program(" @@ -706,6 +719,7 @@ mod tests { "); } + #[ignore] #[test] fn simultaneous_definition_and_expression() { run_program(" @@ -713,6 +727,7 @@ mod tests { "); } + #[ignore] #[test] fn exit_quits() { let mut r = repl(); From 85aaa44bec2a87f8df290d4f9b3f7350de50d067 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 5 Aug 2013 00:47:04 -0700 Subject: [PATCH 17/48] Turn on the new runtime --- src/libstd/unstable/lang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index e0c4950b38ea..98c0fe254b69 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -135,7 +135,7 @@ pub fn start(main: *u8, argc: int, argv: **c_char, use os; unsafe { - let use_old_rt = os::getenv("RUST_NEWRT").is_none(); + let use_old_rt = os::getenv("RUST_OLDRT").is_some(); if use_old_rt { return rust_start(main as *c_void, argc as c_int, argv, crate_map as *c_void) as int; From ffb670ffcd69ed8e7cd13a7f06375ede752349e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 29 Jul 2013 01:12:41 -0700 Subject: [PATCH 18/48] Add initial support for a new formatting syntax The new macro is available under the name ifmt! (only an intermediate name) --- src/libstd/either.rs | 2 +- src/libstd/fmt/mod.rs | 368 ++++++++ src/libstd/fmt/parse.rs | 896 ++++++++++++++++++++ src/libstd/fmt/rt.rs | 62 ++ src/libstd/rt/io/mem.rs | 2 +- src/libstd/std.rs | 3 + src/libsyntax/ext/base.rs | 2 + src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/ext/ifmt.rs | 720 ++++++++++++++++ src/libsyntax/syntax.rs | 1 + src/test/compile-fail/ifmt-bad-arg.rs | 74 ++ src/test/compile-fail/ifmt-bad-plural.rs | 14 + src/test/compile-fail/ifmt-bad-select.rs | 14 + src/test/compile-fail/ifmt-unimpl.rs | 14 + src/test/compile-fail/ifmt-unknown-trait.rs | 14 + src/test/run-pass/ifmt.rs | 71 ++ 16 files changed, 2258 insertions(+), 3 deletions(-) create mode 100644 src/libstd/fmt/mod.rs create mode 100644 src/libstd/fmt/parse.rs create mode 100644 src/libstd/fmt/rt.rs create mode 100644 src/libsyntax/ext/ifmt.rs create mode 100644 src/test/compile-fail/ifmt-bad-arg.rs create mode 100644 src/test/compile-fail/ifmt-bad-plural.rs create mode 100644 src/test/compile-fail/ifmt-bad-select.rs create mode 100644 src/test/compile-fail/ifmt-unimpl.rs create mode 100644 src/test/compile-fail/ifmt-unknown-trait.rs create mode 100644 src/test/run-pass/ifmt.rs diff --git a/src/libstd/either.rs b/src/libstd/either.rs index cfaef550c6fa..bb74d9b3ec48 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -24,7 +24,7 @@ use vec; use vec::{OwnedVector, ImmutableVector}; /// `Either` is a type that represents one of two alternatives -#[deriving(Clone, Eq)] +#[deriving(Clone, Eq, IterBytes)] pub enum Either { Left(L), Right(R) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs new file mode 100644 index 000000000000..2b8807b22917 --- /dev/null +++ b/src/libstd/fmt/mod.rs @@ -0,0 +1,368 @@ +// 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 prelude::*; + +use cast; +use int; +use rt::io::Decorator; +use rt::io::mem::MemWriter; +use rt::io; +use str; +use sys; +use uint; +use util; +use vec; + +pub mod parse; +pub mod rt; + +/// A struct to represent both where to emit formatting strings to and how they +/// should be formatted. A mutable version of this is passed to all formatting +/// traits. +pub struct Formatter<'self> { + /// Flags for formatting (packed version of rt::Flag) + flags: uint, + /// Character used as 'fill' whenever there is alignment + fill: char, + /// Boolean indication of whether the output should be left-aligned + alignleft: bool, + /// Optionally specified integer width that the output should be + width: Option, + /// Optionally specified precision for numeric types + precision: Option, + + /// Output buffer. + buf: &'self mut io::Writer, + + priv curarg: vec::VecIterator<'self, Argument<'self>>, + priv args: &'self [Argument<'self>], +} + +/// This struct represents the generic "argument" which is taken by the Xprintf +/// family of functions. It contains a function to format the given value. At +/// compile time it is ensured that the function and the value have the correct +/// types, and then this struct is used to canonicalize arguments to one type. +pub struct Argument<'self> { + priv formatter: extern "Rust" fn(&util::Void, &mut Formatter), + priv value: &'self util::Void, +} + +#[allow(missing_doc)] +pub trait Bool { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Char { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Signed { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Unsigned { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Octal { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Binary { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait LowerHex { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait UpperHex { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait String { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Poly { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Pointer { fn fmt(&Self, &mut Formatter); } + +/// The sprintf function takes a precompiled format string and a list of +/// arguments, to return the resulting formatted string. +/// +/// This is currently an unsafe function because the types of all arguments +/// aren't verified by immediate callers of this function. This currently does +/// not validate that the correct types of arguments are specified for each +/// format specifier, nor that each argument itself contains the right function +/// for formatting the right type value. Because of this, the function is marked +/// as `unsafe` if this is being called manually. +/// +/// Thankfully the rust compiler provides the macro `ifmt!` which will perform +/// all of this validation at compile-time and provides a safe interface for +/// invoking this function. +/// +/// # Arguments +/// +/// * fmts - the precompiled format string to emit. +/// * args - the list of arguments to the format string. These are only the +/// positional arguments (not named) +/// +/// Note that this function assumes that there are enough arguments for the +/// format string. +pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str { + let output = MemWriter::new(); + { + let mut formatter = Formatter { + flags: 0, + width: None, + precision: None, + // FIXME(#8248): shouldn't need a transmute + buf: cast::transmute(&output as &io::Writer), + alignleft: false, + fill: ' ', + args: args, + curarg: args.iter(), + }; + for piece in fmt.iter() { + formatter.run(piece, None); + } + } + return str::from_bytes_owned(output.inner()); +} + +impl<'self> Formatter<'self> { + fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) { + let setcount = |slot: &mut Option, cnt: &parse::Count| { + match *cnt { + parse::CountIs(n) => { *slot = Some(n); } + parse::CountImplied => { *slot = None; } + parse::CountIsParam(i) => { + let v = self.args[i].value; + unsafe { *slot = Some(*(v as *util::Void as *uint)); } + } + parse::CountIsNextParam => { + let v = self.curarg.next().unwrap().value; + unsafe { *slot = Some(*(v as *util::Void as *uint)); } + } + } + }; + + match *piece { + rt::String(s) => { self.buf.write(s.as_bytes()); } + rt::CurrentArgument(()) => { self.buf.write(cur.unwrap().as_bytes()); } + rt::Argument(ref arg) => { + // Fill in the format parameters into the formatter + self.fill = arg.format.fill; + self.alignleft = arg.format.alignleft; + self.flags = arg.format.flags; + setcount(&mut self.width, &arg.format.width); + setcount(&mut self.precision, &arg.format.precision); + + // Extract the correct argument + let value = match arg.position { + rt::ArgumentNext => { *self.curarg.next().unwrap() } + rt::ArgumentIs(i) => self.args[i], + }; + + // Then actually do some printing + match arg.method { + None => { (value.formatter)(value.value, self); } + Some(ref method) => { self.execute(*method, value); } + } + } + } + } + + fn execute(&mut self, method: &rt::Method, arg: Argument) { + match *method { + // Pluralization is selection upon a numeric value specified as the + // parameter. + rt::Plural(offset, ref selectors, ref default) => { + // This is validated at compile-time to be a pointer to a + // '&uint' value. + let value: &uint = unsafe { cast::transmute(arg.value) }; + let value = *value; + + // First, attempt to match against explicit values without the + // offsetted value + for s in selectors.iter() { + match s.selector { + Right(val) if value == val => { + return self.runplural(value, s.result); + } + _ => {} + } + } + + // Next, offset the value and attempt to match against the + // keyword selectors. + let value = value - match offset { Some(i) => i, None => 0 }; + for s in selectors.iter() { + let run = match s.selector { + Left(parse::Zero) => value == 0, + Left(parse::One) => value == 1, + Left(parse::Two) => value == 2, + + // XXX: Few/Many should have a user-specified boundary + // One possible option would be in the function + // pointer of the 'arg: Argument' struct. + Left(parse::Few) => value < 8, + Left(parse::Many) => value >= 8, + + Right(*) => false + }; + if run { + return self.runplural(value, s.result); + } + } + + self.runplural(value, *default); + } + + // Select is just a matching against the string specified. + rt::Select(ref selectors, ref default) => { + // This is validated at compile-time to be a pointer to a + // string slice, + let value: & &str = unsafe { cast::transmute(arg.value) }; + let value = *value; + + for s in selectors.iter() { + if s.selector == value { + for piece in s.result.iter() { + self.run(piece, Some(value)); + } + return; + } + } + for piece in default.iter() { + self.run(piece, Some(value)); + } + } + } + } + + fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) { + do uint::to_str_bytes(value, 10) |buf| { + let valuestr = str::from_bytes_slice(buf); + for piece in pieces.iter() { + self.run(piece, Some(valuestr)); + } + } + } +} + +/// This is a function which calls are emitted to by the compiler itself to +/// create the Argument structures that are passed into the `sprintf` function. +#[doc(hidden)] +pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter), + t: &'a T) -> Argument<'a> { + unsafe { + Argument { + formatter: cast::transmute(f), + value: cast::transmute(t) + } + } +} + +/// When the compiler determines that the type of an argument *must* be a string +/// (such as for select), then it invokes this method. +#[doc(hidden)] +pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> { + argument(String::fmt, s) +} + +/// When the compiler determines that the type of an argument *must* be a uint +/// (such as for plural), then it invokes this method. +#[doc(hidden)] +pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> { + argument(Unsigned::fmt, s) +} + +// Implementations of the core formatting traits + +impl Bool for bool { + fn fmt(b: &bool, f: &mut Formatter) { + String::fmt(&(if *b {"true"} else {"false"}), f); + } +} + +impl<'self> String for &'self str { + fn fmt(s: & &'self str, f: &mut Formatter) { + // XXX: formatting args + f.buf.write(s.as_bytes()) + } +} + +impl Char for char { + fn fmt(c: &char, f: &mut Formatter) { + // XXX: formatting args + // XXX: shouldn't require an allocation + let mut s = ~""; + s.push_char(*c); + f.buf.write(s.as_bytes()); + } +} + +impl Signed for int { + fn fmt(c: &int, f: &mut Formatter) { + // XXX: formatting args + do int::to_str_bytes(*c, 10) |buf| { + f.buf.write(buf); + } + } +} + +impl Unsigned for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 10) |buf| { + f.buf.write(buf); + } + } +} + +impl Octal for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 8) |buf| { + f.buf.write(buf); + } + } +} + +impl LowerHex for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 16) |buf| { + f.buf.write(buf); + } + } +} + +impl UpperHex for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 16) |buf| { + let mut local = [0u8, ..16]; + for (l, &b) in local.mut_iter().zip(buf.iter()) { + *l = match b as char { + 'a' .. 'f' => (b - 'a' as u8) + 'A' as u8, + _ => b, + }; + } + f.buf.write(local.slice_to(buf.len())); + } + } +} + +impl Poly for T { + fn fmt(t: &T, f: &mut Formatter) { + // XXX: formatting args + let s = sys::log_str(t); + f.buf.write(s.as_bytes()); + } +} + +// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same +// time. +impl Pointer for *const T { + fn fmt(t: &*const T, f: &mut Formatter) { + // XXX: formatting args + f.buf.write("0x".as_bytes()); + LowerHex::fmt(&(*t as uint), f); + } +} + +// If you expected tests to be here, look instead at the run-pass/ifmt.rs test, +// it's a lot easier than creating all of the rt::Piece structures here. diff --git a/src/libstd/fmt/parse.rs b/src/libstd/fmt/parse.rs new file mode 100644 index 000000000000..673ea1d3fa8b --- /dev/null +++ b/src/libstd/fmt/parse.rs @@ -0,0 +1,896 @@ +// 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 prelude::*; + +use char; +use str; +use iterator; + +condition! { pub parse_error: ~str -> (); } + +/// A piece is a portion of the format string which represents the next part to +/// emit. These are emitted as a stream by the `Parser` class. +#[deriving(Eq)] +pub enum Piece<'self> { + /// A literal string which should directly be emitted + String(&'self str), + /// A back-reference to whatever the current argument is. This is used + /// inside of a method call to refer back to the original argument. + CurrentArgument, + /// This describes that formatting should process the next argument (as + /// specified inside) for emission. + Argument(Argument<'self>), +} + +/// Representation of an argument specification. +#[deriving(Eq)] +pub struct Argument<'self> { + /// Where to find this argument + position: Position<'self>, + /// How to format the argument + format: FormatSpec<'self>, + /// If not `None`, what method to invoke on the argument + method: Option<~Method<'self>> +} + +/// Specification for the formatting of an argument in the format string. +#[deriving(Eq)] +pub struct FormatSpec<'self> { + /// Optionally specified character to fill alignment with + fill: Option, + /// Optionally specified alignment + align: Option, + /// Packed version of various flags provided + flags: uint, + /// The integer precision to use + precision: Count, + /// The string width requested for the resulting format + width: Count, + /// The descriptor string representing the name of the format desired for + /// this argument, this can be empty or any number of characters, although + /// it is required to be one word. + ty: &'self str +} + +/// Enum describing where an argument for a format can be located. +#[deriving(Eq)] +pub enum Position<'self> { + ArgumentNext, ArgumentIs(uint), ArgumentNamed(&'self str) +} + +/// Enum of alignments which are supoprted. +#[deriving(Eq)] +pub enum Alignment { AlignLeft, AlignRight } + +/// Various flags which can be applied to format strings, the meaning of these +/// flags is defined by the formatters themselves. +#[deriving(Eq)] +pub enum Flag { + FlagSignPlus, + FlagSignMinus, + FlagAlternate, +} + +/// A count is used for the precision and width parameters of an integer, and +/// can reference either an argument or a literal integer. +#[deriving(Eq)] +pub enum Count { + CountIs(uint), + CountIsParam(uint), + CountIsNextParam, + CountImplied, +} + +/// Enum describing all of the possible methods which the formatting language +/// currently supports. +#[deriving(Eq)] +pub enum Method<'self> { + /// A plural method selects on an integer over a list of either integer or + /// keyword-defined clauses. The meaning of the keywords is defined by the + /// current locale. + /// + /// An offset is optionally present at the beginning which is used to match + /// against keywords, but it is not matched against the literal integers. + /// + /// The final element of this enum is the default "other" case which is + /// always required to be specified. + Plural(Option, ~[PluralArm<'self>], ~[Piece<'self>]), + + /// A select method selects over a string. Each arm is a different string + /// which can be selected for. + /// + /// As with `Plural`, a default "other" case is required as well. + Select(~[SelectArm<'self>], ~[Piece<'self>]), +} + +/// Structure representing one "arm" of the `plural` function. +#[deriving(Eq)] +pub struct PluralArm<'self> { + /// A selector can either be specified by a keyword or with an integer + /// literal. + selector: Either, + /// Array of pieces which are the format of this arm + result: ~[Piece<'self>], +} + +/// Enum of the 5 CLDR plural keywords. There is one more, "other", but that is +/// specially placed in the `Plural` variant of `Method` +/// +/// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html +#[deriving(Eq, IterBytes)] +pub enum PluralKeyword { + Zero, One, Two, Few, Many +} + +/// Structure representing one "arm" of the `select` function. +#[deriving(Eq)] +pub struct SelectArm<'self> { + /// String selector which guards this arm + selector: &'self str, + /// Array of pieces which are the format of this arm + result: ~[Piece<'self>], +} + +/// The parser structure for interpreting the input format string. This is +/// modelled as an iterator over `Piece` structures to form a stream of tokens +/// being output. +/// +/// This is a recursive-descent parser for the sake of simplicity, and if +/// necessary there's probably lots of room for improvement performance-wise. +pub struct Parser<'self> { + priv input: &'self str, + priv cur: str::CharOffsetIterator<'self>, +} + +impl<'self> iterator::Iterator> for Parser<'self> { + fn next(&mut self) -> Option> { + match self.cur.clone().next() { + Some((_, '#')) => { self.cur.next(); Some(CurrentArgument) } + Some((_, '{')) => { + self.cur.next(); + let ret = Some(Argument(self.argument())); + if !self.consume('}') { + self.err(~"unterminated format string"); + } + ret + } + Some((pos, '\\')) => { + self.cur.next(); + self.escape(); // ensure it's a valid escape sequence + Some(String(self.string(pos + 1))) // skip the '\' character + } + Some((_, '}')) | None => { None } + Some((pos, _)) => { + Some(String(self.string(pos))) + } + } + } +} + +impl<'self> Parser<'self> { + /// Creates a new parser for the given format string + pub fn new<'a>(s: &'a str) -> Parser<'a> { + Parser { + input: s, + cur: s.char_offset_iter(), + } + } + + /// Notifies of an error. The message doesn't actually need to be of type + /// ~str, but I think it does when this eventually uses conditions so it + /// might as well start using it now. + fn err(&self, msg: ~str) { + parse_error::cond.raise(msg); + } + + /// Optionally consumes the specified character. If the character is not at + /// the current position, then the current iterator isn't moved and false is + /// returned, otherwise the character is consumed and true is returned. + fn consume(&mut self, c: char) -> bool { + match self.cur.clone().next() { + Some((_, maybe)) if c == maybe => { + self.cur.next(); + true + } + Some(*) | None => false, + } + } + + /// Attempts to consume any amount of whitespace followed by a character + fn wsconsume(&mut self, c: char) -> bool { + self.ws(); self.consume(c) + } + + /// Consumes all whitespace characters until the first non-whitespace + /// character + fn ws(&mut self) { + loop { + match self.cur.clone().next() { + Some((_, c)) if char::is_whitespace(c) => { self.cur.next(); } + Some(*) | None => { return } + } + } + } + + /// Consumes an escape sequence, failing if there is not a valid character + /// to be escaped. + fn escape(&mut self) -> char { + match self.cur.next() { + Some((_, c @ '#')) | Some((_, c @ '{')) | + Some((_, c @ '\\')) | Some((_, c @ '}')) => { c } + Some((_, c)) => { + self.err(fmt!("invalid escape character `%c`", c)); + c + } + None => { + self.err(~"expected an escape sequence, but format string was \ + terminated"); + ' ' + } + } + } + + /// Parses all of a string which is to be considered a "raw literal" in a + /// format string. This is everything outside of the braces. + fn string(&mut self, start: uint) -> &'self str { + loop { + // we may not consume the character, so clone the iterator + match self.cur.clone().next() { + Some((pos, '\\')) | Some((pos, '#')) | + Some((pos, '}')) | Some((pos, '{')) => { + return self.input.slice(start, pos); + } + Some(*) => { self.cur.next(); } + None => { + self.cur.next(); + return self.input.slice(start, self.input.len()); + } + } + } + } + + /// Parses an Argument structure, or what's contained within braces inside + /// the format string + fn argument(&mut self) -> Argument<'self> { + Argument { + position: self.position(), + format: self.format(), + method: self.method(), + } + } + + /// Parses a positional argument for a format. This could either be an + /// integer index of an argument, a named argument, or a blank string. + fn position(&mut self) -> Position<'self> { + match self.integer() { + Some(i) => { ArgumentIs(i) } + None => { + match self.cur.clone().next() { + Some((_, c)) if char::is_alphabetic(c) => { + ArgumentNamed(self.word()) + } + _ => ArgumentNext + } + } + } + } + + /// Parses a format specifier at the current position, returning all of the + /// relevant information in the FormatSpec struct. + fn format(&mut self) -> FormatSpec<'self> { + let mut spec = FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: self.input.slice(0, 0), + }; + if !self.consume(':') { return spec } + + // fill character + match self.cur.clone().next() { + Some((_, c)) => { + match self.cur.clone().skip(1).next() { + Some((_, '>')) | Some((_, '<')) => { + spec.fill = Some(c); + self.cur.next(); + } + Some(*) | None => {} + } + } + None => {} + } + // Alignment + if self.consume('<') { + spec.align = Some(AlignLeft); + } else if self.consume('>') { + spec.align = Some(AlignRight); + } + // Sign flags + if self.consume('+') { + spec.flags |= 1 << (FlagSignPlus as uint); + } else if self.consume('-') { + spec.flags |= 1 << (FlagSignMinus as uint); + } + // Alternate marker + if self.consume('#') { + spec.flags |= 1 << (FlagAlternate as uint); + } + // Width and precision + spec.width = self.count(); + if self.consume('.') { + if self.consume('*') { + spec.precision = CountIsNextParam; + } else { + spec.precision = self.count(); + } + } + // Finally the actual format specifier + spec.ty = self.word(); + return spec; + } + + /// Parses a method to be applied to the previously specified argument and + /// its format. The two current supported methods are 'plural' and 'select' + fn method(&mut self) -> Option<~Method<'self>> { + if !self.wsconsume(',') { + return None; + } + self.ws(); + match self.word() { + "select" => { + if !self.wsconsume(',') { + self.err(~"`select` must be followed by `,`"); + } + Some(self.select()) + } + "plural" => { + if !self.wsconsume(',') { + self.err(~"`plural` must be followed by `,`"); + } + Some(self.plural()) + } + "" => { + self.err(~"expected method after comma"); + return None; + } + method => { + self.err(fmt!("unknown method: `%s`", method)); + return None; + } + } + } + + /// Parses a 'select' statement (after the initial 'select' word) + fn select(&mut self) -> ~Method<'self> { + let mut other = None; + let mut arms = ~[]; + // Consume arms one at a time + loop { + self.ws(); + let selector = self.word(); + if selector == "" { + self.err(~"cannot have an empty selector"); + break + } + if !self.wsconsume('{') { + self.err(~"selector must be followed by `{`"); + } + let pieces = self.collect(); + if !self.wsconsume('}') { + self.err(~"selector case must be terminated by `}`"); + } + if selector == "other" { + if !other.is_none() { + self.err(~"multiple `other` statements in `select"); + } + other = Some(pieces); + } else { + arms.push(SelectArm { selector: selector, result: pieces }); + } + self.ws(); + match self.cur.clone().next() { + Some((_, '}')) => { break } + Some(*) | None => {} + } + } + // The "other" selector must be present + let other = match other { + Some(arm) => { arm } + None => { + self.err(~"`select` statement must provide an `other` case"); + ~[] + } + }; + ~Select(arms, other) + } + + /// Parses a 'plural' statement (after the initial 'plural' word) + fn plural(&mut self) -> ~Method<'self> { + let mut offset = None; + let mut other = None; + let mut arms = ~[]; + + // First, attempt to parse the 'offset:' field. We know the set of + // selector words which can appear in plural arms, and the only ones + // which start with 'o' are "other" and "offset", hence look two + // characters deep to see if we can consume the word "offset" + self.ws(); + let mut it = self.cur.clone(); + match it.next() { + Some((_, 'o')) => { + match it.next() { + Some((_, 'f')) => { + let word = self.word(); + if word != "offset" { + self.err(fmt!("expected `offset`, found `%s`", + word)); + } else { + if !self.consume(':') { + self.err(~"`offset` must be followed by `:`"); + } + match self.integer() { + Some(i) => { offset = Some(i); } + None => { + self.err(~"offset must be an integer"); + } + } + } + } + Some(*) | None => {} + } + } + Some(*) | None => {} + } + + // Next, generate all the arms + loop { + let mut isother = false; + let selector = if self.wsconsume('=') { + match self.integer() { + Some(i) => Right(i), + None => { + self.err(~"plural `=` selectors must be followed by an \ + integer"); + Right(0) + } + } + } else { + let word = self.word(); + match word { + "other" => { isother = true; Left(Zero) } + "zero" => Left(Zero), + "one" => Left(One), + "two" => Left(Two), + "few" => Left(Few), + "many" => Left(Many), + word => { + self.err(fmt!("unexpected plural selector `%s`", word)); + if word == "" { + break + } else { + Left(Zero) + } + } + } + }; + if !self.wsconsume('{') { + self.err(~"selector must be followed by `{`"); + } + let pieces = self.collect(); + if !self.wsconsume('}') { + self.err(~"selector case must be terminated by `}`"); + } + if isother { + if !other.is_none() { + self.err(~"multiple `other` statements in `select"); + } + other = Some(pieces); + } else { + arms.push(PluralArm { selector: selector, result: pieces }); + } + self.ws(); + match self.cur.clone().next() { + Some((_, '}')) => { break } + Some(*) | None => {} + } + } + + let other = match other { + Some(arm) => { arm } + None => { + self.err(~"`plural` statement must provide an `other` case"); + ~[] + } + }; + ~Plural(offset, arms, other) + } + + /// Parses a Count parameter at the current position. This does not check + /// for 'CountIsNextParam' because that is only used in precision, not + /// width. + fn count(&mut self) -> Count { + match self.integer() { + Some(i) => { + if self.consume('$') { + CountIsParam(i) + } else { + CountIs(i) + } + } + None => { CountImplied } + } + } + + /// Parses a word starting at the current position. A word is considered to + /// be an alphabetic character followed by any number of alphanumeric + /// characters. + fn word(&mut self) -> &'self str { + let start = match self.cur.clone().next() { + Some((pos, c)) if char::is_alphabetic(c) => { + self.cur.next(); + pos + } + Some(*) | None => { return self.input.slice(0, 0); } + }; + let mut end; + loop { + match self.cur.clone().next() { + Some((_, c)) if char::is_alphanumeric(c) => { + self.cur.next(); + } + Some((pos, _)) => { end = pos; break } + None => { end = self.input.len(); break } + } + } + self.input.slice(start, end) + } + + /// Optionally parses an integer at the current position. This doesn't deal + /// with overflow at all, it's just accumulating digits. + fn integer(&mut self) -> Option { + let mut cur = 0; + let mut found = false; + loop { + match self.cur.clone().next() { + Some((_, c)) => { + match char::to_digit(c, 10) { + Some(i) => { + cur = cur * 10 + i; + found = true; + self.cur.next(); + } + None => { break } + } + } + None => { break } + } + } + if found { + return Some(cur); + } else { + return None; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; + use realstd::fmt::{String}; + + fn same(fmt: &'static str, p: ~[Piece<'static>]) { + let mut parser = Parser::new(fmt); + assert_eq!(p, parser.collect()); + } + + fn fmtdflt() -> FormatSpec<'static> { + return FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + } + } + + fn musterr(s: &str) { + Parser::new(s).next(); + } + + #[test] + fn simple() { + same("asdf", ~[String("asdf")]); + same("a\\{b", ~[String("a"), String("{b")]); + same("a\\#b", ~[String("a"), String("#b")]); + same("a\\}b", ~[String("a"), String("}b")]); + same("a\\}", ~[String("a"), String("}")]); + same("\\}", ~[String("}")]); + } + + #[test] #[should_fail] fn invalid01() { musterr("{") } + #[test] #[should_fail] fn invalid02() { musterr("\\") } + #[test] #[should_fail] fn invalid03() { musterr("\\a") } + #[test] #[should_fail] fn invalid04() { musterr("{3a}") } + #[test] #[should_fail] fn invalid05() { musterr("{:|}") } + #[test] #[should_fail] fn invalid06() { musterr("{:>>>}") } + + #[test] + fn format_nothing() { + same("{}", ~[Argument(Argument { + position: ArgumentNext, + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_position() { + same("{3}", ~[Argument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_position_nothing_else() { + same("{3:}", ~[Argument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_type() { + same("{3:a}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "a", + }, + method: None, + })]); + } + #[test] + fn format_align_fill() { + same("{3:>}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: Some(AlignRight), + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + method: None, + })]); + same("{3:0<}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: Some('0'), + align: Some(AlignLeft), + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + method: None, + })]); + same("{3:* or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This is an internal module used by the ifmt! runtime. These structures are +//! emitted to static arrays to precompile format strings ahead of time. +//! +//! These definitions are similar to their `ct` equivalents, but differ in that +//! these can be statically allocated and are slightly optimized for the runtime + +#[allow(missing_doc)]; +#[doc(hidden)]; + +use either::Either; +use fmt::parse; +use option::Option; + +pub enum Piece<'self> { + String(&'self str), + // FIXME(#8259): this shouldn't require the unit-value here + CurrentArgument(()), + Argument(Argument<'self>), +} + +pub struct Argument<'self> { + position: Position, + format: FormatSpec, + method: Option<&'self Method<'self>> +} + +pub struct FormatSpec { + fill: char, + alignleft: bool, + flags: uint, + precision: parse::Count, + width: parse::Count, +} + +pub enum Position { + ArgumentNext, ArgumentIs(uint) +} + +pub enum Method<'self> { + Plural(Option, &'self [PluralArm<'self>], &'self [Piece<'self>]), + Select(&'self [SelectArm<'self>], &'self [Piece<'self>]), +} + +pub struct PluralArm<'self> { + selector: Either, + result: &'self [Piece<'self>], +} + +pub struct SelectArm<'self> { + selector: &'self str, + result: &'self [Piece<'self>], +} diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index c93945a6a9aa..277897e5d2e2 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -26,7 +26,7 @@ pub struct MemWriter { } impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: ~[] } } + pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } } } impl Writer for MemWriter { diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 568709c89da7..7000b56069df 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -177,6 +177,7 @@ pub mod rand; pub mod run; pub mod sys; pub mod cast; +pub mod fmt; pub mod repr; pub mod cleanup; pub mod reflect; @@ -216,4 +217,6 @@ mod std { pub use unstable; pub use str; pub use os; + pub use fmt; + pub use to_bytes; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ed5ca3e402a..99f74543e797 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -139,6 +139,8 @@ pub fn syntax_expander_table() -> SyntaxEnv { ext::tt::macro_rules::add_new_extension)); syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt(ext::fmt::expand_syntax_ext)); + syntax_expanders.insert(intern(&"ifmt"), + builtin_normal_tt(ext::ifmt::expand_syntax_ext)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c7020b990bf0..a928680e0939 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1014,7 +1014,9 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess, .. *afp}; let f = make_fold(f_pre); - @f.fold_crate(c) + let ret = @f.fold_crate(c); + parse_sess.span_diagnostic.handler().abort_if_errors(); + return ret; } // given a function from idents to idents, produce diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs new file mode 100644 index 000000000000..5cf5fdba632f --- /dev/null +++ b/src/libsyntax/ext/ifmt.rs @@ -0,0 +1,720 @@ +// 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. + +use ast; +use codemap::{span, respan}; +use ext::base::*; +use ext::base; +use ext::build::AstBuilder; +use rsparse = parse; +use parse::token; + +use std::fmt::parse; +use std::hashmap::{HashMap, HashSet}; +use std::vec; + +#[deriving(Eq)] +enum ArgumentType { + Unknown, + Known(@str), + Unsigned, + String, +} + +struct Context { + ecx: @ExtCtxt, + fmtsp: span, + + // Parsed argument expressions and the types that we've found so far for + // them. + args: ~[@ast::expr], + arg_types: ~[Option], + // Parsed named expressions and the types that we've found for them so far + names: HashMap<@str, @ast::expr>, + name_types: HashMap<@str, ArgumentType>, + + // Collection of the compiled `rt::Piece` structures + pieces: ~[@ast::expr], + name_positions: HashMap<@str, uint>, + method_statics: ~[@ast::item], + + // Updated as arguments are consumed or methods are entered + nest_level: uint, + next_arg: uint, +} + +impl Context { + /// Parses the arguments from the given list of tokens, returning None if + /// there's a parse error so we can continue parsing other fmt! expressions. + fn parse_args(&mut self, sp: span, + tts: &[ast::token_tree]) -> Option<@ast::expr> { + let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(), + self.ecx.cfg(), + tts.to_owned()); + if *p.token == token::EOF { + self.ecx.span_err(sp, "ifmt! expects at least one argument"); + return None; + } + let fmtstr = p.parse_expr(); + let mut named = false; + while *p.token != token::EOF { + if !p.eat(&token::COMMA) { + self.ecx.span_err(sp, "expected token: `,`"); + return None; + } + if named || (token::is_ident(p.token) && + p.look_ahead(1, |t| *t == token::EQ)) { + named = true; + let ident = match *p.token { + token::IDENT(i, _) => { + p.bump(); + i + } + _ if named => { + self.ecx.span_err(*p.span, + "expected ident, positional arguments \ + cannot follow named arguments"); + return None; + } + _ => { + self.ecx.span_err(*p.span, + fmt!("expected ident for named \ + argument, but found `%s`", + p.this_token_to_str())); + return None; + } + }; + let name = self.ecx.str_of(ident); + p.expect(&token::EQ); + let e = p.parse_expr(); + match self.names.find(&name) { + None => {} + Some(prev) => { + self.ecx.span_err(e.span, fmt!("duplicate argument \ + named `%s`", name)); + self.ecx.parse_sess.span_diagnostic.span_note( + prev.span, "previously here"); + loop + } + } + self.names.insert(name, e); + } else { + self.args.push(p.parse_expr()); + self.arg_types.push(None); + } + } + return Some(fmtstr); + } + + /// Verifies one piece of a parse string. All errors are not emitted as + /// fatal so we can continue giving errors about this and possibly other + /// format strings. + fn verify_piece(&mut self, p: &parse::Piece) { + match *p { + parse::String(*) => {} + parse::CurrentArgument => { + if self.nest_level == 0 { + self.ecx.span_err(self.fmtsp, + "`#` reference used with nothing to \ + reference back to"); + } + } + parse::Argument(ref arg) => { + // argument first (it's first in the format string) + let pos = match arg.position { + parse::ArgumentNext => { + let i = self.next_arg; + if self.check_positional_ok() { + self.next_arg += 1; + } + Left(i) + } + parse::ArgumentIs(i) => Left(i), + parse::ArgumentNamed(s) => Right(s.to_managed()), + }; + let ty = if arg.format.ty == "" { + Unknown + } else { Known(arg.format.ty.to_managed()) }; + self.verify_arg_type(pos, ty); + + // width/precision next + self.verify_count(arg.format.width); + self.verify_count(arg.format.precision); + + // and finally the method being applied + match arg.method { + None => {} + Some(ref method) => { self.verify_method(pos, *method); } + } + } + } + } + + fn verify_pieces(&mut self, pieces: &[parse::Piece]) { + for piece in pieces.iter() { + self.verify_piece(piece); + } + } + + fn verify_count(&mut self, c: parse::Count) { + match c { + parse::CountImplied | parse::CountIs(*) => {} + parse::CountIsParam(i) => { + self.verify_arg_type(Left(i), Unsigned); + } + parse::CountIsNextParam => { + if self.check_positional_ok() { + self.verify_arg_type(Left(self.next_arg), Unsigned); + self.next_arg += 1; + } + } + } + } + + fn check_positional_ok(&mut self) -> bool { + if self.nest_level != 0 { + self.ecx.span_err(self.fmtsp, "cannot use implicit positional \ + arguments nested inside methods"); + false + } else { + true + } + } + + fn verify_method(&mut self, pos: Either, m: &parse::Method) { + self.nest_level += 1; + match *m { + parse::Plural(_, ref arms, ref default) => { + let mut seen_cases = HashSet::new(); + self.verify_arg_type(pos, Unsigned); + for arm in arms.iter() { + if !seen_cases.insert(arm.selector) { + match arm.selector { + Left(name) => { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector \ + `%?`", name)); + } + Right(idx) => { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector \ + `=%u`", idx)); + } + } + } + self.verify_pieces(arm.result); + } + self.verify_pieces(*default); + } + parse::Select(ref arms, ref default) => { + self.verify_arg_type(pos, String); + let mut seen_cases = HashSet::new(); + for arm in arms.iter() { + if !seen_cases.insert(arm.selector) { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector `%s`", + arm.selector)); + } else if arm.selector == "" { + self.ecx.span_err(self.fmtsp, + "empty selector in `select`"); + } + self.verify_pieces(arm.result); + } + self.verify_pieces(*default); + } + } + self.nest_level -= 1; + } + + fn verify_arg_type(&mut self, arg: Either, ty: ArgumentType) { + match arg { + Left(arg) => { + if arg < 0 || self.args.len() <= arg { + let msg = fmt!("invalid reference to argument `%u` (there \ + are %u arguments)", arg, self.args.len()); + self.ecx.span_err(self.fmtsp, msg); + return; + } + self.verify_same(self.args[arg].span, ty, self.arg_types[arg]); + if ty != Unknown || self.arg_types[arg].is_none() { + self.arg_types[arg] = Some(ty); + } + } + + Right(name) => { + let span = match self.names.find(&name) { + Some(e) => e.span, + None => { + let msg = fmt!("There is no argument named `%s`", name); + self.ecx.span_err(self.fmtsp, msg); + return; + } + }; + self.verify_same(span, ty, + self.name_types.find(&name).map(|&x| *x)); + if ty != Unknown || !self.name_types.contains_key(&name) { + self.name_types.insert(name, ty); + } + // Assign this named argument a slot in the arguments array if + // it hasn't already been assigned a slot. + if !self.name_positions.contains_key(&name) { + let slot = self.name_positions.len(); + self.name_positions.insert(name, slot); + } + } + } + } + + /// When we're keeping track of the types that are declared for certain + /// arguments, we assume that `None` means we haven't seen this argument + /// yet, `Some(None)` means that we've seen the argument, but no format was + /// specified, and `Some(Some(x))` means that the argument was declared to + /// have type `x`. + /// + /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true + /// that: `Some(None) == Some(Some(x))` + fn verify_same(&self, sp: span, ty: ArgumentType, + before: Option) { + if ty == Unknown { return } + let cur = match before { + Some(Unknown) | None => return, + Some(t) => t, + }; + if ty == cur { return } + match (cur, ty) { + (Known(cur), Known(ty)) => { + self.ecx.span_err(sp, + fmt!("argument redeclared with type `%s` when \ + it was previously `%s`", ty, cur)); + } + (Known(cur), _) => { + self.ecx.span_err(sp, + fmt!("argument used to format with `%s` was \ + attempted to not be used for formatting", + cur)); + } + (_, Known(ty)) => { + self.ecx.span_err(sp, + fmt!("argument previously used as a format \ + argument attempted to be used as `%s`", + ty)); + } + (_, _) => { + self.ecx.span_err(sp, "argument declared with multiple formats"); + } + } + } + + /// Translate a `parse::Piece` to a static `rt::Piece` + fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr { + let sp = self.fmtsp; + let rtpath = |s: &str| { + ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), + self.ecx.ident_of("rt"), self.ecx.ident_of(s)] + }; + let ctpath = |s: &str| { + ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), + self.ecx.ident_of("parse"), self.ecx.ident_of(s)] + }; + let none = || { + let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]); + self.ecx.expr_path(p) + }; + let some = |e: @ast::expr| { + self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e]) + }; + let trans_count = |c: parse::Count| { + match c { + parse::CountIs(i) => { + self.ecx.expr_call_global(sp, ctpath("CountIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + parse::CountIsParam(i) => { + self.ecx.expr_call_global(sp, ctpath("CountIsParam"), + ~[self.ecx.expr_uint(sp, i)]) + } + parse::CountImplied => { + let path = self.ecx.path_global(sp, ctpath("CountImplied")); + self.ecx.expr_path(path) + } + parse::CountIsNextParam => { + let path = self.ecx.path_global(sp, ctpath("CountIsNextParam")); + self.ecx.expr_path(path) + } + } + }; + let trans_method = |method: &parse::Method| { + let method = match *method { + parse::Select(ref arms, ref default) => { + let arms = arms.iter().transform(|arm| { + let p = self.ecx.path_global(sp, rtpath("SelectArm")); + let result = arm.result.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + let s = arm.selector.to_managed(); + let selector = self.ecx.expr_str(sp, s); + self.ecx.expr_struct(sp, p, ~[ + self.ecx.field_imm(sp, + self.ecx.ident_of("selector"), + selector), + self.ecx.field_imm(sp, self.ecx.ident_of("result"), + self.ecx.expr_vec_slice(sp, result)), + ]) + }).collect(); + let default = default.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + self.ecx.expr_call_global(sp, rtpath("Select"), ~[ + self.ecx.expr_vec_slice(sp, arms), + self.ecx.expr_vec_slice(sp, default), + ]) + } + parse::Plural(offset, ref arms, ref default) => { + let offset = match offset { + Some(i) => { some(self.ecx.expr_uint(sp, i)) } + None => { none() } + }; + let arms = arms.iter().transform(|arm| { + let p = self.ecx.path_global(sp, rtpath("PluralArm")); + let result = arm.result.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + let (lr, selarg) = match arm.selector { + Left(t) => { + let p = ctpath(fmt!("%?", t)); + let p = self.ecx.path_global(sp, p); + (self.ecx.ident_of("Left"), + self.ecx.expr_path(p)) + } + Right(i) => { + (self.ecx.ident_of("Right"), + self.ecx.expr_uint(sp, i)) + } + }; + let selector = self.ecx.expr_call_ident(sp, + lr, ~[selarg]); + self.ecx.expr_struct(sp, p, ~[ + self.ecx.field_imm(sp, + self.ecx.ident_of("selector"), + selector), + self.ecx.field_imm(sp, self.ecx.ident_of("result"), + self.ecx.expr_vec_slice(sp, result)), + ]) + }).collect(); + let default = default.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + self.ecx.expr_call_global(sp, rtpath("Plural"), ~[ + offset, + self.ecx.expr_vec_slice(sp, arms), + self.ecx.expr_vec_slice(sp, default), + ]) + } + }; + let life = self.ecx.lifetime(sp, self.ecx.ident_of("static")); + let ty = self.ecx.ty_path(self.ecx.path_all( + sp, + true, + rtpath("Method"), + Some(life), + ~[] + ), None); + let st = ast::item_static(ty, ast::m_imm, method); + let static_name = self.ecx.ident_of(fmt!("__static_method_%u", + self.method_statics.len())); + let item = self.ecx.item(sp, static_name, ~[], st); + self.method_statics.push(item); + self.ecx.expr_ident(sp, static_name) + }; + + match *piece { + parse::String(s) => { + self.ecx.expr_call_global(sp, rtpath("String"), + ~[self.ecx.expr_str(sp, s.to_managed())]) + } + parse::CurrentArgument => { + let nil = self.ecx.expr_lit(sp, ast::lit_nil); + self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil]) + } + parse::Argument(ref arg) => { + // Translate the position + let pos = match arg.position { + // These two have a direct mapping + parse::ArgumentNext => { + let path = self.ecx.path_global(sp, + rtpath("ArgumentNext")); + self.ecx.expr_path(path) + } + parse::ArgumentIs(i) => { + self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + // Named arguments are converted to positional arguments at + // the end of the list of arguments + parse::ArgumentNamed(n) => { + let n = n.to_managed(); + let i = match self.name_positions.find_copy(&n) { + Some(i) => i, + None => 0, // error already emitted elsewhere + }; + let i = i + self.args.len(); + self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + }; + + // Translate the format + let fill = match arg.format.fill { Some(c) => c, None => ' ' }; + let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64, + ast::ty_char)); + let align = match arg.format.align { + None | Some(parse::AlignLeft) => { + self.ecx.expr_bool(sp, true) + } + Some(parse::AlignRight) => { + self.ecx.expr_bool(sp, false) + } + }; + let flags = self.ecx.expr_uint(sp, arg.format.flags); + let prec = trans_count(arg.format.precision); + let width = trans_count(arg.format.width); + let path = self.ecx.path_global(sp, rtpath("FormatSpec")); + let fmt = self.ecx.expr_struct(sp, path, ~[ + self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), + self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align), + self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), + self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), + self.ecx.field_imm(sp, self.ecx.ident_of("width"), width), + ]); + + // Translate the method (if any) + let method = match arg.method { + None => { none() } + Some(ref m) => { + let m = trans_method(*m); + some(self.ecx.expr_addr_of(sp, m)) + } + }; + let path = self.ecx.path_global(sp, rtpath("Argument")); + let s = self.ecx.expr_struct(sp, path, ~[ + self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), + self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt), + self.ecx.field_imm(sp, self.ecx.ident_of("method"), method), + ]); + self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s]) + } + } + } + + /// Actually builds the expression which the ifmt! block will be expanded + /// to + fn to_expr(&self) -> @ast::expr { + let mut lets = ~[]; + let mut locals = ~[]; + let mut names = vec::from_fn(self.name_positions.len(), |_| None); + + // First, declare all of our methods that are statics + for &method in self.method_statics.iter() { + let decl = respan(self.fmtsp, ast::decl_item(method)); + lets.push(@respan(self.fmtsp, + ast::stmt_decl(@decl, self.ecx.next_id()))); + } + + // Next, build up the static array which will become our precompiled + // format "string" + let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone()); + let ty = ast::ty_fixed_length_vec( + self.ecx.ty_mt( + self.ecx.ty_path(self.ecx.path_all( + self.fmtsp, + true, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("rt"), + self.ecx.ident_of("Piece"), + ], + Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + ~[] + ), None), + ast::m_imm + ), + self.ecx.expr_uint(self.fmtsp, self.pieces.len()) + ); + let ty = self.ecx.ty(self.fmtsp, ty); + let st = ast::item_static(ty, ast::m_imm, fmt); + let static_name = self.ecx.ident_of("__static_fmtstr"); + let item = self.ecx.item(self.fmtsp, static_name, ~[], st); + let decl = respan(self.fmtsp, ast::decl_item(item)); + lets.push(@respan(self.fmtsp, ast::stmt_decl(@decl, self.ecx.next_id()))); + + // Right now there is a bug such that for the expression: + // foo(bar(&1)) + // the lifetime of `1` doesn't outlast the call to `bar`, so it's not + // vald for the call to `foo`. To work around this all arguments to the + // fmt! string are shoved into locals. + for (i, &e) in self.args.iter().enumerate() { + if self.arg_types[i].is_none() { loop } // error already generated + + let name = self.ecx.ident_of(fmt!("__arg%u", i)); + lets.push(self.ecx.stmt_let(e.span, false, name, e)); + locals.push(self.format_arg(e.span, Left(i), name)); + } + for (&name, &e) in self.names.iter() { + if !self.name_types.contains_key(&name) { loop } + + let lname = self.ecx.ident_of(fmt!("__arg%s", name)); + lets.push(self.ecx.stmt_let(e.span, false, lname, e)); + names[*self.name_positions.get(&name)] = + Some(self.format_arg(e.span, Right(name), lname)); + } + + let args = names.consume_iter().transform(|a| a.unwrap()); + let mut args = locals.consume_iter().chain_(args); + + // Next, build up the actual call to the sprintf function. + let result = self.ecx.expr_call_global(self.fmtsp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("sprintf"), + ], ~[ + self.ecx.expr_ident(self.fmtsp, static_name), + self.ecx.expr_vec(self.fmtsp, args.collect()), + ]); + + // sprintf is unsafe, but we just went through a lot of work to + // validate that our call is save, so inject the unsafe block for the + // user. + let result = self.ecx.expr_block(ast::Block { + view_items: ~[], + stmts: ~[], + expr: Some(result), + id: self.ecx.next_id(), + rules: ast::UnsafeBlock, + span: self.fmtsp, + }); + + self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result))) + } + + fn format_arg(&self, sp: span, arg: Either, + ident: ast::ident) -> @ast::expr { + let mut ty = match arg { + Left(i) => self.arg_types[i].unwrap(), + Right(s) => *self.name_types.get(&s) + }; + // Default types to '?' if nothing else is specified. + if ty == Unknown { + ty = Known(@"?"); + } + let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident)); + match ty { + Known(tyname) => { + let fmt_trait = match tyname.as_slice() { + "?" => "Poly", + "d" | "i" => "Signed", + "u" => "Unsigned", + "b" => "Bool", + "c" => "Char", + "o" => "Octal", + "x" => "LowerHex", + "X" => "UpperHex", + "s" => "String", + "p" => "Pointer", + _ => { + self.ecx.span_err(sp, fmt!("unknown format trait \ + `%s`", tyname)); + "Dummy" + } + }; + let format_fn = self.ecx.path_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of(fmt_trait), + self.ecx.ident_of("fmt"), + ]); + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argument"), + ], ~[self.ecx.expr_path(format_fn), argptr]) + } + String => { + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argumentstr"), + ], ~[argptr]) + } + Unsigned => { + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argumentuint"), + ], ~[argptr]) + } + Unknown => { fail!() } + } + } +} + +pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + let mut cx = Context { + ecx: ecx, + args: ~[], + arg_types: ~[], + names: HashMap::new(), + name_positions: HashMap::new(), + name_types: HashMap::new(), + nest_level: 0, + next_arg: 0, + pieces: ~[], + method_statics: ~[], + fmtsp: sp, + }; + let efmt = match cx.parse_args(sp, tts) { + Some(e) => e, + None => { return MRExpr(ecx.expr_uint(sp, 2)); } + }; + cx.fmtsp = efmt.span; + let fmt = expr_to_str(ecx, efmt, + ~"first argument to ifmt! must be a string literal."); + + let mut err = false; + do parse::parse_error::cond.trap(|m| { + if !err { + err = true; + ecx.span_err(efmt.span, m); + } + }).inside { + for piece in parse::Parser::new(fmt) { + if !err { + cx.verify_piece(&piece); + let piece = cx.trans_piece(&piece); + cx.pieces.push(piece); + } + } + } + if err { return MRExpr(efmt) } + + // Make sure that all arguments were used and all arguments have types. + for (i, ty) in cx.arg_types.iter().enumerate() { + if ty.is_none() { + ecx.span_err(cx.args[i].span, "argument never used"); + } + } + for (name, e) in cx.names.iter() { + if !cx.name_types.contains_key(name) { + ecx.span_err(e.span, "named argument never used"); + } + } + + MRExpr(cx.to_expr()) +} diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs index e0f5aa848a29..a5feb0483d89 100644 --- a/src/libsyntax/syntax.rs +++ b/src/libsyntax/syntax.rs @@ -73,6 +73,7 @@ pub mod ext { pub mod cfg; pub mod fmt; + pub mod ifmt; pub mod env; pub mod bytes; pub mod concat_idents; diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs new file mode 100644 index 000000000000..875ad0d2b62a --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -0,0 +1,74 @@ +// 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. + +fn main() { + // bad arguments to the ifmt! call + + ifmt!(); //~ ERROR: expects at least one + ifmt!("{}"); //~ ERROR: invalid reference to argument + + ifmt!("{1}", 1); //~ ERROR: invalid reference to argument `1` + //~^ ERROR: argument never used + ifmt!("{foo}"); //~ ERROR: no argument named `foo` + + ifmt!("{}", 1, 2); //~ ERROR: argument never used + ifmt!("{1}", 1, 2); //~ ERROR: argument never used + ifmt!("{}", 1, foo=2); //~ ERROR: named argument never used + ifmt!("{foo}", 1, foo=2); //~ ERROR: argument never used + ifmt!("", foo=2); //~ ERROR: named argument never used + + ifmt!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` + ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` + + ifmt!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument + ifmt!("#"); //~ ERROR: `#` reference used + ifmt!("", foo=1, 2); //~ ERROR: positional arguments cannot follow + ifmt!("" 1); //~ ERROR: expected token: `,` + ifmt!("", 1 1); //~ ERROR: expected token: `,` + + ifmt!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector + ifmt!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector + ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector + + // bad syntax of the format string + + ifmt!("{"); //~ ERROR: unterminated format string + ifmt!("\\ "); //~ ERROR: invalid escape + ifmt!("\\"); //~ ERROR: expected an escape + + ifmt!("{0, }", 1); //~ ERROR: expected method + ifmt!("{0, foo}", 1); //~ ERROR: unknown method + ifmt!("{0, select}", "a"); //~ ERROR: must be followed by + ifmt!("{0, plural}", 1); //~ ERROR: must be followed by + + ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated + ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector + ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other` + ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer + ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:` + ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer + ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural + ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other` + ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other` + + ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as + ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to + ifmt!("{0, select, other{}} \ + {0, plural, other{}}", "a"); + //~^ ERROR: declared with multiple formats + + // It should be illegal to use implicit placement arguments nested inside of + // format strings because otherwise the "internal pointer of which argument + // is next" would be invalidated if different cases had different numbers of + // arguments. + ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit + ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit + ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit +} diff --git a/src/test/compile-fail/ifmt-bad-plural.rs b/src/test/compile-fail/ifmt-bad-plural.rs new file mode 100644 index 000000000000..76a697b174f5 --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-plural.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + ifmt!("{0, plural, other{}}", "a"); + //~^ ERROR: expected uint but found +} diff --git a/src/test/compile-fail/ifmt-bad-select.rs b/src/test/compile-fail/ifmt-bad-select.rs new file mode 100644 index 000000000000..abe3b6ed65a6 --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-select.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + ifmt!("{0, select, other{}}", 2); + //~^ ERROR: expected &str but found integral +} diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs new file mode 100644 index 000000000000..427f5ea562c7 --- /dev/null +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + ifmt!("{:d}", "3"); + //~^ ERROR: failed to find an implementation of trait std::fmt::Signed +} diff --git a/src/test/compile-fail/ifmt-unknown-trait.rs b/src/test/compile-fail/ifmt-unknown-trait.rs new file mode 100644 index 000000000000..85556f9501ac --- /dev/null +++ b/src/test/compile-fail/ifmt-unknown-trait.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + ifmt!("{:notimplemented}", "3"); + //~^ ERROR: unknown format trait `notimplemented` +} diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs new file mode 100644 index 000000000000..562642453fd2 --- /dev/null +++ b/src/test/run-pass/ifmt.rs @@ -0,0 +1,71 @@ +// 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::fmt; + +struct A; +struct B; + +#[fmt="foo"] +impl fmt::Signed for A { + fn fmt(_: &A, f: &mut fmt::Formatter) { f.buf.write("aloha".as_bytes()); } +} +impl fmt::Signed for B { + fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); } +} + +pub fn main() { + fn t(a: ~str, b: &str) { assert_eq!(a, b.to_owned()); } + + // Make sure there's a poly formatter that takes anything + t(ifmt!("{}", 1), "1"); + t(ifmt!("{}", A), "{}"); + t(ifmt!("{}", ()), "()"); + t(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")"); + + // Various edge cases without formats + t(ifmt!(""), ""); + t(ifmt!("hello"), "hello"); + t(ifmt!("hello \\{"), "hello {"); + + // At least exercise all the formats + t(ifmt!("{:b}", true), "true"); + t(ifmt!("{:c}", '☃'), "☃"); + t(ifmt!("{:d}", 10), "10"); + t(ifmt!("{:i}", 10), "10"); + t(ifmt!("{:u}", 10u), "10"); + t(ifmt!("{:o}", 10u), "12"); + t(ifmt!("{:x}", 10u), "a"); + t(ifmt!("{:X}", 10u), "A"); + t(ifmt!("{:s}", "foo"), "foo"); + t(ifmt!("{:p}", 0x1234 as *int), "0x1234"); + t(ifmt!("{:p}", 0x1234 as *mut int), "0x1234"); + t(ifmt!("{:d}", A), "aloha"); + t(ifmt!("{:d}", B), "adios"); + t(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t(ifmt!("{1} {0}", 0, 1), "1 0"); + t(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1"); + t(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); + t(ifmt!("{} {0:s}", "a"), "a a"); + t(ifmt!("{} {0}", "a"), "\"a\" \"a\""); + + // Methods should probably work + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd"); + t(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab"); + t(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb"); +} + From 026c1ae3113a6333bace9058d2d38cb7bc1c9cc8 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Wed, 7 Aug 2013 16:59:17 +0200 Subject: [PATCH 19/48] extra: Remove all .each methods in smallintmap --- src/libextra/smallintmap.rs | 43 ------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index e5116f19afa5..8103ed7a4785 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -16,7 +16,6 @@ #[allow(missing_doc)]; use std::iterator::{Iterator, IteratorUtil, Enumerate, FilterMap, Invert}; -use std::uint; use std::util::replace; use std::vec::{VecIterator, VecMutIterator}; use std::vec; @@ -116,48 +115,6 @@ impl SmallIntMap { /// Create an empty SmallIntMap pub fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } - /// Visit all key-value pairs in order - pub fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all keys in order - pub fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - pub fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { - for i in range(0, self.v.len()) { - match self.v[i] { - Some(ref mut elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { - do uint::range_rev(self.v.len(), 0) |i| { - match self.v[i] { - Some(ref elt) => it(i, elt), - None => true - } - } - } - pub fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } From 40bdbf0f5d1e997891918a2bf8bec5fc61432f05 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Wed, 7 Aug 2013 16:58:56 +0200 Subject: [PATCH 20/48] std: Fix for-range loops that can use iterators Fix inappropriate for-range loops to use for-iterator constructs (or other appropriate solution) instead. --- src/libextra/arc.rs | 14 ++++---------- src/libextra/bitv.rs | 17 +++++++++-------- src/libextra/smallintmap.rs | 14 ++++++-------- src/libextra/sort.rs | 10 ++-------- src/libstd/at_vec.rs | 6 +++--- src/libstd/hashmap.rs | 6 +++--- src/libstd/trie.rs | 4 ++-- src/libstd/vec.rs | 4 ++-- 8 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index cb4468f48ecb..ad950f198ce9 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -846,22 +846,16 @@ mod tests { } assert_eq!(*state, 42); *state = 31337; - // FIXME: #7372: hits type inference bug with iterators // send to other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (ref rc, _) => rc.send(()), - } + for &(ref rc, _) in reader_convos.iter() { + rc.send(()) } } let read_mode = arc.downgrade(write_mode); do (&read_mode).read |state| { - // FIXME: #7372: hits type inference bug with iterators // complete handshake with other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (_, ref rp) => rp.recv(), - } + for &(_, ref rp) in reader_convos.iter() { + rp.recv() } wc1.send(()); // tell writer to try again assert_eq!(*state, 31337); diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 6dedd9ee4dd2..20a3add3e7b3 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -145,14 +145,16 @@ impl BigBitv { let len = b.storage.len(); assert_eq!(self.storage.len(), len); let mut changed = false; - for i in range(0, len) { + for (i, (a, b)) in self.storage.mut_iter() + .zip(b.storage.iter()) + .enumerate() { let mask = big_mask(nbits, i); - let w0 = self.storage[i] & mask; - let w1 = b.storage[i] & mask; + let w0 = *a & mask; + let w1 = *b & mask; let w = op(w0, w1) & mask; if w0 != w { changed = true; - self.storage[i] = w; + *a = w; } } changed @@ -160,7 +162,7 @@ impl BigBitv { #[inline] pub fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) -> bool { - range(0u, self.storage.len()).advance(|i| op(&mut self.storage[i])) + self.storage.mut_iter().advance(|elt| op(elt)) } #[inline] @@ -205,10 +207,9 @@ impl BigBitv { #[inline] pub fn equals(&self, b: &BigBitv, nbits: uint) -> bool { - let len = b.storage.len(); - for i in range(0, len) { + for (i, elt) in b.storage.iter().enumerate() { let mask = big_mask(nbits, i); - if mask & self.storage[i] != mask & b.storage[i] { + if mask & self.storage[i] != mask & *elt { return false; } } diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index 8103ed7a4785..a601270e8ece 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -28,14 +28,12 @@ pub struct SmallIntMap { impl Container for SmallIntMap { /// Return the number of elements in the map fn len(&self) -> uint { - let mut sz = 0; - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(_) => sz += 1, - None => {} - } - } - sz + self.v.iter().count(|elt| elt.is_some()) + } + + /// Return true if there are no elements in the map + fn is_empty(&self) -> bool { + self.v.iter().all(|elt| elt.is_none()) } } diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index 8090dd26ef20..daafdbc37182 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -469,10 +469,7 @@ impl MergeState { base2: uint, len2: uint) { assert!(len1 != 0 && len2 != 0 && base1+len1 == base2); - let mut tmp = ~[]; - for i in range(base1, base1+len1) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base1, base1 + len1).to_owned(); let mut c1 = 0; let mut c2 = base2; @@ -579,10 +576,7 @@ impl MergeState { base2: uint, len2: uint) { assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2); - let mut tmp = ~[]; - for i in range(base2, base2+len2) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base2, base2 + len2).to_owned(); let mut c1 = base1 + len1 - 1; let mut c2 = len2 - 1; diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index a84f3137bbd5..f2470bed7329 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,7 +12,7 @@ use clone::Clone; use container::Container; -use iterator::{Iterator, range}; +use iterator::Iterator; use option::{Option, Some, None}; use sys; use unstable::raw::Repr; @@ -92,8 +92,8 @@ pub fn append(lhs: @[T], rhs: &[T]) -> @[T] { for x in lhs.iter() { push((*x).clone()); } - for i in range(0u, rhs.len()) { - push(rhs[i].clone()); + for elt in rhs.iter() { + push(elt.clone()); } } } diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 3484a5e7d6e8..84cba254dcf2 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,7 @@ use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; -use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range}; +use iterator::{Iterator, IteratorUtil, FromIterator, Extendable}; use iterator::{FilterMap, Chain, Repeat, Zip}; use num; use option::{None, Option, Some}; @@ -265,8 +265,8 @@ impl Container for HashMap { impl Mutable for HashMap { /// Clear the map, removing all key-value pairs. fn clear(&mut self) { - for idx in range(0u, self.buckets.len()) { - self.buckets[idx] = None; + for bkt in self.buckets.mut_iter() { + *bkt = None; } self.size = 0; } diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 6f61d29780f0..a5efae542a1f 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -271,8 +271,8 @@ impl TrieNode { impl TrieNode { fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - for idx in range(0u, self.children.len()) { - match self.children[idx] { + for elt in self.children.iter() { + match *elt { Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 36201dc5e826..0f6d94bb7710 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1602,8 +1602,8 @@ impl OwnedCopyableVector for ~[T] { let new_len = self.len() + rhs.len(); self.reserve(new_len); - for i in range(0u, rhs.len()) { - self.push(unsafe { raw::get(rhs, i) }) + for elt in rhs.iter() { + self.push((*elt).clone()) } } From e7d4a9c7f248a87a1aa6b5008c7229da2b69a20f Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Wed, 7 Aug 2013 19:29:19 +0200 Subject: [PATCH 21/48] Bugfix .each_edge in middle/graph.rs Edge iterator used the length of the nodes vector, must be a mistake. --- src/librustc/middle/graph.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 28d24b169ca4..46394454d006 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -187,12 +187,12 @@ impl Graph { pub fn each_node(&self, f: &fn(NodeIndex, &Node) -> bool) -> bool { //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(NodeIndex(i), &self.nodes[i])) + self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node)) } pub fn each_edge(&self, f: &fn(EdgeIndex, &Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(EdgeIndex(i), &self.edges[i])) + //! Iterates over all edges defined in the graph + self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge)) } pub fn each_outgoing_edge(&self, From 8523f6d64355f53bb9453c2c9d32e835bec790ae Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Wed, 7 Aug 2013 20:19:15 +0200 Subject: [PATCH 22/48] rustc: Fix for-range loops that can use iterators Transform range loops that can be regular iterator loops. --- src/compiletest/runtest.rs | 4 ++-- src/librustc/middle/borrowck/check_loans.rs | 8 ++++---- src/librustc/middle/dataflow.rs | 8 ++++---- src/librustc/middle/trans/base.rs | 3 +-- src/librustc/middle/trans/cabi_x86_64.rs | 4 ++-- src/librustc/middle/trans/type_use.rs | 11 ++--------- src/librustc/middle/typeck/check/method.rs | 4 ++-- src/librustc/middle/typeck/coherence.rs | 4 ++-- .../middle/typeck/infer/region_inference/mod.rs | 4 ++-- 9 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 0d1c5c8eb435..9c176b504b2e 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -412,8 +412,8 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], } } - for i in range(0u, found_flags.len()) { - if !found_flags[i] { + for (i, &flag) in found_flags.iter().enumerate() { + if !flag { let ee = &expected_errors[i]; fatal_ProcRes(fmt!("expected %s on line %u not found: %s", ee.kind, ee.line, ee.msg), ProcRes); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index c3bb2000447f..88e168db5584 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -159,10 +159,10 @@ impl<'self> CheckLoanCtxt<'self> { true }; - for i in range(0u, new_loan_indices.len()) { - let old_loan = &self.all_loans[new_loan_indices[i]]; - for j in range(i+1, new_loan_indices.len()) { - let new_loan = &self.all_loans[new_loan_indices[j]]; + for (i, &x) in new_loan_indices.iter().enumerate() { + let old_loan = &self.all_loans[x]; + for &y in new_loan_indices.slice_from(i+1).iter() { + let new_loan = &self.all_loans[y]; self.report_error_if_loans_conflict(old_loan, new_loan); } } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 008add975d49..46b6d2214ae4 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -983,10 +983,10 @@ fn bitwise(out_vec: &mut [uint], op: &fn(uint, uint) -> uint) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; - for i in range(0u, out_vec.len()) { - let old_val = out_vec[i]; - let new_val = op(old_val, in_vec[i]); - out_vec[i] = new_val; + for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) { + let old_val = *out_elt; + let new_val = op(old_val, *in_elt); + *out_elt = new_val; changed |= (old_val != new_val); } changed diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index dcaa141cbc28..db8a86fe948d 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1742,8 +1742,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext, _ => {} } - for arg_n in range(0u, arg_tys.len()) { - let arg_ty = arg_tys[arg_n]; + for (arg_n, &arg_ty) in arg_tys.iter().enumerate() { let raw_llarg = raw_llargs[arg_n]; // For certain mode/type combinations, the raw llarg values are passed diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 530e1ff8e5ba..dd24ec3ff1ac 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -145,8 +145,8 @@ fn classify_ty(ty: Type) -> ~[RegClass] { } fn all_mem(cls: &mut [RegClass]) { - for i in range(0u, cls.len()) { - cls[i] = Memory; + for elt in cls.mut_iter() { + *elt = Memory; } } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index ad83286c8c1d..f25bf011f5d0 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -206,15 +206,8 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) { // Optimization -- don't descend type if all params already have this use - let len = { - let uses = &*cx.uses; - uses.len() - }; - for i in range(0u, len) { - if cx.uses[i] & use_ != use_ { - type_needs_inner(cx, use_, ty, @Nil); - return; - } + if cx.uses.iter().any(|&elt| elt & use_ != use_) { + type_needs_inner(cx, use_, ty, @Nil); } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index e1e7d10db0ab..ae0a95688ed2 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -772,8 +772,8 @@ impl<'self> LookupContext<'self> { self.tcx().sess.span_err( self.expr.span, "multiple applicable methods in scope"); - for idx in range(0u, relevant_candidates.len()) { - self.report_candidate(idx, &relevant_candidates[idx].origin); + for (idx, candidate) in relevant_candidates.iter().enumerate() { + self.report_candidate(idx, &candidate.origin); } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index bc8de29b78bc..c3df0d06f83d 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -554,8 +554,8 @@ impl CoherenceChecker { let mut provided_names = HashSet::new(); // Implemented methods - for i in range(0u, all_methods.len()) { - provided_names.insert(all_methods[i].ident); + for elt in all_methods.iter() { + provided_names.insert(elt.ident); } let r = ty::trait_methods(tcx, trait_did); diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 63503f3e6b6c..91b6a4ce3bce 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -374,8 +374,8 @@ impl RegionVarBindings { pub fn vars_created_since_snapshot(&mut self, snapshot: uint) -> ~[RegionVid] { do vec::build |push| { - for i in range(snapshot, self.undo_log.len()) { - match self.undo_log[i] { + for &elt in self.undo_log.slice_from(snapshot).iter() { + match elt { AddVar(vid) => push(vid), _ => () } From 8964fcc5ac9cefcc55ea071142c3c81d623a52be Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 6 Aug 2013 22:34:22 -0700 Subject: [PATCH 23/48] Implement DoubleEndedIterator on Range Range is now invertable as long as its element type conforms to Integer. Remove int::range_rev() et al in favor of range().invert(). --- src/libstd/iterator.rs | 35 ++++++++++++++++++++++--- src/libstd/num/int_macros.rs | 18 +------------ src/libstd/num/uint_macros.rs | 17 +----------- src/libstd/run.rs | 6 ++--- src/libstd/trie.rs | 26 +++++++++--------- src/test/bench/core-map.rs | 15 +++++------ src/test/run-fail/assert-eq-macro-fail | Bin 0 -> 104051 bytes src/test/run-pass/num-range-rev.rs | 4 +-- 8 files changed, 56 insertions(+), 65 deletions(-) create mode 100755 src/test/run-fail/assert-eq-macro-fail diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 29f54bd10fba..d10a5541e41a 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,9 +18,9 @@ implementing the `Iterator` trait. */ use cmp; -use num::{Zero, One, Saturating}; +use num::{Zero, One, Integer, Saturating}; use option::{Option, Some, None}; -use ops::{Add, Mul}; +use ops::{Add, Mul, Sub}; use cmp::Ord; use clone::Clone; use uint; @@ -1531,7 +1531,7 @@ pub fn range + Ord + Clone + One>(start: A, stop: A) -> Range { Range{state: start, stop: stop, one: One::one()} } -impl + Ord + Clone + One> Iterator for Range { +impl + Ord + Clone> Iterator for Range { #[inline] fn next(&mut self) -> Option { if self.state < self.stop { @@ -1544,6 +1544,22 @@ impl + Ord + Clone + One> Iterator for Range { } } +impl + Integer + Ord + Clone> DoubleEndedIterator for Range { + #[inline] + fn next_back(&mut self) -> Option { + if self.stop > self.state { + // Integer doesn't technically define this rule, but we're going to assume that every + // Integer is reachable from every other one by adding or subtracting enough Ones. This + // seems like a reasonable-enough rule that every Integer should conform to, even if it + // can't be statically checked. + self.stop = self.stop - self.one; + Some(self.stop.clone()) + } else { + None + } + } +} + impl + Clone> Iterator for Counter { #[inline] fn next(&mut self) -> Option { @@ -2121,4 +2137,17 @@ mod tests { check_randacc_iter(xs.iter().cycle().take_(27), 27); check_randacc_iter(empty.iter().cycle(), 0); } + + #[test] + fn test_double_ended_range() { + assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]); + for _ in range(10i, 0).invert() { + fail!("unreachable"); + } + + assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]); + for _ in range(10u, 0).invert() { + fail!("unreachable"); + } + } } diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 9842a570d7ea..b692bedebfd5 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -124,14 +124,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) range_step_core(start, last, step, Closed, it) } - -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T, it) -} - impl Num for $T {} #[cfg(not(test))] @@ -889,10 +881,6 @@ mod tests { fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -917,8 +905,7 @@ mod tests { l.push(i); true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -926,9 +913,6 @@ mod tests { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,10) |_i| { - fail!(~"unreachable"); - }; do range_step(10,0,1) |_i| { fail!(~"unreachable"); }; diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index a2874c967039..29b8f29d87d3 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -125,13 +125,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> range_step_core(start, last, step, Closed, it) } -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it) -} - impl Num for $T {} #[cfg(not(test))] @@ -654,10 +647,6 @@ mod tests { pub fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -683,8 +672,7 @@ mod tests { true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -692,9 +680,6 @@ mod tests { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,0) |_i| { - fail!("unreachable"); - }; do range_step(10,0,1) |_i| { fail!("unreachable"); }; diff --git a/src/libstd/run.rs b/src/libstd/run.rs index ef3d881c5fea..694aa672af7b 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -632,7 +632,6 @@ fn spawn_process_os(prog: &str, args: &[~str], use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; - use int; mod rustrt { use libc::c_void; @@ -665,10 +664,9 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); } // close all other fds - do int::range_rev(getdtablesize() as int, 3) |fd| { + for fd in range(3, getdtablesize()).invert() { close(fd as c_int); - true - }; + } do with_dirp(dir) |dirp| { if !dirp.is_null() && chdir(dirp) == -1 { diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index a5efae542a1f..5ef5526e5162 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -282,13 +282,14 @@ impl TrieNode { } fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - do uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx] { - Internal(ref x) => x.each_reverse(|i,t| f(i,t)), - External(k, ref v) => f(&k, v), - Nothing => true + for elt in self.children.rev_iter() { + match *elt { + 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 => () } } + true } fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { @@ -539,10 +540,9 @@ mod test_map { fn test_each_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 10000; do m.each |k, v| { @@ -580,10 +580,9 @@ mod test_map { fn test_each_reverse_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 1; do m.each_reverse |k, v| { @@ -634,10 +633,9 @@ mod test_map { let last = uint::max_value; let mut map = TrieMap::new(); - do uint::range_rev(last, first) |x| { + for x in range(first, last).invert() { map.insert(x, x / 2); - true - }; + } let mut i = 0; for (k, &v) in map.iter() { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index cf160ca31c6f..6475012e0097 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -53,24 +53,21 @@ fn descending>(map: &mut M, n_keys: uint) { io::println(" Descending integers:"); do timed("insert") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { map.insert(i, i + 1); - true - }; + } } do timed("search") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { assert_eq!(map.find(&i).unwrap(), &(i + 1)); - true - }; + } } do timed("remove") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys) { assert!(map.remove(&i)); - true - }; + } } } diff --git a/src/test/run-fail/assert-eq-macro-fail b/src/test/run-fail/assert-eq-macro-fail new file mode 100755 index 0000000000000000000000000000000000000000..2841756d4a0e10e1d852b1e651e62f7903f954ac GIT binary patch literal 104051 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 literal 0 HcmV?d00001 diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs index 5eecbe7e03af..ea7d4a651f75 100644 --- a/src/test/run-pass/num-range-rev.rs +++ b/src/test/run-pass/num-range-rev.rs @@ -20,11 +20,11 @@ fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool { } fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool { - uint::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool { - int::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool { From e99eff172a11816f335153147dd0800fc4877bee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 6 Aug 2013 23:03:31 -0700 Subject: [PATCH 24/48] Forbid `priv` where it has no effect This is everywhere except struct fields and enum variants. --- src/libextra/fileinput.rs | 14 +++++------ src/libextra/future.rs | 2 +- src/libextra/getopts.rs | 8 +++---- src/libextra/num/bigint.rs | 20 ++++++++-------- src/libextra/stats.rs | 2 +- src/libextra/term.rs | 4 ++-- src/libextra/terminfo/parm.rs | 12 +++++----- src/libextra/time.rs | 4 ++-- src/librustc/middle/typeck/rscope.rs | 2 +- src/libstd/comm.rs | 8 +++---- src/libstd/num/strconv.rs | 6 ++--- src/libstd/run.rs | 6 ++--- src/libstd/str.rs | 20 ++++++++-------- src/libstd/str/ascii.rs | 6 ++--- src/libsyntax/parse/obsolete.rs | 5 ++++ src/libsyntax/parse/parser.rs | 24 ++++++++++++++----- .../class-cast-to-trait-multiple-types.rs | 2 +- 17 files changed, 81 insertions(+), 64 deletions(-) diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index 7a36b25eac57..14b02688cffc 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -129,27 +129,27 @@ struct FileInput_ { `Some(path)` is the file represented by `path`, `None` is `stdin`. Consumed as the files are read. */ - priv files: ~[Option], + files: ~[Option], /** The current file: `Some(r)` for an open file, `None` before starting and after reading everything. */ - priv current_reader: Option<@io::Reader>, - priv state: FileInputState, + current_reader: Option<@io::Reader>, + state: FileInputState, /** Used to keep track of whether we need to insert the newline at the end of a file that is missing it, which is needed to separate the last and first lines. */ - priv previous_was_newline: bool + previous_was_newline: bool } // XXX: remove this when Reader has &mut self. Should be removable via // "self.fi." -> "self." and renaming FileInput_. Documentation above // will likely have to be updated to use `let mut in = ...`. pub struct FileInput { - priv fi: @mut FileInput_ + fi: @mut FileInput_ } impl FileInput { @@ -198,7 +198,7 @@ impl FileInput { FileInput::from_vec(pathed) } - priv fn current_file_eof(&self) -> bool { + fn current_file_eof(&self) -> bool { match self.fi.current_reader { None => false, Some(r) => r.eof() @@ -240,7 +240,7 @@ impl FileInput { Returns `true` if it had to move to the next file and did so successfully. */ - priv fn next_file_if_eof(&self) -> bool { + fn next_file_if_eof(&self) -> bool { match self.fi.current_reader { None => self.next_file(), Some(r) => { diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 7d2a0658969a..cc65c49d73a9 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -46,7 +46,7 @@ impl Drop for Future { fn drop(&self) {} } -priv enum FutureState { +enum FutureState { Pending(~fn() -> A), Evaluating, Forced(A) diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 15aac8ef47c9..8bd9d857d695 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -708,9 +708,9 @@ pub mod groups { * Fails during iteration if the string contains a non-whitespace * sequence longer than the limit. */ - priv fn each_split_within<'a>(ss: &'a str, - lim: uint, - it: &fn(&'a str) -> bool) -> bool { + fn each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) -> bool { // Just for fun, let's write this as an state machine: enum SplitWithinState { @@ -778,7 +778,7 @@ pub mod groups { } #[test] - priv fn test_split_within() { + fn test_split_within() { fn t(s: &str, i: uint, u: &[~str]) { let mut v = ~[]; do each_split_within(s, i) |s| { v.push(s.to_owned()); true }; diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index c3737d44e385..0c8701bd0b51 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -59,13 +59,13 @@ pub mod BigDigit { pub static bits: uint = 32; pub static base: uint = 1 << bits; - priv static hi_mask: uint = (-1 as uint) << bits; - priv static lo_mask: uint = (-1 as uint) >> bits; + static hi_mask: uint = (-1 as uint) << bits; + static lo_mask: uint = (-1 as uint) >> bits; - priv fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } + fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } - priv fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } + fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } /// Split one machine sized unsigned integer into two BigDigits. @@ -613,7 +613,7 @@ impl BigUint { } - priv fn shl_unit(&self, n_unit: uint) -> BigUint { + fn shl_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return (*self).clone(); } return BigUint::new(vec::from_elem(n_unit, ZERO_BIG_DIGIT) @@ -621,7 +621,7 @@ impl BigUint { } - priv fn shl_bits(&self, n_bits: uint) -> BigUint { + fn shl_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.is_zero() { return (*self).clone(); } let mut carry = 0; @@ -637,7 +637,7 @@ impl BigUint { } - priv fn shr_unit(&self, n_unit: uint) -> BigUint { + fn shr_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 { return (*self).clone(); } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( @@ -646,7 +646,7 @@ impl BigUint { } - priv fn shr_bits(&self, n_bits: uint) -> BigUint { + fn shr_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.data.is_empty() { return (*self).clone(); } let mut borrow = 0; @@ -661,7 +661,7 @@ impl BigUint { #[cfg(target_arch = "x86_64")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (4294967296, 32), @@ -687,7 +687,7 @@ priv fn get_radix_base(radix: uint) -> (uint, uint) { #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (65536, 16), diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 9238034cba33..881d931fe0ac 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -223,7 +223,7 @@ impl<'self> Stats for &'self [f64] { // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using // linear interpolation. If samples are not sorted, return nonsensical value. -priv fn percentile_of_sorted(sorted_samples: &[f64], +fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { assert!(sorted_samples.len() != 0); if sorted_samples.len() == 1 { diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 2173eb838e5e..d0412b8954db 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -75,7 +75,7 @@ pub mod attr { } #[cfg(not(target_os = "win32"))] -priv fn cap_for_attr(attr: attr::Attr) -> &'static str { +fn cap_for_attr(attr: attr::Attr) -> &'static str { match attr { attr::Bold => "bold", attr::Dim => "dim", @@ -234,7 +234,7 @@ impl Terminal { } } - priv fn dim_if_necessary(&self, color: color::Color) -> color::Color { + fn dim_if_necessary(&self, color: color::Color) -> color::Color { if color >= self.num_colors && color >= 8 && color < 16 { color-8 } else { color } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index b619e0f33b64..0929575ee9e7 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -430,7 +430,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } #[deriving(Eq)] -priv struct Flags { +struct Flags { width: uint, precision: uint, alternate: bool, @@ -440,13 +440,13 @@ priv struct Flags { } impl Flags { - priv fn new() -> Flags { + fn new() -> Flags { Flags{ width: 0, precision: 0, alternate: false, left: false, sign: false, space: false } } } -priv enum FormatOp { +enum FormatOp { FormatDigit, FormatOctal, FormatHex, @@ -455,7 +455,7 @@ priv enum FormatOp { } impl FormatOp { - priv fn from_char(c: char) -> FormatOp { + fn from_char(c: char) -> FormatOp { match c { 'd' => FormatDigit, 'o' => FormatOctal, @@ -465,7 +465,7 @@ impl FormatOp { _ => fail!("bad FormatOp char") } } - priv fn to_char(self) -> char { + fn to_char(self) -> char { match self { FormatDigit => 'd', FormatOctal => 'o', @@ -476,7 +476,7 @@ impl FormatOp { } } -priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { +fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { let mut s = match val { Number(d) => { match op { diff --git a/src/libextra/time.rs b/src/libextra/time.rs index efc3dc87adc0..f6a5fd98234b 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -254,7 +254,7 @@ impl Tm { } } -priv fn do_strptime(s: &str, format: &str) -> Result { +fn do_strptime(s: &str, format: &str) -> Result { fn match_str(s: &str, pos: uint, needle: &str) -> bool { let mut i = pos; for ch in needle.byte_iter() { @@ -687,7 +687,7 @@ priv fn do_strptime(s: &str, format: &str) -> Result { } } -priv fn do_strftime(format: &str, tm: &Tm) -> ~str { +fn do_strftime(format: &str, tm: &Tm) -> ~str { fn parse_type(ch: char, tm: &Tm) -> ~str { //FIXME (#2350): Implement missing types. let die = || fmt!("strftime: can't understand this format %c ", ch); diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index bbcf42b1c5d3..c9e2b8dd37b9 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -215,7 +215,7 @@ impl region_scope for MethodRscope { pub struct type_rscope(Option); impl type_rscope { - priv fn replacement(&self) -> ty::Region { + fn replacement(&self) -> ty::Region { if self.is_some() { ty::re_bound(ty::br_self) } else { diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 4356f1143da4..a4de10f8c776 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -314,7 +314,7 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod oneshot { - priv use std::kinds::Send; + use std::kinds::Send; use ptr::to_mut_unsafe_ptr; pub fn init() -> (server::Oneshot, client::Oneshot) { @@ -341,7 +341,7 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use std::kinds::Send; + use std::kinds::Send; #[allow(non_camel_case_types)] pub fn try_send(pipe: Oneshot, x_0: T) -> @@ -489,7 +489,7 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod streamp { - priv use std::kinds::Send; + use std::kinds::Send; pub fn init() -> (server::Open, client::Open) { pub use std::pipes::HasBuffer; @@ -501,7 +501,7 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use std::kinds::Send; + use std::kinds::Send; #[allow(non_camel_case_types)] pub fn try_data(pipe: Open, x_0: T) -> diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 7ab3c81b61f7..1f22343ad9c3 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -422,9 +422,9 @@ pub fn float_to_str_common(d: Option<&Path>, } #[cfg(windows)] -priv fn free_handle(handle: *()) { +fn free_handle(handle: *()) { unsafe { libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle)); } } #[cfg(unix)] -priv fn free_handle(_handle: *()) { +fn free_handle(_handle: *()) { // unix has no process handle object, just a pid } @@ -823,7 +823,7 @@ pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput { * operate on a none-existant process or, even worse, on a newer process * with the same id. */ -priv fn waitpid(pid: pid_t) -> int { +fn waitpid(pid: pid_t) -> int { return waitpid_os(pid); #[cfg(windows)] diff --git a/src/libstd/str.rs b/src/libstd/str.rs index c4bd2c5435a2..fa75916fb864 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -738,7 +738,7 @@ pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { } // https://tools.ietf.org/html/rfc3629 -priv static UTF8_CHAR_WIDTH: [u8, ..256] = [ +static UTF8_CHAR_WIDTH: [u8, ..256] = [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -781,15 +781,15 @@ macro_rules! utf8_acc_cont_byte( ) // UTF-8 tags and ranges -priv static TAG_CONT_U8: u8 = 128u8; -priv static TAG_CONT: uint = 128u; -priv static MAX_ONE_B: uint = 128u; -priv static TAG_TWO_B: uint = 192u; -priv static MAX_TWO_B: uint = 2048u; -priv static TAG_THREE_B: uint = 224u; -priv static MAX_THREE_B: uint = 65536u; -priv static TAG_FOUR_B: uint = 240u; -priv static MAX_UNICODE: uint = 1114112u; +static TAG_CONT_U8: u8 = 128u8; +static TAG_CONT: uint = 128u; +static MAX_ONE_B: uint = 128u; +static TAG_TWO_B: uint = 192u; +static MAX_TWO_B: uint = 2048u; +static TAG_THREE_B: uint = 224u; +static MAX_THREE_B: uint = 65536u; +static TAG_FOUR_B: uint = 240u; +static MAX_UNICODE: uint = 1114112u; /// Unsafe operations pub mod raw { diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index 1be4d07dfa47..6ededb02107d 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -274,7 +274,7 @@ pub fn to_ascii_lower(string: &str) -> ~str { } #[inline] -priv fn map_bytes(string: &str, map: &'static [u8]) -> ~str { +fn map_bytes(string: &str, map: &'static [u8]) -> ~str { let len = string.len(); let mut result = str::with_capacity(len); unsafe { @@ -298,7 +298,7 @@ pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool { |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b]) } -priv static ASCII_LOWER_MAP: &'static [u8] = &[ +static ASCII_LOWER_MAP: &'static [u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -333,7 +333,7 @@ priv static ASCII_LOWER_MAP: &'static [u8] = &[ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; -priv static ASCII_UPPER_MAP: &'static [u8] = &[ +static ASCII_UPPER_MAP: &'static [u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ec956f618637..dda5e990221e 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -64,6 +64,7 @@ pub enum ObsoleteSyntax { ObsoleteMutWithMultipleBindings, ObsoleteExternVisibility, ObsoleteUnsafeExternFn, + ObsoletePrivVisibility, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -253,6 +254,10 @@ impl ParserObsoleteMethods for Parser { "external functions are always unsafe; remove the `unsafe` \ keyword" ), + ObsoletePrivVisibility => ( + "`priv` not necessary", + "an item without a visibility qualifier is private by default" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4902c4587ac3..7d6dce22fb7b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -85,7 +85,7 @@ use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType}; use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl}; use parse::obsolete::{ObsoleteMutWithMultipleBindings}; use parse::obsolete::{ObsoleteExternVisibility, ObsoleteUnsafeExternFn}; -use parse::obsolete::{ParserObsoleteMethods}; +use parse::obsolete::{ParserObsoleteMethods, ObsoletePrivVisibility}; use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; use parse::token::{is_ident_or_path}; use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; @@ -814,7 +814,7 @@ impl Parser { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; - let vis = p.parse_visibility(); + let vis = p.parse_non_priv_visibility(); let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. @@ -3608,7 +3608,7 @@ impl Parser { let attrs = self.parse_outer_attributes(); let lo = self.span.lo; - let visa = self.parse_visibility(); + let visa = self.parse_non_priv_visibility(); let pur = self.parse_fn_purity(); let ident = self.parse_ident(); let generics = self.parse_generics(); @@ -3871,6 +3871,18 @@ impl Parser { else { inherited } } + // parse visibility, but emits an obsolete error if it's private + fn parse_non_priv_visibility(&self) -> visibility { + match self.parse_visibility() { + public => public, + inherited => inherited, + private => { + self.obsolete(*self.last_span, ObsoletePrivVisibility); + inherited + } + } + } + fn parse_staticness(&self) -> bool { if self.eat_keyword(keywords::Static) { self.obsolete(*self.last_span, ObsoleteStaticMethod); @@ -4063,7 +4075,7 @@ impl Parser { // parse a function declaration from a foreign module fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; - let vis = self.parse_visibility(); + let vis = self.parse_non_priv_visibility(); // Parse obsolete purity. let purity = self.parse_fn_purity(); @@ -4443,7 +4455,7 @@ impl Parser { maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); // must be a view item: if self.eat_keyword(keywords::Use) { @@ -4575,7 +4587,7 @@ impl Parser { maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); if (self.is_keyword(keywords::Const) || self.is_keyword(keywords::Static)) { // FOREIGN CONST ITEM diff --git a/src/test/run-pass/class-cast-to-trait-multiple-types.rs b/src/test/run-pass/class-cast-to-trait-multiple-types.rs index a5d7ba2c1aaa..a134ffe49fd0 100644 --- a/src/test/run-pass/class-cast-to-trait-multiple-types.rs +++ b/src/test/run-pass/class-cast-to-trait-multiple-types.rs @@ -21,7 +21,7 @@ struct dog { } impl dog { - priv fn bark(&self) -> int { + fn bark(&self) -> int { info!("Woof %u %d", *self.barks, *self.volume); *self.barks += 1u; if *self.barks % 3u == 0u { From a7f008bc3954223d3c6693389d82880a88dc407c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Aug 2013 14:34:58 +0200 Subject: [PATCH 25/48] Add missing getopts::groups::optflagmulti function --- src/libextra/getopts.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 8bd9d857d695..5ec6713509ec 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -542,6 +542,20 @@ pub mod groups { occur: Optional}; } + /// Create a long option that can occur more than once and does not + /// take an argument + pub fn optflagmulti(short_name: &str, long_name: &str, + desc: &str) -> OptGroup { + let len = short_name.len(); + assert!(len == 1 || len == 0); + return OptGroup {short_name: short_name.to_owned(), + long_name: long_name.to_owned(), + hint: ~"", + desc: desc.to_owned(), + hasarg: No, + occur: Multi}; + } + /// Create a long option that is optional and takes an optional argument pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { From a8f3f038c03eb1393110dfdb1e6bdf1be6a3fb62 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Aug 2013 14:37:54 +0200 Subject: [PATCH 26/48] Turn OptGroups into a main opt and a main and an aliased opts This way opt_present("apple") will match no matter if the user passed -a or --apple --- src/libextra/getopts.rs | 99 ++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 5ec6713509ec..1b65528923a1 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -114,7 +114,8 @@ pub enum Occur { pub struct Opt { name: Name, hasarg: HasArg, - occur: Occur + occur: Occur, + aliases: ~[Opt], } fn mkname(nm: &str) -> Name { @@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name { /// Create an option that is required and takes an argument pub fn reqopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Req}; + return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]}; } /// Create an option that is optional and takes an argument pub fn optopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Optional}; + return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]}; } /// Create an option that is optional and does not take an argument pub fn optflag(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Optional}; + return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]}; } /** Create an option that is optional, does not take an argument, * and may occur multiple times. */ pub fn optflagmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Multi}; + return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]}; } /// Create an option that is optional and takes an optional argument pub fn optflagopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Maybe, occur: Optional}; + return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]}; } /** @@ -157,7 +158,7 @@ pub fn optflagopt(name: &str) -> Opt { * multiple times */ pub fn optmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Multi}; + return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]}; } #[deriving(Clone, Eq)] @@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str { } fn find_opt(opts: &[Opt], nm: Name) -> Option { - opts.iter().position(|opt| opt.name == nm) + // search main options + let pos = opts.iter().position(|opt| opt.name == nm); + if pos.is_some() { + return pos + } + + // search in aliases + for candidate in opts.iter() { + if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { + return opts.iter().position(|opt| opt.name == candidate.name); + } + } + + None } /** @@ -488,8 +502,6 @@ pub mod groups { use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req}; use getopts::{Short, Yes}; - use std::vec; - /** one group of options, e.g., both -h and --help, along with * their shared description and properties */ @@ -587,7 +599,7 @@ pub mod groups { // translate OptGroup into Opt // (both short and long names correspond to different Opts) - pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { + pub fn long_to_short(lopt: &OptGroup) -> Opt { let OptGroup{short_name: short_name, long_name: long_name, hasarg: hasarg, @@ -595,24 +607,29 @@ pub mod groups { _} = (*lopt).clone(); match (short_name.len(), long_name.len()) { - (0,0) => fail!("this long-format option was given no name"), + (0,0) => fail!("this long-format option was given no name"), - (0,_) => ~[Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], + (0,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, - (1,0) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}], + (1,0) => Opt {name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, - (1,_) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}, - Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], + (1,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[Opt { + name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[] + }]}, - (_,_) => fail!("something is wrong with the long-form opt") + (_,_) => fail!("something is wrong with the long-form opt") } } @@ -620,7 +637,7 @@ pub mod groups { * Parse command line args with the provided long format options */ pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result { - ::getopts::getopts(args, vec::flat_map(opts, long_to_short)) + ::getopts::getopts(args, opts.map(long_to_short)) } /** @@ -1454,7 +1471,8 @@ mod tests { #[test] fn test_groups_long_to_short() { - let short = ~[reqopt("b"), reqopt("banana")]; + let mut short = reqopt("banana"); + short.aliases = ~[reqopt("b")]; let verbose = groups::reqopt("b", "banana", "some bananas", "VAL"); assert_eq!(groups::long_to_short(&verbose), short); @@ -1462,10 +1480,16 @@ mod tests { #[test] fn test_groups_getopts() { + let mut banana = reqopt("banana"); + banana.aliases = ~[reqopt("b")]; + let mut apple = optopt("apple"); + apple.aliases = ~[optopt("a")]; + let mut kiwi = optflag("kiwi"); + kiwi.aliases = ~[optflag("k")]; let short = ~[ - reqopt("b"), reqopt("banana"), - optopt("a"), optopt("apple"), - optflag("k"), optflagopt("kiwi"), + banana, + apple, + kiwi, optflagopt("p"), optmulti("l") ]; @@ -1478,7 +1502,7 @@ mod tests { groups::optmulti("l", "", "Desc", "VAL"), ]; - let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k", + let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k", ~"-p", ~"16", ~"l", ~"35"]; // FIXME #4681: sort options here? @@ -1486,6 +1510,19 @@ mod tests { == groups::getopts(sample_args, verbose)); } + #[test] + fn test_groups_aliases_long_and_short() { + let opts = ~[ + groups::optflagmulti("a", "apple", "Desc"), + ]; + + let args = ~[~"-a", ~"--apple", ~"-a"]; + + let matches = groups::getopts(args, opts).unwrap(); + assert_eq!(3, opt_count(&matches, "a")); + assert_eq!(3, opt_count(&matches, "apple")); + } + #[test] fn test_groups_usage() { let optgroups = ~[ From 9b221f56f1d9f923fad48b7e30f886acaeb3f741 Mon Sep 17 00:00:00 2001 From: darkf Date: Sun, 4 Aug 2013 22:28:53 -0700 Subject: [PATCH 27/48] add inflate_bytes_zlib to exra::flate --- src/libextra/flate.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 8024b9aa1596..5d5180c152b1 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -43,6 +43,7 @@ static LZ_NONE : c_int = 0x0; // Huffman-coding only. static LZ_FAST : c_int = 0x1; // LZ with only one probe static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best" +static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { do bytes.as_imm_buf |b, len| { @@ -62,7 +63,7 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { } } -pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { +fn inflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -70,7 +71,7 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tinfl_decompress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - 0); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -80,6 +81,14 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { } } +pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { + inflate_bytes_(bytes, 0) +} + +pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + inflate_bytes_(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) +} + #[cfg(test)] mod tests { use super::*; From dd5e8b218fb7a6f45beca1cddb0c19949307ea3d Mon Sep 17 00:00:00 2001 From: darkf Date: Sun, 4 Aug 2013 22:37:09 -0700 Subject: [PATCH 28/48] add extra::flate::deflate_bytes_zlib and a test --- src/libextra/flate.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 5d5180c152b1..c974148ee124 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -44,8 +44,9 @@ static LZ_FAST : c_int = 0x1; // LZ with only one probe static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum +static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { +fn deflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -53,7 +54,7 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tdefl_compress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - LZ_NORM); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -63,6 +64,14 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { } } +pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { + deflate_bytes_(bytes, LZ_NORM) +} + +pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + deflate_bytes_(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) +} + fn inflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { @@ -118,4 +127,12 @@ mod tests { assert_eq!(input, out); } } + + #[test] + fn test_zlib_flate() { + let bytes = ~[1, 2, 3, 4, 5]; + let deflated = deflate_bytes(bytes); + let inflated = inflate_bytes(deflated); + assert_eq!(inflated, bytes); + } } From cc160a00285b2856610b31004eee7704ca0806d1 Mon Sep 17 00:00:00 2001 From: darkf Date: Mon, 5 Aug 2013 06:06:43 -0700 Subject: [PATCH 29/48] extra: add `internal` to {de,in}flate_bytes_ naming to address nit --- src/libextra/flate.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index c974148ee124..ed8cbcd0663f 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -46,7 +46,7 @@ static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -65,14 +65,14 @@ fn deflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { } pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { - deflate_bytes_(bytes, LZ_NORM) + deflate_bytes_internal(bytes, LZ_NORM) } pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { - deflate_bytes_(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) + deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -91,11 +91,11 @@ fn inflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] { } pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { - inflate_bytes_(bytes, 0) + inflate_bytes_internal(bytes, 0) } pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { - inflate_bytes_(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) + inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } #[cfg(test)] From ffd80aa276224c8343d3f8b0942c7497b16df10f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 7 Aug 2013 11:52:33 -0700 Subject: [PATCH 30/48] Fix unit structs in cross-crate situtations --- src/librustc/middle/resolve.rs | 7 +++-- src/test/auxiliary/xcrate_unit_struct.rs | 31 ++++++++++++++++++ src/test/compile-fail/xcrate-unit-struct.rs | 21 +++++++++++++ src/test/run-pass/xcrate-unit-struct.rs | 35 +++++++++++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/test/auxiliary/xcrate_unit_struct.rs create mode 100644 src/test/compile-fail/xcrate-unit-struct.rs create mode 100644 src/test/run-pass/xcrate-unit-struct.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index da0ba1558c9b..f55fdd22c9a9 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -13,7 +13,7 @@ use driver::session::Session; use metadata::csearch::{each_path, get_trait_method_def_ids}; use metadata::csearch::get_method_name_and_explicit_self; use metadata::csearch::get_static_methods_if_impl; -use metadata::csearch::get_type_name_if_impl; +use metadata::csearch::{get_type_name_if_impl, get_struct_fields}; use metadata::cstore::find_extern_mod_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; @@ -1700,9 +1700,12 @@ impl Resolver { } def_struct(def_id) => { debug!("(building reduced graph for external \ - crate) building type %s", + crate) building type and value for %s", final_ident); child_name_bindings.define_type(privacy, def, dummy_sp()); + if get_struct_fields(self.session.cstore, def_id).len() == 0 { + child_name_bindings.define_value(privacy, def, dummy_sp()); + } self.structs.insert(def_id); } def_method(*) => { diff --git a/src/test/auxiliary/xcrate_unit_struct.rs b/src/test/auxiliary/xcrate_unit_struct.rs new file mode 100644 index 000000000000..a72bf307e5dd --- /dev/null +++ b/src/test/auxiliary/xcrate_unit_struct.rs @@ -0,0 +1,31 @@ +// 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. + +#[crate_type = "lib"]; + +// used by the rpass test + +pub struct Struct; + +pub enum Unit { + Unit, + Argument(Struct) +} + +// used by the cfail test + +pub struct StructWithFields { + foo: int, +} + +pub enum EnumWithVariants { + EnumVariant, + EnumVariantArg(int) +} diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs new file mode 100644 index 000000000000..e71a0f05dffc --- /dev/null +++ b/src/test/compile-fail/xcrate-unit-struct.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs + +// Make sure that when we have cross-crate unit structs we don't accidentally +// make values out of cross-crate structs that aren't unit. + +extern mod xcrate_unit_struct; + +fn main() { + let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name + let _ = xcrate_unit_struct::Struct; +} diff --git a/src/test/run-pass/xcrate-unit-struct.rs b/src/test/run-pass/xcrate-unit-struct.rs new file mode 100644 index 000000000000..58676f7cd70e --- /dev/null +++ b/src/test/run-pass/xcrate-unit-struct.rs @@ -0,0 +1,35 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs + +extern mod xcrate_unit_struct; + +use std::util; + +static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct; +static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit; +static s3: xcrate_unit_struct::Unit = + xcrate_unit_struct::Argument(xcrate_unit_struct::Struct); +static s4: xcrate_unit_struct::Unit = xcrate_unit_struct::Argument(s1); + +fn f1(_: xcrate_unit_struct::Struct) {} +fn f2(_: xcrate_unit_struct::Unit) {} + +fn main() { + f1(xcrate_unit_struct::Struct); + f2(xcrate_unit_struct::Unit); + f2(xcrate_unit_struct::Argument(xcrate_unit_struct::Struct)); + + f1(s1); + f2(s2); + f2(s3); + f2(s4); +} From 19d0eb90600f1b643025b99b8a2ea204e4d08034 Mon Sep 17 00:00:00 2001 From: Sangeun Kim Date: Wed, 7 Aug 2013 16:44:42 +0900 Subject: [PATCH 31/48] Change Freeze to Static --- src/librustdoc/markdown_pass.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index f05c59083f40..beebe71faae2 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -150,8 +150,8 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str { doc::FnTag(_) => { ~"Function" } - doc::ConstTag(_) => { - ~"Freeze" + doc::StaticTag(_) => { + ~"Static" } doc::EnumTag(_) => { ~"Enum" @@ -777,7 +777,7 @@ mod test { #[test] fn should_write_const_header() { let markdown = render(~"static a: bool = true;"); - assert!(markdown.contains("## Freeze `a`\n\n")); + assert!(markdown.contains("## Static `a`\n\n")); } #[test] From a9b7bec2e7f005431c7424a59095ccda33484bb1 Mon Sep 17 00:00:00 2001 From: Sangeun Kim Date: Wed, 7 Aug 2013 16:47:21 +0900 Subject: [PATCH 32/48] Change const to static --- src/librustdoc/doc.rs | 16 +++++++-------- src/librustdoc/extract.rs | 12 ++++++------ src/librustdoc/fold.rs | 28 +++++++++++++-------------- src/librustdoc/markdown_pass.rs | 10 +++++----- src/librustdoc/sort_item_type_pass.rs | 6 +++--- src/librustdoc/tystr_pass.rs | 14 +++++++------- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index d24fd1f5bfe5..aba7ea1f0d75 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -54,7 +54,7 @@ pub struct CrateDoc { pub enum ItemTag { ModTag(ModDoc), NmodTag(NmodDoc), - ConstTag(ConstDoc), + StaticTag(StaticDoc), FnTag(FnDoc), EnumTag(EnumDoc), TraitTag(TraitDoc), @@ -95,7 +95,7 @@ pub struct NmodDoc { index: Option } -pub type ConstDoc = SimpleItemDoc; +pub type StaticDoc = SimpleItemDoc; pub type FnDoc = SimpleItemDoc; @@ -214,8 +214,8 @@ impl ModDoc { md!(FnTag) } - pub fn consts(&self) -> ~[ConstDoc] { - md!(ConstTag) + pub fn statics(&self) -> ~[StaticDoc] { + md!(StaticTag) } pub fn enums(&self) -> ~[EnumDoc] { @@ -249,7 +249,7 @@ pub trait PageUtils { fn mods(&self) -> ~[ModDoc]; fn nmods(&self) -> ~[NmodDoc]; fn fns(&self) -> ~[FnDoc]; - fn consts(&self) -> ~[ConstDoc]; + fn statics(&self) -> ~[StaticDoc]; fn enums(&self) -> ~[EnumDoc]; fn traits(&self) -> ~[TraitDoc]; fn impls(&self) -> ~[ImplDoc]; @@ -270,8 +270,8 @@ impl PageUtils for ~[Page] { pu!(FnTag) } - fn consts(&self) -> ~[ConstDoc] { - pu!(ConstTag) + fn statics(&self) -> ~[StaticDoc] { + pu!(StaticTag) } fn enums(&self) -> ~[EnumDoc] { @@ -301,7 +301,7 @@ impl Item for ItemTag { &doc::ModTag(ref doc) => doc.item.clone(), &doc::NmodTag(ref doc) => doc.item.clone(), &doc::FnTag(ref doc) => doc.item.clone(), - &doc::ConstTag(ref doc) => doc.item.clone(), + &doc::StaticTag(ref doc) => doc.item.clone(), &doc::EnumTag(ref doc) => doc.item.clone(), &doc::TraitTag(ref doc) => doc.item.clone(), &doc::ImplTag(ref doc) => doc.item.clone(), diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index f849cfade9bd..2cab62296a4d 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -101,8 +101,8 @@ fn moddoc_from_mod( )) } ast::item_static(*) => { - Some(doc::ConstTag( - constdoc_from_const(ItemDoc) + Some(doc::StaticTag( + staticdoc_from_static(ItemDoc) )) } ast::item_enum(enum_definition, _) => { @@ -165,7 +165,7 @@ fn fndoc_from_fn(itemdoc: doc::ItemDoc) -> doc::FnDoc { } } -fn constdoc_from_const(itemdoc: doc::ItemDoc) -> doc::ConstDoc { +fn staticdoc_from_static(itemdoc: doc::ItemDoc) -> doc::StaticDoc { doc::SimpleItemDoc { item: itemdoc, sig: None @@ -356,10 +356,10 @@ mod test { } #[test] - fn should_extract_const_name_and_id() { + fn should_extract_static_name_and_id() { let doc = mk_doc(@"static a: int = 0;"); - assert!(doc.cratemod().consts()[0].id() != 0); - assert!(doc.cratemod().consts()[0].name_() == ~"a"); + assert!(doc.cratemod().statics()[0].id() != 0); + assert!(doc.cratemod().statics()[0].name_() == ~"a"); } #[test] diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ad0dabdc3a4b..589232f6e2f2 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -21,7 +21,7 @@ pub struct Fold { fold_mod: FoldMod, fold_nmod: FoldNmod, fold_fn: FoldFn, - fold_const: FoldConst, + fold_static: FoldStatic, fold_enum: FoldEnum, fold_trait: FoldTrait, fold_impl: FoldImpl, @@ -39,7 +39,7 @@ impl Clone for Fold { fold_mod: self.fold_mod, fold_nmod: self.fold_nmod, fold_fn: self.fold_fn, - fold_const: self.fold_const, + fold_static: self.fold_static, fold_enum: self.fold_enum, fold_trait: self.fold_trait, fold_impl: self.fold_impl, @@ -55,7 +55,7 @@ type FoldItem = @fn(fold: &Fold, doc: doc::ItemDoc) -> doc::ItemDoc; type FoldMod = @fn(fold: &Fold, doc: doc::ModDoc) -> doc::ModDoc; type FoldNmod = @fn(fold: &Fold, doc: doc::NmodDoc) -> doc::NmodDoc; type FoldFn = @fn(fold: &Fold, doc: doc::FnDoc) -> doc::FnDoc; -type FoldConst = @fn(fold: &Fold, doc: doc::ConstDoc) -> doc::ConstDoc; +type FoldStatic = @fn(fold: &Fold, doc: doc::StaticDoc) -> doc::StaticDoc; type FoldEnum = @fn(fold: &Fold, doc: doc::EnumDoc) -> doc::EnumDoc; type FoldTrait = @fn(fold: &Fold, doc: doc::TraitDoc) -> doc::TraitDoc; type FoldImpl = @fn(fold: &Fold, doc: doc::ImplDoc) -> doc::ImplDoc; @@ -73,7 +73,7 @@ fn mk_fold( fold_mod: FoldMod, fold_nmod: FoldNmod, fold_fn: FoldFn, - fold_const: FoldConst, + fold_static: FoldStatic, fold_enum: FoldEnum, fold_trait: FoldTrait, fold_impl: FoldImpl, @@ -88,7 +88,7 @@ fn mk_fold( fold_mod: fold_mod, fold_nmod: fold_nmod, fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -106,7 +106,7 @@ pub fn default_any_fold(ctxt: T) -> Fold { |f, d| default_any_fold_mod(f, d), |f, d| default_any_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -124,7 +124,7 @@ pub fn default_seq_fold(ctxt: T) -> Fold { |f, d| default_seq_fold_mod(f, d), |f, d| default_seq_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -142,7 +142,7 @@ pub fn default_par_fold(ctxt: T) -> Fold { |f, d| default_par_fold_mod(f, d), |f, d| default_par_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -272,8 +272,8 @@ pub fn fold_ItemTag(fold: &Fold, doc: doc::ItemTag) -> doc::ItemTag { doc::FnTag(FnDoc) => { doc::FnTag((fold.fold_fn)(fold, FnDoc)) } - doc::ConstTag(ConstDoc) => { - doc::ConstTag((fold.fold_const)(fold, ConstDoc)) + doc::StaticTag(StaticDoc) => { + doc::StaticTag((fold.fold_static)(fold, StaticDoc)) } doc::EnumTag(EnumDoc) => { doc::EnumTag((fold.fold_enum)(fold, EnumDoc)) @@ -303,10 +303,10 @@ pub fn default_seq_fold_fn( } } -pub fn default_seq_fold_const( +pub fn default_seq_fold_static( fold: &Fold, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item.clone()), .. doc @@ -374,7 +374,7 @@ fn default_fold_should_produce_same_doc() { } #[test] -fn default_fold_should_produce_same_consts() { +fn default_fold_should_produce_same_statics() { let source = @"static a: int = 0;"; let ast = parse::from_str(source); let doc = extract::extract(ast, ~""); diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index beebe71faae2..7d07b4864f50 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -321,7 +321,7 @@ fn write_item_(ctxt: &Ctxt, doc: doc::ItemTag, write_header: bool) { doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc), doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc), doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc), - doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc), + doc::StaticTag(StaticDoc) => write_static(ctxt, StaticDoc), doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc), doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc), doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc), @@ -409,9 +409,9 @@ fn code_block(s: ~str) -> ~str { ~~~", s) } -fn write_const( +fn write_static( ctxt: &Ctxt, - doc: doc::ConstDoc + doc: doc::StaticDoc ) { write_sig(ctxt, doc.sig.clone()); write_common(ctxt, doc.desc(), doc.sections()); @@ -775,13 +775,13 @@ mod test { } #[test] - fn should_write_const_header() { + fn should_write_static_header() { let markdown = render(~"static a: bool = true;"); assert!(markdown.contains("## Static `a`\n\n")); } #[test] - fn should_write_const_description() { + fn should_write_static_description() { let markdown = render( ~"#[doc = \"b\"]\ static a: bool = true;"); diff --git a/src/librustdoc/sort_item_type_pass.rs b/src/librustdoc/sort_item_type_pass.rs index 366cc83df272..ba8f37601fd5 100644 --- a/src/librustdoc/sort_item_type_pass.rs +++ b/src/librustdoc/sort_item_type_pass.rs @@ -18,7 +18,7 @@ pub fn mk_pass() -> Pass { fn by_score(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool { fn score(item: &doc::ItemTag) -> int { match *item { - doc::ConstTag(_) => 0, + doc::StaticTag(_) => 0, doc::TyTag(_) => 1, doc::EnumTag(_) => 2, doc::StructTag(_) => 3, @@ -43,7 +43,7 @@ fn test() { let source = ~"mod imod { } \ - static iconst: int = 0; \ + static istatic: int = 0; \ fn ifn() { } \ enum ienum { ivar } \ trait itrait { fn a(); } \ @@ -54,7 +54,7 @@ fn test() { let doc = extract::from_srv(srv.clone(), ~""); let doc = (mk_pass().f)(srv.clone(), doc); // hidden __std_macros module at the start. - assert_eq!(doc.cratemod().items[0].name_(), ~"iconst"); + assert_eq!(doc.cratemod().items[0].name_(), ~"istatic"); assert_eq!(doc.cratemod().items[1].name_(), ~"itype"); assert_eq!(doc.cratemod().items[2].name_(), ~"ienum"); assert_eq!(doc.cratemod().items[3].name_(), ~"istruct"); diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 0d7ec34243da..196c7e892a88 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -39,7 +39,7 @@ pub fn run( let fold = Fold { ctxt: srv.clone(), fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -93,10 +93,10 @@ fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> { } } -fn fold_const( +fn fold_static( fold: &fold::Fold, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { let srv = fold.ctxt.clone(); doc::SimpleItemDoc { @@ -109,7 +109,7 @@ fn fold_const( }, _) => { pprust::ty_to_str(ty, extract::interner()) } - _ => fail!("fold_const: id not bound to a const item") + _ => fail!("fold_static: id not bound to a static item") } }}), .. doc @@ -384,9 +384,9 @@ mod test { } #[test] - fn should_add_const_types() { + fn should_add_static_types() { let doc = mk_doc(~"static a: bool = true;"); - assert!(doc.cratemod().consts()[0].sig == Some(~"bool")); + assert!(doc.cratemod().statics()[0].sig == Some(~"bool")); } #[test] From 3db9dc1dfd8038862b06b712ece75fd7d17339af Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Aug 2013 22:13:26 +0200 Subject: [PATCH 33/48] Document rand module with more emphasis on cryptographic security --- src/libstd/rand.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 4ef524d77152..4408e5e1f275 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -610,6 +610,11 @@ impl RngUtil for R { } /// Create a random number generator with a default algorithm and seed. +/// +/// It returns the cryptographically-safest `Rng` algorithm currently +/// available in Rust. If you require a specifically seeded `Rng` for +/// consistency over time you should pick one algorithm and create the +/// `Rng` yourself. pub fn rng() -> IsaacRng { IsaacRng::new() } @@ -619,6 +624,8 @@ static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; /// A random number generator that uses the [ISAAC /// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). +/// +/// The ISAAC algorithm is suitable for cryptographic purposes. pub struct IsaacRng { priv cnt: u32, priv rsl: [u32, .. RAND_SIZE], @@ -794,8 +801,11 @@ impl Rng for IsaacRng { } /// An [Xorshift random number -/// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for -/// cryptographic purposes. +/// generator](http://en.wikipedia.org/wiki/Xorshift). +/// +/// The Xorshift algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `IsaacRng`. pub struct XorShiftRng { priv x: u32, priv y: u32, From 403c52d2ae1a59dea1a3b04ad794a66bd687d067 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Aug 2013 22:14:32 +0200 Subject: [PATCH 34/48] Add weak_rng to get a random algo that puts more emphasis on speed than security --- src/libstd/rand.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 4408e5e1f275..5f8fa9fddbcf 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -619,6 +619,16 @@ pub fn rng() -> IsaacRng { IsaacRng::new() } +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fatest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +pub fn weak_rng() -> XorShiftRng { + XorShiftRng::new() +} + static RAND_SIZE_LEN: u32 = 8; static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; From 1b103912eaacef82dfee940a3c3e8ecb693417bc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Aug 2013 19:16:29 -0700 Subject: [PATCH 35/48] Add some documentation about globals in ffi docs --- doc/tutorial-ffi.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 047b57e56a61..d1aa793e5fc1 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -228,6 +228,48 @@ unsafe fn kaboom(ptr: *int) -> int { *ptr } This function can only be called from an `unsafe` block or another `unsafe` function. +# Accessing foreign globals + +Foreign APIs often export a global variable which could do something like track +global state. In order to access these variables, you declare them in `extern` +blocks with the `static` keyword: + +~~~{.xfail-test} +use std::libc; + +#[link_args = "-lreadline"] +extern { + static rl_readline_version: libc::c_int; +} + +fn main() { + println(fmt!("You have readline version %d installed.", + rl_readline_version as int)); +} +~~~ + +Alternatively, you may need to alter global state provided by a foreign +interface. To do this, statics can be declared with `mut` so rust can mutate +them. + +~~~{.xfail-test} +use std::libc; +use std::ptr; + +#[link_args = "-lreadline"] +extern { + static mut rl_prompt: *libc::c_char; +} + +fn main() { + do "[my-awesome-shell] $".as_c_str |buf| { + unsafe { rl_prompt = buf; } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } + } +} +~~~ + # Foreign calling conventions Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when From a185343fc42646b84db32391096e096cb1acba46 Mon Sep 17 00:00:00 2001 From: Do Nhat Minh Date: Tue, 6 Aug 2013 11:04:58 +0800 Subject: [PATCH 36/48] misc help message fix --- src/librustc/rustc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 222433787f0a..bf9808c1ae44 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -136,7 +136,7 @@ Additional help: pub fn describe_warnings() { use extra::sort::Sort; - printfln!(" + println(" Available lint options: -W Warn about -A Allow @@ -157,7 +157,7 @@ Available lint options: fn padded(max: uint, s: &str) -> ~str { str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s } - printfln!("\nAvailable lint checks:\n"); + println("\nAvailable lint checks:\n"); printfln!(" %s %7.7s %s", padded(max_key, "name"), "default", "meaning"); printfln!(" %s %7.7s %s\n", @@ -173,7 +173,7 @@ Available lint options: } pub fn describe_debug_flags() { - printfln!("\nAvailable debug options:\n"); + println("\nAvailable debug options:\n"); let r = session::debugging_opts_map(); for tuple in r.iter() { match *tuple { From 8460dac909fc10b6bf0216d0123735c283cc1391 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 6 Aug 2013 22:19:33 +1000 Subject: [PATCH 37/48] std: add missing #[inline] annotation to the f64 arithmetic trait impls. --- src/libstd/num/f64.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index c7db60e6fd26..60527905779f 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -278,18 +278,22 @@ impl One for f64 { #[cfg(not(test))] impl Add for f64 { + #[inline] fn add(&self, other: &f64) -> f64 { *self + *other } } #[cfg(not(test))] impl Sub for f64 { + #[inline] fn sub(&self, other: &f64) -> f64 { *self - *other } } #[cfg(not(test))] impl Mul for f64 { + #[inline] fn mul(&self, other: &f64) -> f64 { *self * *other } } #[cfg(not(test))] impl Div for f64 { + #[inline] fn div(&self, other: &f64) -> f64 { *self / *other } } #[cfg(not(test))] From 240f8f03c9da7e574fd0fce0eb72e6ade97628ff Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 6 Aug 2013 20:31:35 +0100 Subject: [PATCH 38/48] Gedit/gtksourceview language spec: add 'in' keyword --- src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang index a6415beab36c..b1180098bd2a 100644 --- a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang +++ b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang @@ -50,6 +50,7 @@ for if impl + in let log loop From 4ab05f91f49b1248aab7d21630cfb38d6dafacfa Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Tue, 6 Aug 2013 17:27:39 +0200 Subject: [PATCH 39/48] extra: Simplify Eq/Ord in treemap Write the Eq and Ord impls for TreeMap in a more straightforward way using iterator::Zip --- src/libextra/treemap.rs | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index ab7d47255dac..2e20752754a2 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -42,39 +42,23 @@ pub struct TreeMap { impl Eq for TreeMap { fn eq(&self, other: &TreeMap) -> bool { - if self.len() != other.len() { - false - } else { - let mut x = self.iter(); - let mut y = other.iter(); - for _ in range(0u, self.len()) { - if x.next().unwrap() != y.next().unwrap() { - return false - } - } - true - } + self.len() == other.len() && + self.iter().zip(other.iter()).all(|(a, b)| a == b) } - fn ne(&self, other: &TreeMap) -> bool { !self.eq(other) } } // Lexicographical comparison fn lt(a: &TreeMap, b: &TreeMap) -> bool { - let mut x = a.iter(); - let mut y = b.iter(); - - let (a_len, b_len) = (a.len(), b.len()); - for _ in range(0u, num::min(a_len, b_len)) { - let (key_a, value_a) = x.next().unwrap(); - let (key_b, value_b) = y.next().unwrap(); + // the Zip iterator is as long as the shortest of a and b. + for ((key_a, value_a), (key_b, value_b)) in a.iter().zip(b.iter()) { if *key_a < *key_b { return true; } if *key_a > *key_b { return false; } if *value_a < *value_b { return true; } if *value_a > *value_b { return false; } } - a_len < b_len + a.len() < b.len() } impl Ord for TreeMap { From 52b01c50cbf001e383fb20bde313f6e58ee6f601 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Tue, 6 Aug 2013 20:17:06 +0200 Subject: [PATCH 40/48] extra: External iterators for TreeSet set operations Write external iterators for Difference, Sym. Difference, Intersection and Union set operations. These iterators are generic insofar that they could work on any ordered sequence iterators, even though they are type specialized to the TreeSetIterator in this case. Looking at the `check` function in the treeset tests, rustc seems unwilling to compile a function resembling:: fn check<'a, T: Iterator<&'a int>>(... ) so the tests for these iterators are still running the legacy loop protocol. --- src/libextra/treemap.rs | 274 +++++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 127 deletions(-) diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 2e20752754a2..051587a74f96 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -433,20 +433,7 @@ impl Set for TreeSet { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &TreeSet) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - match a1.cmp(b1) { - Less => a = x.next(), - Greater => b = y.next(), - Equal => return false - } - } - true + self.intersection(other).next().is_none() } /// Return true if the set is a subset of another @@ -526,124 +513,25 @@ impl TreeSet { } /// Visit the values (in-order) representing the difference - pub fn difference(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Equal { a = x.next() } - b = y.next(); - } - } - return true; + pub fn difference<'a>(&'a self, other: &'a TreeSet) -> Difference<'a, T> { + Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } /// Visit the values (in-order) representing the symmetric difference - pub fn symmetric_difference(&self, other: &TreeSet, - f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Greater { - if !f(b1) { return false; } - } else { - a = x.next(); - } - b = y.next(); - } - } - b.iter().advance(|&x| f(x)) && y.advance(f) + pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet) + -> SymDifference<'a, T> { + SymDifference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } /// Visit the values (in-order) representing the intersection - pub fn intersection(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Less { - a = x.next(); - } else { - if cmp == Equal { - if !f(a1) { return false } - } - b = y.next(); - } - } - return true; + pub fn intersection<'a>(&'a self, other: &'a TreeSet) + -> Intersection<'a, T> { + Intersection{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } /// Visit the values (in-order) representing the union - pub fn union(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Greater { - if !f(b1) { return false; } - b = y.next(); - } else { - if !f(a1) { return false; } - if cmp == Equal { - b = y.next(); - } - a = x.next(); - } - } - b.iter().advance(|&x| f(x)) && y.advance(f) + pub fn union<'a>(&'a self, other: &'a TreeSet) -> Union<'a, T> { + Union{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } } @@ -652,6 +540,138 @@ pub struct TreeSetIterator<'self, T> { priv iter: TreeMapIterator<'self, T, ()> } +// Encapsulate an iterator and hold its latest value until stepped forward +struct Focus { + priv iter: T, + priv focus: Option, +} + +impl> Focus { + fn new(mut it: T) -> Focus { + Focus{focus: it.next(), iter: it} + } + fn step(&mut self) { + self.focus = self.iter.next() + } +} + +/// Lazy iterator producing elements in the set difference (in-order) +pub struct Difference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} + +/// Lazy iterator producing elements in the set symmetric difference (in-order) +pub struct SymDifference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} + +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Intersection<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} + +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Union<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} + +impl<'self, T: TotalOrd> Iterator<&'self T> for Difference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (ret , None ) => { self.a.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + if cmp == Equal { self.a.step() } + self.b.step(); + } + } + } + } + } +} + +impl<'self, T: TotalOrd> Iterator<&'self T> for SymDifference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None ) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + self.b.step(); + if cmp == Greater { + return Some(b1); + } else { + self.a.step(); + } + } + } + } + } + } +} + +impl<'self, T: TotalOrd> Iterator<&'self T> for Intersection<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (_ , None ) => return None, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + } else { + self.b.step(); + if cmp == Equal { + return Some(a1); + } + } + }, + } + } + } +} + +impl<'self, T: TotalOrd> Iterator<&'self T> for Union<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Greater { + self.b.step(); + return Some(b1); + } else { + self.a.step(); + if cmp == Equal { + self.b.step(); + } + return Some(a1); + } + } + } + } + } +} + + // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. #[deriving(Clone)] @@ -1426,7 +1446,7 @@ mod test_set { #[test] fn test_intersection() { fn check_intersection(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.intersection(y, z)) + check(a, b, expected, |x, y, f| x.intersection(y).advance(f)) } check_intersection([], [], []); @@ -1442,7 +1462,7 @@ mod test_set { #[test] fn test_difference() { fn check_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.difference(y, z)) + check(a, b, expected, |x, y, f| x.difference(y).advance(f)) } check_difference([], [], []); @@ -1460,7 +1480,7 @@ mod test_set { fn test_symmetric_difference() { fn check_symmetric_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.symmetric_difference(y, z)) + check(a, b, expected, |x, y, f| x.symmetric_difference(y).advance(f)) } check_symmetric_difference([], [], []); @@ -1475,7 +1495,7 @@ mod test_set { fn test_union() { fn check_union(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.union(y, z)) + check(a, b, expected, |x, y, f| x.union(y).advance(f)) } check_union([], [], []); From 7afface3fffc09e8872569199ba902cf8a3170cb Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Tue, 6 Aug 2013 21:57:46 +0200 Subject: [PATCH 41/48] extra: Implement .rev_iter() in treemap Implement reverse iterators for TreeMap and TreeSet, that produce the keys in backward order. --- src/libextra/treemap.rs | 81 ++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 051587a74f96..989f7a419bba 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -13,7 +13,6 @@ //! `TotalOrd`. -use std::num; use std::util::{swap, replace}; use std::iterator::{FromIterator, Extendable}; @@ -152,7 +151,7 @@ impl TreeMap { /// Visit all key-value pairs in reverse order pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { - each_reverse(&self.root, f) + self.rev_iter().advance(|(k,v)| f(k, v)) } /// Visit all keys in reverse order @@ -176,6 +175,12 @@ impl TreeMap { } } + /// Get a lazy reverse iterator over the key-value pairs in the map. + /// Requires that it be frozen (immutable). + pub fn rev_iter<'a>(&'a self) -> TreeMapRevIterator<'a, K, V> { + TreeMapRevIterator{iter: self.iter()} + } + /// Get a lazy iterator that should be initialized using /// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`. fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -254,20 +259,18 @@ pub struct TreeMapIterator<'self, K, V> { priv remaining_max: uint } -impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { - /// Advance the iterator to the next node (in order) and return a - /// tuple with a reference to the key and value. If there are no - /// more nodes, return `None`. - fn next(&mut self) -> Option<(&'self K, &'self V)> { +impl<'self, K, V> TreeMapIterator<'self, K, V> { + #[inline(always)] + fn next_(&mut self, forward: bool) -> Option<(&'self K, &'self V)> { while !self.stack.is_empty() || self.node.is_some() { match *self.node { Some(ref x) => { self.stack.push(x); - self.node = &x.left; + self.node = if forward { &x.left } else { &x.right }; } None => { let res = self.stack.pop(); - self.node = &res.right; + self.node = if forward { &res.right } else { &res.left }; self.remaining_max -= 1; if self.remaining_min > 0 { self.remaining_min -= 1; @@ -278,6 +281,15 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V } None } +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.next_(true) + } #[inline] fn size_hint(&self) -> (uint, Option) { @@ -285,6 +297,25 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V } } +/// Lazy backward iterator over a map +pub struct TreeMapRevIterator<'self, K, V> { + priv iter: TreeMapIterator<'self, K, V>, +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapRevIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.iter.next_(false) + } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + self.iter.size_hint() + } +} + /// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to /// initialize TreeMapIterator pointing to element inside tree structure. /// @@ -382,6 +413,14 @@ impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> { } } +impl<'self, T> Iterator<&'self T> for TreeSetRevIterator<'self, T> { + /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. + #[inline] + fn next(&mut self) -> Option<&'self T> { + do self.iter.next().map |&(value, _)| { value } + } +} + /// A implementation of the `Set` trait on top of the `TreeMap` container. The /// only requirement is that the type of the elements contained ascribes to the /// `TotalOrd` trait. @@ -492,6 +531,13 @@ impl TreeSet { TreeSetIterator{iter: self.map.iter()} } + /// Get a lazy iterator over the values in the set. + /// Requires that it be frozen (immutable). + #[inline] + pub fn rev_iter<'a>(&'a self) -> TreeSetRevIterator<'a, T> { + TreeSetRevIterator{iter: self.map.rev_iter()} + } + /// Get a lazy iterator pointing to the first value not less than `v` (greater or equal). /// If all elements in the set are less than `v` empty iterator is returned. #[inline] @@ -540,6 +586,11 @@ pub struct TreeSetIterator<'self, T> { priv iter: TreeMapIterator<'self, T, ()> } +/// Lazy backward iterator over a set +pub struct TreeSetRevIterator<'self, T> { + priv iter: TreeMapRevIterator<'self, T, ()> +} + // Encapsulate an iterator and hold its latest value until stepped forward struct Focus { priv iter: T, @@ -691,18 +742,6 @@ impl TreeNode { } } -fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) && - each(&x.right, |k,v| f(k,v))) -} - -fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) && - each_reverse(&x.left, |k,v| f(k,v))) -} - fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, f: &fn(&'r K, &'r mut V) -> bool) -> bool { From 898226f39a5fcc4479899e9b90f616eb77d387b7 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Tue, 6 Aug 2013 22:53:51 +0200 Subject: [PATCH 42/48] extra: Remove all each_* methods in treemap .each_key(), .each_value() and the other methods are replaced by .iter() and .rev_iter(), and restrictions of those iterators. --- src/libextra/treemap.rs | 45 ++++++----------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 989f7a419bba..4d898dfb2b4f 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -134,36 +134,11 @@ impl TreeMap { /// Create an empty TreeMap pub fn new() -> TreeMap { TreeMap{root: None, length: 0} } - /// Visit all keys in order - pub fn each_key(&self, f: &fn(&K) -> bool) -> bool { - self.iter().advance(|(k, _)| f(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { - self.iter().advance(|(_, v)| f(v)) - } - /// Iterate over the map and mutate the contained values pub fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { mutate_values(&mut self.root, f) } - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { - self.rev_iter().advance(|(k,v)| f(k, v)) - } - - /// Visit all keys in reverse order - pub fn each_key_reverse(&self, f: &fn(&K) -> bool) -> bool { - self.each_reverse(|k, _| f(k)) - } - - /// Visit all values in reverse order - pub fn each_value_reverse(&self, f: &fn(&V) -> bool) -> bool { - self.each_reverse(|_, v| f(v)) - } - /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -552,12 +527,6 @@ impl TreeSet { TreeSetIterator{iter: self.map.upper_bound_iter(v)} } - /// Visit all values in reverse order - #[inline] - pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { - self.map.each_key_reverse(f) - } - /// Visit the values (in-order) representing the difference pub fn difference<'a>(&'a self, other: &'a TreeSet) -> Difference<'a, T> { Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} @@ -1172,7 +1141,7 @@ mod test_treemap { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeMap::new(); assert!(m.insert(3, 6)); @@ -1182,12 +1151,11 @@ mod test_treemap { assert!(m.insert(1, 2)); let mut n = 4; - do m.each_reverse |k, v| { + for (k, v) in m.rev_iter() { assert_eq!(*k, n); assert_eq!(*v, n * 2); n -= 1; - true - }; + } } #[test] @@ -1448,7 +1416,7 @@ mod test_set { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeSet::new(); assert!(m.insert(3)); @@ -1458,11 +1426,10 @@ mod test_set { assert!(m.insert(1)); let mut n = 4; - do m.each_reverse |x| { + for x in m.rev_iter() { assert_eq!(*x, n); n -= 1; - true - }; + } } fn check(a: &[int], b: &[int], expected: &[int], From 8ebdb37fd24435d08451625656cc53ebc814c3fa Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Mon, 5 Aug 2013 19:58:10 -0400 Subject: [PATCH 43/48] fix recv_ready for Port to take &self and not need to return a tuple. Close #8192. --- src/libstd/rt/comm.rs | 29 +++++++++++++++++++++++++---- src/libstd/rt/select.rs | 4 +--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 0cf223f30291..6dc44dd1193b 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -508,7 +508,11 @@ impl Peekable for Port { } } -impl Select for Port { +// XXX: Kind of gross. A Port should be selectable so you can make an array +// of them, but a &Port should also be selectable so you can select2 on it +// alongside a PortOne without passing the port by value in recv_ready. + +impl<'self, T> Select for &'self Port { #[inline] fn optimistic_check(&mut self) -> bool { do self.next.with_mut_ref |pone| { pone.optimistic_check() } @@ -526,12 +530,29 @@ impl Select for Port { } } -impl SelectPort<(T, Port)> for Port { - fn recv_ready(self) -> Option<(T, Port)> { +impl Select for Port { + #[inline] + fn optimistic_check(&mut self) -> bool { + (&*self).optimistic_check() + } + + #[inline] + fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool { + (&*self).block_on(sched, task) + } + + #[inline] + fn unblock_from(&mut self) -> bool { + (&*self).unblock_from() + } +} + +impl<'self, T> SelectPort for &'self Port { + fn recv_ready(self) -> Option { match self.next.take().recv_ready() { Some(StreamPayload { val, next }) => { self.next.put_back(next); - Some((val, self)) + Some(val) } None => None } diff --git a/src/libstd/rt/select.rs b/src/libstd/rt/select.rs index 006b777b71b1..84ce36c3e6b5 100644 --- a/src/libstd/rt/select.rs +++ b/src/libstd/rt/select.rs @@ -199,9 +199,7 @@ mod test { // get it back out util::swap(port.get_mut_ref(), &mut ports[index]); // NB. Not recv(), because optimistic_check randomly fails. - let (data, new_port) = port.take_unwrap().recv_ready().unwrap(); - assert!(data == 31337); - port = Some(new_port); + assert!(port.get_ref().recv_ready().unwrap() == 31337); } } } From fb1575bcc4fdcae1be5654d630d2b3ac9ebc9712 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Mon, 5 Aug 2013 20:14:20 -0400 Subject: [PATCH 44/48] (cleanup) Improve rtabort message for atomic-sleep. --- src/libstd/rt/kill.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 789c7531eca8..b3e81d4b7b28 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -590,7 +590,8 @@ impl Death { #[inline] pub fn assert_may_sleep(&self) { if self.wont_sleep != 0 { - rtabort!("illegal atomic-sleep: can't deschedule inside atomically()"); + rtabort!("illegal atomic-sleep: attempt to reschedule while \ + using an Exclusive or LittleLock"); } } } From 0627089bba7e1cc8040f41800fff2a5d80896958 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Wed, 7 Aug 2013 23:20:06 -0400 Subject: [PATCH 45/48] Fix fallout --- src/test/auxiliary/cci_class_5.rs | 2 +- src/test/compile-fail/issue-3763.rs | 2 +- src/test/compile-fail/issue-3993-3.rs | 4 ++-- src/test/compile-fail/issue-3993.rs | 2 +- src/test/compile-fail/private-impl-method.rs | 2 +- src/test/compile-fail/private-item-simple.rs | 2 +- src/test/compile-fail/private-method.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/auxiliary/cci_class_5.rs b/src/test/auxiliary/cci_class_5.rs index 7cdfcf64bb9d..5b8bebda9248 100644 --- a/src/test/auxiliary/cci_class_5.rs +++ b/src/test/auxiliary/cci_class_5.rs @@ -17,7 +17,7 @@ pub mod kitties { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/compile-fail/issue-3763.rs b/src/test/compile-fail/issue-3763.rs index 9647d412d2cd..7097615b87e7 100644 --- a/src/test/compile-fail/issue-3763.rs +++ b/src/test/compile-fail/issue-3763.rs @@ -16,7 +16,7 @@ mod my_mod { MyStruct {priv_field: 4} } impl MyStruct { - priv fn happyfun(&self) {} + fn happyfun(&self) {} } } diff --git a/src/test/compile-fail/issue-3993-3.rs b/src/test/compile-fail/issue-3993-3.rs index ccda6f158eda..cab999f621de 100644 --- a/src/test/compile-fail/issue-3993-3.rs +++ b/src/test/compile-fail/issue-3993-3.rs @@ -12,8 +12,8 @@ use zoo::fly; //~ ERROR failed to resolve import //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv type fly = (); - priv fn fly() {} + type fly = (); + fn fly() {} } diff --git a/src/test/compile-fail/issue-3993.rs b/src/test/compile-fail/issue-3993.rs index 450ea023bcbe..53a56ad27742 100644 --- a/src/test/compile-fail/issue-3993.rs +++ b/src/test/compile-fail/issue-3993.rs @@ -12,7 +12,7 @@ use zoo::fly; //~ ERROR failed to resolve import //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv fn fly() {} + fn fly() {} } diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs index 26b7d73ab2af..42da53e98903 100644 --- a/src/test/compile-fail/private-impl-method.rs +++ b/src/test/compile-fail/private-impl-method.rs @@ -14,7 +14,7 @@ mod a { } impl Foo { - priv fn foo(&self) {} + fn foo(&self) {} } } diff --git a/src/test/compile-fail/private-item-simple.rs b/src/test/compile-fail/private-item-simple.rs index 8776739db2d7..a31d0030f67e 100644 --- a/src/test/compile-fail/private-item-simple.rs +++ b/src/test/compile-fail/private-item-simple.rs @@ -9,7 +9,7 @@ // except according to those terms. mod a { - priv fn f() {} + fn f() {} } fn main() { diff --git a/src/test/compile-fail/private-method.rs b/src/test/compile-fail/private-method.rs index 1cde50cc15e9..858227655955 100644 --- a/src/test/compile-fail/private-method.rs +++ b/src/test/compile-fail/private-method.rs @@ -18,7 +18,7 @@ mod kitties { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { From 86d581f83bc4a1d788de0c7bf35565665870ca0a Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Thu, 8 Aug 2013 15:34:59 -0400 Subject: [PATCH 46/48] xfail-fast an aux test --- src/test/run-pass/xcrate-unit-struct.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/xcrate-unit-struct.rs b/src/test/run-pass/xcrate-unit-struct.rs index 58676f7cd70e..d6522231f65f 100644 --- a/src/test/run-pass/xcrate-unit-struct.rs +++ b/src/test/run-pass/xcrate-unit-struct.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:xcrate_unit_struct.rs - +// xfail-fast extern mod xcrate_unit_struct; use std::util; From 878e74e1cedd80a909e06073f8fb677d6ffd895f Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Thu, 8 Aug 2013 17:02:03 -0400 Subject: [PATCH 47/48] Fix more priv fallout --- doc/tutorial.md | 4 ++-- src/librustdoc/prune_private_pass.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 6e6b804aa9d3..40e276ae04a1 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2288,8 +2288,8 @@ pub mod farm { } impl Farm { - priv fn feed_chickens(&self) { ... } - priv fn feed_cows(&self) { ... } + fn feed_chickens(&self) { ... } + fn feed_cows(&self) { ... } pub fn add_chicken(&self, c: Chicken) { ... } } diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 6f3f91f3c65d..3e380732d0f0 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -202,7 +202,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -212,7 +212,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -232,7 +232,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } From af2e03998d4d06f2781ca72ec005f6913148f8bb Mon Sep 17 00:00:00 2001 From: toddaaro Date: Mon, 5 Aug 2013 13:06:24 -0700 Subject: [PATCH 48/48] Enabled workstealing in the scheduler. Previously we had one global work queue shared by each scheduler. Now there is a separate work queue for each scheduler, and work is "stolen" from other queues when it is exhausted locally. --- src/libstd/rt/comm.rs | 7 +- src/libstd/rt/mod.rs | 32 +++-- src/libstd/rt/sched.rs | 167 ++++++++++++++++------- src/libstd/rt/select.rs | 2 + src/libstd/rt/test.rs | 18 ++- src/libstd/task/spawn.rs | 9 +- src/test/bench/rt-messaging-ping-pong.rs | 82 +++++++++++ src/test/bench/rt-parfib.rs | 49 +++++++ src/test/bench/rt-spawn-rate.rs | 33 +++++ 9 files changed, 332 insertions(+), 67 deletions(-) create mode 100644 src/test/bench/rt-messaging-ping-pong.rs create mode 100644 src/test/bench/rt-parfib.rs create mode 100644 src/test/bench/rt-spawn-rate.rs diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 0cf223f30291..33b4b307af84 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -225,9 +225,10 @@ impl Select for PortOne { fn optimistic_check(&mut self) -> bool { // The optimistic check is never necessary for correctness. For testing // purposes, making it randomly return false simulates a racing sender. - use rand::{Rand, rng}; - let mut rng = rng(); - let actually_check = Rand::rand(&mut rng); + use rand::{Rand}; + let actually_check = do Local::borrow:: |sched| { + Rand::rand(&mut sched.rng) + }; if actually_check { unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE } } else { diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 147c75e5c41e..01a52892f633 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -63,8 +63,7 @@ Several modules in `core` are clients of `rt`: use cell::Cell; use clone::Clone; use container::Container; -use iter::Times; -use iterator::{Iterator, IteratorUtil}; +use iterator::{Iterator, IteratorUtil, range}; use option::{Some, None}; use ptr::RawPtr; use rt::local::Local; @@ -247,11 +246,16 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let main = Cell::new(main); - // The shared list of sleeping schedulers. Schedulers wake each other - // occassionally to do new work. + // The shared list of sleeping schedulers. let sleepers = SleeperList::new(); - // The shared work queue. Temporary until work stealing is implemented. - let work_queue = WorkQueue::new(); + + // Create a work queue for each scheduler, ntimes. Create an extra + // for the main thread if that flag is set. We won't steal from it. + let mut work_queues = ~[]; + for _ in range(0u, nscheds) { + let work_queue: WorkQueue<~Task> = WorkQueue::new(); + work_queues.push(work_queue); + } // The schedulers. let mut scheds = ~[]; @@ -259,12 +263,15 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // sent the Shutdown message to terminate the schedulers. let mut handles = ~[]; - do nscheds.times { + for i in range(0u, nscheds) { rtdebug!("inserting a regular scheduler"); // Every scheduler is driven by an I/O event loop. let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); + let mut sched = ~Scheduler::new(loop_, + work_queues[i].clone(), + work_queues.clone(), + sleepers.clone()); let handle = sched.make_handle(); scheds.push(sched); @@ -280,9 +287,14 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let friend_handle = friend_sched.make_handle(); scheds.push(friend_sched); + // This scheduler needs a queue that isn't part of the stealee + // set. + let work_queue = WorkQueue::new(); + let main_loop = ~UvEventLoop::new(); let mut main_sched = ~Scheduler::new_special(main_loop, - work_queue.clone(), + work_queue, + work_queues.clone(), sleepers.clone(), false, Some(friend_handle)); @@ -371,7 +383,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None, home, main.take()); main_task.death.on_exit = Some(on_exit.take()); - rtdebug!("boostrapping main_task"); + rtdebug!("bootstrapping main_task"); main_sched.bootstrap(main_task); } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 990e1a4a3de9..ce4e64c47d2e 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -13,7 +13,6 @@ use option::{Option, Some, None}; use cast::{transmute, transmute_mut_region, transmute_mut_unsafe}; use clone::Clone; use unstable::raw; - use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; use super::stack::{StackPool}; @@ -28,6 +27,9 @@ use rt::rtio::RemoteCallback; use rt::metrics::SchedMetrics; use borrow::{to_uint}; use cell::Cell; +use rand::{XorShiftRng, RngUtil}; +use iterator::{range}; +use vec::{OwnedVector}; /// The Scheduler is responsible for coordinating execution of Coroutines /// on a single thread. When the scheduler is running it is owned by @@ -37,9 +39,11 @@ use cell::Cell; /// XXX: This creates too many callbacks to run_sched_once, resulting /// in too much allocation and too many events. pub struct Scheduler { - /// A queue of available work. Under a work-stealing policy there - /// is one per Scheduler. - work_queue: WorkQueue<~Task>, + /// There are N work queues, one per scheduler. + priv work_queue: WorkQueue<~Task>, + /// Work queues for the other schedulers. These are created by + /// cloning the core work queues. + work_queues: ~[WorkQueue<~Task>], /// The queue of incoming messages from other schedulers. /// These are enqueued by SchedHandles after which a remote callback /// is triggered to handle the message. @@ -70,7 +74,10 @@ pub struct Scheduler { run_anything: bool, /// If the scheduler shouldn't run some tasks, a friend to send /// them to. - friend_handle: Option + friend_handle: Option, + /// A fast XorShift rng for scheduler use + rng: XorShiftRng + } pub struct SchedHandle { @@ -97,10 +104,13 @@ impl Scheduler { pub fn new(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList) -> Scheduler { - Scheduler::new_special(event_loop, work_queue, sleeper_list, true, None) + Scheduler::new_special(event_loop, work_queue, + work_queues, + sleeper_list, true, None) } @@ -108,6 +118,7 @@ impl Scheduler { // task field is None. pub fn new_special(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList, run_anything: bool, friend: Option) @@ -120,12 +131,14 @@ impl Scheduler { no_sleep: false, event_loop: event_loop, work_queue: work_queue, + work_queues: work_queues, stack_pool: StackPool::new(), sched_task: None, cleanup_job: None, metrics: SchedMetrics::new(), run_anything: run_anything, - friend_handle: friend + friend_handle: friend, + rng: XorShiftRng::new() } } @@ -248,7 +261,7 @@ impl Scheduler { // Second activity is to try resuming a task from the queue. - let result = sched.resume_task_from_queue(); + let result = sched.do_work(); let mut sched = match result { Some(sched) => { // Failed to dequeue a task, so we return. @@ -415,47 +428,98 @@ impl Scheduler { } } - // Resume a task from the queue - but also take into account that - // it might not belong here. + // Workstealing: In this iteration of the runtime each scheduler + // thread has a distinct work queue. When no work is available + // locally, make a few attempts to steal work from the queues of + // other scheduler threads. If a few steals fail we end up in the + // old "no work" path which is fine. - // If we perform a scheduler action we give away the scheduler ~ - // pointer, if it is still available we return it. - - fn resume_task_from_queue(~self) -> Option<~Scheduler> { - - let mut this = self; - - match this.work_queue.pop() { + // First step in the process is to find a task. This function does + // that by first checking the local queue, and if there is no work + // there, trying to steal from the remote work queues. + fn find_work(&mut self) -> Option<~Task> { + rtdebug!("scheduler looking for work"); + match self.work_queue.pop() { Some(task) => { - let mut task = task; - let home = task.take_unwrap_home(); - match home { - Sched(home_handle) => { - if home_handle.sched_id != this.sched_id() { - task.give_home(Sched(home_handle)); - Scheduler::send_task_home(task); - return Some(this); - } else { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(Sched(home_handle)); - this.resume_task_immediately(task); - return None; - } - } - AnySched if this.run_anything => { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(AnySched); - this.resume_task_immediately(task); - return None; - } - AnySched => { - task.give_home(AnySched); - this.send_to_friend(task); - return Some(this); - } - } + rtdebug!("found a task locally"); + return Some(task) } None => { + // Our naive stealing, try kinda hard. + rtdebug!("scheduler trying to steal"); + let _len = self.work_queues.len(); + return self.try_steals(2); + } + } + } + + // With no backoff try stealing n times from the queues the + // scheduler knows about. This naive implementation can steal from + // our own queue or from other special schedulers. + fn try_steals(&mut self, n: uint) -> Option<~Task> { + for _ in range(0, n) { + let index = self.rng.gen_uint_range(0, self.work_queues.len()); + let work_queues = &mut self.work_queues; + match work_queues[index].steal() { + Some(task) => { + rtdebug!("found task by stealing"); return Some(task) + } + None => () + } + }; + rtdebug!("giving up on stealing"); + return None; + } + + // Given a task, execute it correctly. + fn process_task(~self, task: ~Task) -> Option<~Scheduler> { + let mut this = self; + let mut task = task; + + rtdebug!("processing a task"); + + let home = task.take_unwrap_home(); + match home { + Sched(home_handle) => { + if home_handle.sched_id != this.sched_id() { + rtdebug!("sending task home"); + task.give_home(Sched(home_handle)); + Scheduler::send_task_home(task); + return Some(this); + } else { + rtdebug!("running task here"); + task.give_home(Sched(home_handle)); + this.resume_task_immediately(task); + return None; + } + } + AnySched if this.run_anything => { + rtdebug!("running anysched task here"); + task.give_home(AnySched); + this.resume_task_immediately(task); + return None; + } + AnySched => { + rtdebug!("sending task to friend"); + task.give_home(AnySched); + this.send_to_friend(task); + return Some(this); + } + } + } + + // Bundle the helpers together. + fn do_work(~self) -> Option<~Scheduler> { + let mut this = self; + + rtdebug!("scheduler calling do work"); + match this.find_work() { + Some(task) => { + rtdebug!("found some work! processing the task"); + return this.process_task(task); + } + None => { + rtdebug!("no work was found, returning the scheduler struct"); return Some(this); } } @@ -711,7 +775,6 @@ impl Scheduler { GiveTask(task, f) => f.to_fn()(self, task) } } - } // The cases for the below function. @@ -745,6 +808,8 @@ impl ClosureConverter for UnsafeTaskReceiver { #[cfg(test)] mod test { + extern mod extra; + use prelude::*; use rt::test::*; use unstable::run_in_bare_thread; @@ -862,12 +927,15 @@ mod test { do run_in_bare_thread { let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); + let normal_queue = WorkQueue::new(); + let special_queue = WorkQueue::new(); + let queues = ~[normal_queue.clone(), special_queue.clone()]; // Our normal scheduler let mut normal_sched = ~Scheduler::new( ~UvEventLoop::new(), - work_queue.clone(), + normal_queue, + queues.clone(), sleepers.clone()); let normal_handle = Cell::new(normal_sched.make_handle()); @@ -877,7 +945,8 @@ mod test { // Our special scheduler let mut special_sched = ~Scheduler::new_special( ~UvEventLoop::new(), - work_queue.clone(), + special_queue.clone(), + queues.clone(), sleepers.clone(), false, Some(friend_handle)); diff --git a/src/libstd/rt/select.rs b/src/libstd/rt/select.rs index 006b777b71b1..07f8ca77d9db 100644 --- a/src/libstd/rt/select.rs +++ b/src/libstd/rt/select.rs @@ -182,6 +182,7 @@ mod test { fn select_stream() { use util; use comm::GenericChan; + use iter::Times; // Sends 10 buffered packets, and uses select to retrieve them all. // Puts the port in a different spot in the vector each time. @@ -265,6 +266,7 @@ mod test { fn select_racing_senders_helper(killable: bool, send_on_chans: ~[uint]) { use rt::test::spawntask_random; + use iter::Times; do run_in_newsched_task { // A bit of stress, since ordinarily this is just smoke and mirrors. diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 792ea5eb33f5..92366d5187fe 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -15,8 +15,8 @@ use cell::Cell; use clone::Clone; use container::Container; use iterator::{Iterator, range}; -use vec::{OwnedVector, MutableVector}; use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; +use vec::{OwnedVector, MutableVector, ImmutableVector}; use rt::sched::Scheduler; use unstable::run_in_bare_thread; use rt::thread::Thread; @@ -29,8 +29,12 @@ use result::{Result, Ok, Err}; pub fn new_test_uv_sched() -> Scheduler { + let queue = WorkQueue::new(); + let queues = ~[queue.clone()]; + let mut sched = Scheduler::new(~UvEventLoop::new(), - WorkQueue::new(), + queue, + queues, SleeperList::new()); // Don't wait for the Shutdown message @@ -164,15 +168,21 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { }; let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); let mut handles = ~[]; let mut scheds = ~[]; + let mut work_queues = ~[]; for _ in range(0u, nthreads) { + let work_queue = WorkQueue::new(); + work_queues.push(work_queue); + } + + for i in range(0u, nthreads) { let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, - work_queue.clone(), + work_queues[i].clone(), + work_queues.clone(), sleepers.clone()); let handle = sched.make_handle(); diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 2d0a2d98e9fc..05a17f8539c2 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -98,6 +98,7 @@ use rt::kill::KillHandle; use rt::sched::Scheduler; use rt::uv::uvio::UvEventLoop; use rt::thread::Thread; +use rt::work_queue::WorkQueue; #[cfg(test)] use task::default_task_opts; #[cfg(test)] use comm; @@ -722,10 +723,16 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let sched = Local::unsafe_borrow::(); let sched_handle = (*sched).make_handle(); + // Since this is a 1:1 scheduler we create a queue not in + // the stealee set. The run_anything flag is set false + // which will disable stealing. + let work_queue = WorkQueue::new(); + // Create a new scheduler to hold the new task let new_loop = ~UvEventLoop::new(); let mut new_sched = ~Scheduler::new_special(new_loop, - (*sched).work_queue.clone(), + work_queue, + (*sched).work_queues.clone(), (*sched).sleeper_list.clone(), false, Some(sched_handle)); diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs new file mode 100644 index 000000000000..3d38d61bc2eb --- /dev/null +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -0,0 +1,82 @@ +// 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. + +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; + +// This is a simple bench that creates M pairs of of tasks. These +// tasks ping-pong back and forth over a pair of streams. This is a +// cannonical message-passing benchmark as it heavily strains message +// passing and almost nothing else. + +fn ping_pong_bench(n: uint, m: uint) { + + // Create pairs of tasks that pingpong back and forth. + fn run_pair(n: uint) { + // Create a stream A->B + let (pa,ca) = stream::<()>(); + // Create a stream B->A + let (pb,cb) = stream::<()>(); + + let pa = Cell::new(pa); + let ca = Cell::new(ca); + let pb = Cell::new(pb); + let cb = Cell::new(cb); + + do spawntask_later() || { + let chan = ca.take(); + let port = pb.take(); + do n.times { + chan.send(()); + port.recv(); + } + } + + do spawntask_later() || { + let chan = cb.take(); + let port = pa.take(); + do n.times { + port.recv(); + chan.send(()); + } + } + } + + do m.times { + run_pair(n) + } + +} + + + +fn main() { + + let args = os::args(); + let n = if args.len() == 3 { + uint::from_str(args[1]).unwrap() + } else { + 10000 + }; + + let m = if args.len() == 3 { + uint::from_str(args[2]).unwrap() + } else { + 4 + }; + + ping_pong_bench(n, m); + +} diff --git a/src/test/bench/rt-parfib.rs b/src/test/bench/rt-parfib.rs new file mode 100644 index 000000000000..6669342f511a --- /dev/null +++ b/src/test/bench/rt-parfib.rs @@ -0,0 +1,49 @@ +// 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. + +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; +use std::comm::*; + +// A simple implementation of parfib. One subtree is found in a new +// task and communicated over a oneshot pipe, the other is found +// locally. There is no sequential-mode threshold. + +fn parfib(n: uint) -> uint { + if(n == 0 || n == 1) { + return 1; + } + + let (port,chan) = oneshot::(); + let chan = Cell::new(chan); + do spawntask_later { + chan.take().send(parfib(n-1)); + }; + let m2 = parfib(n-2); + return (port.recv() + m2); +} + +fn main() { + + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 10 + }; + + parfib(n); + +} diff --git a/src/test/bench/rt-spawn-rate.rs b/src/test/bench/rt-spawn-rate.rs new file mode 100644 index 000000000000..ff578ed70b9c --- /dev/null +++ b/src/test/bench/rt-spawn-rate.rs @@ -0,0 +1,33 @@ +// 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. + +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; + +// Very simple spawn rate test. Spawn N tasks that do nothing and +// return. + +fn main() { + + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 100000 + }; + + do n.times { + do spawn || {}; + } + +}