diff options
Diffstat (limited to 'src')
307 files changed, 5433 insertions, 5045 deletions
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index f76cefcd941..e28029c4d9d 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -286,6 +286,9 @@ pub fn test_opts(config: &Config) -> test::TestOpts { test_shard: config.test_shard.clone(), nocapture: false, color: test::AutoColor, + show_boxplot: false, + boxplot_width: 50, + show_all_stats: false, } } diff --git a/src/doc/guide.md b/src/doc/guide.md index c2d43a20ec4..3f3b533bbd5 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -140,7 +140,7 @@ $ editor main.rs ``` Rust files always end in a `.rs` extension. If you're using more than one word -in your file name, use an underscore. `hello_world.rs` rather than +in your filename, use an underscore. `hello_world.rs` rather than `helloworld.rs`. Now that you've got your file open, type this in: @@ -200,7 +200,7 @@ about this difference. Just know that sometimes, you'll see a `!`, and that means that you're calling a macro instead of a normal function. Rust implements `println!` as a macro rather than a function for good reasons, but that's a very advanced topic. You'll learn more when we talk about macros later. One -last thing to mention: Rust's macros are significantly different than C macros, +last thing to mention: Rust's macros are significantly different from C macros, if you've used those. Don't be scared of using macros. We'll get to the details eventually, you'll just have to trust us for now. @@ -595,8 +595,8 @@ let y = if x == 5i { 10i } else { 15i }; ``` This reveals two interesting things about Rust: it is an expression-based -language, and semicolons are different than in other 'curly brace and -semicolon'-based languages. These two things are related. +language, and semicolons are different from semicolons in other 'curly brace +and semicolon'-based languages. These two things are related. ## Expressions vs. Statements @@ -1454,7 +1454,7 @@ Both `continue` and `break` are valid in both kinds of loops. # Strings Strings are an important concept for any programmer to master. Rust's string -handling system is a bit different than in other languages, due to its systems +handling system is a bit different from other languages, due to its systems focus. Any time you have a data structure of variable size, things can get tricky, and strings are a re-sizable data structure. That said, Rust's strings also work differently than in some other systems languages, such as C. @@ -2064,8 +2064,8 @@ Great! Next up: let's compare our guess to the secret guess. ## Comparing guesses If you remember, earlier in the guide, we made a `cmp` function that compared -two numbers. Let's add that in, along with a `match` statement to compare the -guess to the secret guess: +two numbers. Let's add that in, along with a `match` statement to compare our +guess to the secret number: ```{rust,ignore} use std::io; @@ -2861,7 +2861,7 @@ parts of your library. The six levels are: * experimental: This item was only recently introduced or is otherwise in a state of flux. It may change significantly, or even be removed. No guarantee of backwards-compatibility. -* unstable: This item is still under development, but requires more testing to +* unstable: This item is still under development and requires more testing to be considered stable. No guarantee of backwards-compatibility. * stable: This item is considered stable, and will not change significantly. Guarantee of backwards-compatibility. @@ -5174,12 +5174,12 @@ processor. Rust's semantics lend themselves very nicely to solving a number of issues that programmers have with concurrency. Many concurrency errors that are runtime errors in other languages are compile-time errors in Rust. -Rust's concurrency primitive is called a **task**. Tasks are lightweight, and -do not share memory in an unsafe manner, preferring message passing to -communicate. It's worth noting that tasks are implemented as a library, and -not part of the language. This means that in the future, other concurrency -libraries can be written for Rust to help in specific scenarios. Here's an -example of creating a task: +Rust's concurrency primitive is called a **task**. Tasks are similar to +threads, and do not share memory in an unsafe manner, preferring message +passing to communicate. It's worth noting that tasks are implemented as a +library, and not part of the language. This means that in the future, other +concurrency libraries can be written for Rust to help in specific scenarios. +Here's an example of creating a task: ```{rust} spawn(proc() { diff --git a/src/doc/reference.md b/src/doc/reference.md index 1d27ac096df..9ac4469d549 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -522,7 +522,7 @@ The two values of the boolean type are written `true` and `false`. ### Symbols ```{.ebnf .gram} -symbol : "::" "->" +symbol : "::" | "->" | '#' | '[' | ']' | '(' | ')' | '{' | '}' | ',' | ';' ; ``` @@ -994,7 +994,7 @@ An example of `use` declarations: ``` use std::iter::range_step; -use std::option::{Some, None}; +use std::option::Option::{Some, None}; use std::collections::hash_map::{mod, HashMap}; fn foo<T>(_: T){} @@ -1004,8 +1004,8 @@ fn main() { // Equivalent to 'std::iter::range_step(0u, 10u, 2u);' range_step(0u, 10u, 2u); - // Equivalent to 'foo(vec![std::option::Some(1.0f64), - // std::option::None]);' + // Equivalent to 'foo(vec![std::option::Option::Some(1.0f64), + // std::option::Option::None]);' foo(vec![Some(1.0f64), None]); // Both `hash_map` and `HashMap` are in scope. diff --git a/src/driver/driver.rs b/src/driver/driver.rs index 632d21d7b9c..5c29cb4ec72 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -12,6 +12,6 @@ extern crate "rustdoc" as this; #[cfg(rustc)] -extern crate "rustc_trans" as this; +extern crate "rustc_driver" as this; fn main() { this::main() } diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 1af649f0731..7e5918ea39e 100644 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -54,13 +54,14 @@ def rust_pretty_printer_lookup_function(val): return RustStructPrinter(val, false) if enum_member_count == 1: - if enum_members[0].name == None: + first_variant_name = enum_members[0].name + if first_variant_name == None: # This is a singleton enum return rust_pretty_printer_lookup_function(val[enum_members[0]]) else: - assert enum_members[0].name.startswith("RUST$ENCODED$ENUM$") + assert first_variant_name.startswith("RUST$ENCODED$ENUM$") # This is a space-optimized enum - last_separator_index = enum_members[0].name.rfind("$") + last_separator_index = first_variant_name.rfind("$") second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index) disr_field_index = first_variant_name[second_last_separator_index + 1 : last_separator_index] @@ -68,7 +69,12 @@ def rust_pretty_printer_lookup_function(val): sole_variant_val = val[enum_members[0]] disr_field = get_field_at_index(sole_variant_val, disr_field_index) - discriminant = int(sole_variant_val[disr_field]) + discriminant = sole_variant_val[disr_field] + + # If the discriminant field is a fat pointer we have to consider the + # first word as the true discriminant + if discriminant.type.code == gdb.TYPE_CODE_STRUCT: + discriminant = discriminant[get_field_at_index(discriminant, 0)] if discriminant == 0: null_variant_name = first_variant_name[last_separator_index + 1:] @@ -173,7 +179,7 @@ class RustCStyleEnumPrinter: class IdentityPrinter: def __init__(self, string): - self.string + self.string = string def to_string(self): return self.string diff --git a/src/etc/licenseck.py b/src/etc/licenseck.py index 9162edcb530..7669df36b04 100644 --- a/src/etc/licenseck.py +++ b/src/etc/licenseck.py @@ -38,9 +38,8 @@ exceptions = [ "rt/isaac/randport.cpp", # public domain "rt/isaac/rand.h", # public domain "rt/isaac/standard.h", # public domain - "libstd/sync/mpsc_queue.rs", # BSD - "libstd/sync/spsc_queue.rs", # BSD - "libstd/sync/mpmc_bounded_queue.rs", # BSD + "libstd/comm/mpsc_queue.rs", # BSD + "libstd/comm/spsc_queue.rs", # BSD "test/bench/shootout-binarytrees.rs", # BSD "test/bench/shootout-chameneos-redux.rs", # BSD "test/bench/shootout-fannkuch-redux.rs", # BSD diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index 7924d63c8e0..f4f1a5121d1 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -138,9 +138,14 @@ def print_enum_val(val, internal_dict): return "<invalid enum encoding: %s>" % first_variant_name # Read the discriminant - disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index).GetValueAsUnsigned() + disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index) - if disr_val == 0: + # If the discriminant field is a fat pointer we have to consider the + # first word as the true discriminant + if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct: + disr_val = disr_val.GetChildAtIndex(0) + + if disr_val.GetValueAsUnsigned() == 0: # Null case: Print the name of the null-variant null_variant_name = first_variant_name[last_separator_index + 1:] return null_variant_name diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 15263919fb9..20edf9418f1 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -292,7 +292,7 @@ def escape_char(c): def emit_bsearch_range_table(f): f.write(""" fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; r.binary_search(|&(lo,hi)| { if lo <= c && c <= hi { Equal } @@ -350,10 +350,11 @@ def emit_regex_module(f, cats, w_data): def emit_conversions_module(f, lowerupper, upperlower): f.write("pub mod conversions {") f.write(""" - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; use core::tuple::Tuple2; - use core::option::{Option, Some, None}; + use core::option::Option; + use core::option::Option::{Some, None}; use core::slice; pub fn to_lower(c: char) -> char { @@ -403,7 +404,7 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats): f.write(""" } fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; match r.binary_search(|&(lo, hi, _)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } @@ -430,12 +431,13 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats): def emit_charwidth_module(f, width_table): f.write("pub mod charwidth {\n") - f.write(" use core::option::{Option, Some, None};\n") + f.write(" use core::option::Option;\n") + f.write(" use core::option::Option::{Some, None};\n") f.write(" use core::slice::SlicePrelude;\n") f.write(" use core::slice;\n") f.write(""" fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; match r.binary_search(|&(lo, hi, _, _)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } @@ -530,7 +532,7 @@ def emit_norm_module(f, canon, compat, combine, norm_props): f.write(""" fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; use core::slice; match r.binary_search(|&(lo, hi, _)| { diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 4f744b0b2de..ef05279e825 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -22,7 +22,8 @@ use core::kinds::{Sync, Send}; use core::mem::{min_align_of, size_of, drop}; use core::mem; use core::ops::{Drop, Deref}; -use core::option::{Some, None, Option}; +use core::option::Option; +use core::option::Option::{Some, None}; use core::ptr::RawPtr; use core::ptr; use heap::deallocate; @@ -326,7 +327,8 @@ mod tests { use std::comm::channel; use std::mem::drop; use std::ops::Drop; - use std::option::{Option, Some, None}; + use std::option::Option; + use std::option::Option::{Some, None}; use std::str::Str; use std::sync::atomic; use std::task; diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 000dda59e3d..eb483498998 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -19,7 +19,8 @@ use core::kinds::Sized; use core::mem; use core::option::Option; use core::raw::TraitObject; -use core::result::{Ok, Err, Result}; +use core::result::Result; +use core::result::Result::{Ok, Err}; /// A value that represents the global exchange heap. This is the default /// place that the `box` keyword allocates into when no place is supplied. diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 579f47ee874..c6b6a784f06 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -123,9 +123,62 @@ const MIN_ALIGN: uint = 8; target_arch = "x86_64"))] const MIN_ALIGN: uint = 16; -#[cfg(jemalloc)] +#[cfg(external_funcs)] mod imp { - use core::option::{None, Option}; + extern { + fn rust_allocate(size: uint, align: uint) -> *mut u8; + fn rust_deallocate(ptr: *mut u8, old_size: uint, align: uint); + fn rust_reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8; + fn rust_reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, + align: uint) -> uint; + fn rust_usable_size(size: uint, align: uint) -> uint; + fn rust_stats_print(); + } + + #[inline] + pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 { + rust_allocate(size, align) + } + + #[inline] + pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, + align: uint) -> uint { + rust_reallocate_inplace(ptr, old_size, size, align) + } + + #[inline] + pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) { + rust_deallocate(ptr, old_size, align) + } + + #[inline] + pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, + align: uint) -> uint { + rust_reallocate_inplace(ptr, old_size, size, align) + } + + #[inline] + pub fn usable_size(size: uint, align: uint) -> uint { + unsafe { rust_usable_size(size, align) } + } + + #[inline] + pub fn stats_print() { + unsafe { rust_stats_print() } + } +} + +#[cfg(external_crate)] +mod imp { + extern crate external; + pub use self::external::{allocate, deallocate, reallocate_inplace, reallocate}; + pub use self::external::{usable_size, stats_print}; +} + +#[cfg(all(not(external_funcs), not(external_crate), jemalloc))] +mod imp { + use core::option::Option; + use core::option::Option::None; use core::ptr::{null_mut, null}; use core::num::Int; use libc::{c_char, c_int, c_void, size_t}; @@ -199,7 +252,7 @@ mod imp { } } -#[cfg(all(not(jemalloc), unix))] +#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), unix))] mod imp { use core::cmp; use core::ptr; @@ -260,7 +313,7 @@ mod imp { pub fn stats_print() {} } -#[cfg(all(not(jemalloc), windows))] +#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), windows))] mod imp { use libc::{c_void, size_t}; use libc; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index e626d63937b..53891583edb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -149,10 +149,12 @@ use core::fmt; use core::kinds::marker; use core::mem::{transmute, min_align_of, size_of, forget}; use core::ops::{Deref, Drop}; -use core::option::{Option, Some, None}; +use core::option::Option; +use core::option::Option::{Some, None}; use core::ptr; use core::ptr::RawPtr; -use core::result::{Result, Ok, Err}; +use core::result::Result; +use core::result::Result::{Ok, Err}; use heap::deallocate; @@ -739,8 +741,9 @@ impl<T> RcBoxPtr<T> for Weak<T> { mod tests { use super::{Rc, Weak, weak_count, strong_count}; use std::cell::RefCell; - use std::option::{Option, Some, None}; - use std::result::{Err, Ok}; + use std::option::Option; + use std::option::Option::{Some, None}; + use std::result::Result::{Err, Ok}; use std::mem::drop; use std::clone::Clone; diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 64ae4f6a508..3973b4774b3 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -94,12 +94,46 @@ impl<T> BTreeSet<T> { impl<T: Ord> BTreeSet<T> { /// Visits the values representing the difference, in ascending order. + /// + /// # Example + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1u); + /// a.insert(2u); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2u); + /// b.insert(3u); + /// + /// let diff: Vec<uint> = a.difference(&b).cloned().collect(); + /// assert_eq!(diff, vec![1u]); + /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> DifferenceItems<'a, T> { DifferenceItems{a: self.iter().peekable(), b: other.iter().peekable()} } /// Visits the values representing the symmetric difference, in ascending order. + /// + /// # Example + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1u); + /// a.insert(2u); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2u); + /// b.insert(3u); + /// + /// let sym_diff: Vec<uint> = a.symmetric_difference(&b).cloned().collect(); + /// assert_eq!(sym_diff, vec![1u,3]); + /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn symmetric_difference<'a>(&'a self, other: &'a BTreeSet<T>) -> SymDifferenceItems<'a, T> { @@ -107,6 +141,23 @@ impl<T: Ord> BTreeSet<T> { } /// Visits the values representing the intersection, in ascending order. + /// + /// # Example + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1u); + /// a.insert(2u); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2u); + /// b.insert(3u); + /// + /// let intersection: Vec<uint> = a.intersection(&b).cloned().collect(); + /// assert_eq!(intersection, vec![2u]); + /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn intersection<'a>(&'a self, other: &'a BTreeSet<T>) -> IntersectionItems<'a, T> { @@ -114,6 +165,21 @@ impl<T: Ord> BTreeSet<T> { } /// Visits the values representing the union, in ascending order. + /// + /// # Example + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1u); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2u); + /// + /// let union: Vec<uint> = a.union(&b).cloned().collect(); + /// assert_eq!(union, vec![1u,2]); + /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn union<'a>(&'a self, other: &'a BTreeSet<T>) -> UnionItems<'a, T> { UnionItems{a: self.iter().peekable(), b: other.iter().peekable()} diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ad0a5e76176..78cdda61104 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -833,8 +833,10 @@ mod tests { use std::default::Default; use std::char::Char; use std::clone::Clone; - use std::cmp::{Equal, Greater, Less, Ord, PartialOrd, Equiv}; - use std::option::{Some, None}; + use std::cmp::{Ord, PartialOrd, Equiv}; + use std::cmp::Ordering::{Equal, Greater, Less}; + use std::option::Option; + use std::option::Option::{Some, None}; use std::ptr::RawPtr; use std::iter::{Iterator, IteratorExt, DoubleEndedIteratorExt}; diff --git a/src/libcollections/trie/set.rs b/src/libcollections/trie/set.rs index dd884b6ee41..1b3657943da 100644 --- a/src/libcollections/trie/set.rs +++ b/src/libcollections/trie/set.rs @@ -9,7 +9,6 @@ // except according to those terms. // FIXME(conventions): implement bounded iterators -// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub // FIXME(conventions): replace each_reverse by making iter DoubleEnded // FIXME(conventions): implement iter_mut and into_iter @@ -463,6 +462,90 @@ impl Extend<uint> for TrieSet { } } +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl BitOr<TrieSet, TrieSet> for TrieSet { + /// Returns the union of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = a | b; + /// let v: Vec<uint> = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2, 3, 4, 5]); + /// ``` + fn bitor(&self, rhs: &TrieSet) -> TrieSet { + self.union(rhs).collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl BitAnd<TrieSet, TrieSet> for TrieSet { + /// Returns the intersection of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![2, 3, 4].into_iter().collect(); + /// + /// let set: TrieSet = a & b; + /// let v: Vec<uint> = set.iter().collect(); + /// assert_eq!(v, vec![2u, 3]); + /// ``` + fn bitand(&self, rhs: &TrieSet) -> TrieSet { + self.intersection(rhs).collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl BitXor<TrieSet, TrieSet> for TrieSet { + /// Returns the symmetric difference of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = a ^ b; + /// let v: Vec<uint> = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2, 4, 5]); + /// ``` + fn bitxor(&self, rhs: &TrieSet) -> TrieSet { + self.symmetric_difference(rhs).collect() + } +} + +#[unstable = "matches collection reform specification, waiting for dust to settle"] +impl Sub<TrieSet, TrieSet> for TrieSet { + /// Returns the difference of `self` and `rhs` as a new `TrieSet`. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + /// let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + /// + /// let set: TrieSet = a - b; + /// let v: Vec<uint> = set.iter().collect(); + /// assert_eq!(v, vec![1u, 2]); + /// ``` + fn sub(&self, rhs: &TrieSet) -> TrieSet { + self.difference(rhs).collect() + } +} + /// A forward iterator over a set. pub struct SetItems<'a> { iter: Entries<'a, ()> @@ -569,6 +652,7 @@ impl<'a> Iterator<uint> for UnionItems<'a> { mod test { use std::prelude::*; use std::uint; + use vec::Vec; use super::TrieSet; @@ -738,4 +822,44 @@ mod test { &[1, 5, 9, 13, 19], &[1, 3, 5, 9, 11, 13, 16, 19, 24]); } + + #[test] + fn test_bit_or() { + let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + + let set: TrieSet = a | b; + let v: Vec<uint> = set.iter().collect(); + assert_eq!(v, vec![1u, 2, 3, 4, 5]); + } + + #[test] + fn test_bit_and() { + let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + let b: TrieSet = vec![2, 3, 4].into_iter().collect(); + + let set: TrieSet = a & b; + let v: Vec<uint> = set.iter().collect(); + assert_eq!(v, vec![2u, 3]); + } + + #[test] + fn test_bit_xor() { + let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + + let set: TrieSet = a ^ b; + let v: Vec<uint> = set.iter().collect(); + assert_eq!(v, vec![1u, 2, 4, 5]); + } + + #[test] + fn test_sub() { + let a: TrieSet = vec![1, 2, 3].into_iter().collect(); + let b: TrieSet = vec![3, 4, 5].into_iter().collect(); + + let set: TrieSet = a - b; + let v: Vec<uint> = set.iter().collect(); + assert_eq!(v, vec![1u, 2]); + } } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 36e66ed27f3..986e7ef5bc2 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -115,6 +115,22 @@ impl<V> VecMap<V> { VecMap { v: Vec::with_capacity(capacity) } } + /// Returns the number of elements the `VecMap` can hold without + /// reallocating. + /// + /// # Example + /// + /// ``` + /// use std::collections::VecMap; + /// let map: VecMap<String> = VecMap::with_capacity(10); + /// assert!(map.capacity() >= 10); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn capacity(&self) -> uint { + self.v.capacity() + } + /// Returns an iterator visiting all keys in ascending order by the keys. /// The iterator's element type is `uint`. #[unstable = "matches collection reform specification, waiting for dust to settle"] diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 5d1f996831e..75feb4d8828 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -72,7 +72,8 @@ #![stable] use mem::{transmute}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use raw::TraitObject; use intrinsics::TypeId; diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index b88fb914dd8..b44b87bd938 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -137,6 +137,18 @@ pub enum Cow<'a, T, Sized? B: 'a> where B: ToOwned<T> { Owned(T) } +impl<'a, T, Sized? B> Clone for Cow<'a, T, B> where B: ToOwned<T> { + fn clone(&self) -> Cow<'a, T, B> { + match *self { + Borrowed(b) => Borrowed(b), + Owned(ref o) => { + let b: &B = BorrowFrom::borrow_from(o); + Owned(b.to_owned()) + }, + } + } +} + impl<'a, T, Sized? B> Cow<'a, T, B> where B: ToOwned<T> { /// Acquire a mutable reference to the owned form of the data. /// diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 587bb4cb110..1ec2efaf801 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -160,7 +160,8 @@ use cmp::PartialEq; use default::Default; use kinds::{marker, Copy}; use ops::{Deref, DerefMut, Drop}; -use option::{None, Option, Some}; +use option::Option; +use option::Option::{None, Some}; /// A mutable memory location that admits only `Copy` data. #[unstable = "likely to be renamed; otherwise stable"] @@ -277,12 +278,9 @@ impl<T> RefCell<T> { /// Returns `None` if the value is currently mutably borrowed. #[unstable = "may be renamed, depending on global conventions"] pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> { - match self.borrow.get() { - WRITING => None, - borrow => { - self.borrow.set(borrow + 1); - Some(Ref { _parent: self }) - } + match BorrowRef::new(&self.borrow) { + Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }), + None => None, } } @@ -310,12 +308,9 @@ impl<T> RefCell<T> { /// Returns `None` if the value is currently borrowed. #[unstable = "may be renamed, depending on global conventions"] pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> { - match self.borrow.get() { - UNUSED => { - self.borrow.set(WRITING); - Some(RefMut { _parent: self }) - }, - _ => None + match BorrowRefMut::new(&self.borrow) { + Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }), + None => None, } } @@ -368,29 +363,56 @@ impl<T: PartialEq> PartialEq for RefCell<T> { } } -/// Wraps a borrowed reference to a value in a `RefCell` box. -#[unstable] -pub struct Ref<'b, T:'b> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _parent: &'b RefCell<T> +struct BorrowRef<'b> { + _borrow: &'b Cell<BorrowFlag>, +} + +impl<'b> BorrowRef<'b> { + fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> { + match borrow.get() { + WRITING => None, + b => { + borrow.set(b + 1); + Some(BorrowRef { _borrow: borrow }) + }, + } + } } #[unsafe_destructor] -#[unstable] -impl<'b, T> Drop for Ref<'b, T> { +impl<'b> Drop for BorrowRef<'b> { fn drop(&mut self) { - let borrow = self._parent.borrow.get(); + let borrow = self._borrow.get(); debug_assert!(borrow != WRITING && borrow != UNUSED); - self._parent.borrow.set(borrow - 1); + self._borrow.set(borrow - 1); } } +impl<'b> Clone for BorrowRef<'b> { + fn clone(&self) -> BorrowRef<'b> { + // Since this Ref exists, we know the borrow flag + // is not set to WRITING. + let borrow = self._borrow.get(); + debug_assert!(borrow != WRITING && borrow != UNUSED); + self._borrow.set(borrow + 1); + BorrowRef { _borrow: self._borrow } + } +} + +/// Wraps a borrowed reference to a value in a `RefCell` box. +#[unstable] +pub struct Ref<'b, T:'b> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _value: &'b T, + _borrow: BorrowRef<'b>, +} + #[unstable = "waiting for `Deref` to become stable"] impl<'b, T> Deref<T> for Ref<'b, T> { #[inline] fn deref<'a>(&'a self) -> &'a T { - unsafe { &*self._parent.value.get() } + self._value } } @@ -401,41 +423,52 @@ impl<'b, T> Deref<T> for Ref<'b, T> { /// A `Clone` implementation would interfere with the widespread /// use of `r.borrow().clone()` to clone the contents of a `RefCell`. #[experimental = "likely to be moved to a method, pending language changes"] -pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> { - // Since this Ref exists, we know the borrow flag - // is not set to WRITING. - let borrow = orig._parent.borrow.get(); - debug_assert!(borrow != WRITING && borrow != UNUSED); - orig._parent.borrow.set(borrow + 1); - +pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> { Ref { - _parent: orig._parent, + _value: orig._value, + _borrow: orig._borrow.clone(), } } -/// Wraps a mutable borrowed reference to a value in a `RefCell` box. -#[unstable] -pub struct RefMut<'b, T:'b> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _parent: &'b RefCell<T> +struct BorrowRefMut<'b> { + _borrow: &'b Cell<BorrowFlag>, } #[unsafe_destructor] -#[unstable] -impl<'b, T> Drop for RefMut<'b, T> { +impl<'b> Drop for BorrowRefMut<'b> { fn drop(&mut self) { - let borrow = self._parent.borrow.get(); + let borrow = self._borrow.get(); debug_assert!(borrow == WRITING); - self._parent.borrow.set(UNUSED); + self._borrow.set(UNUSED); } } +impl<'b> BorrowRefMut<'b> { + fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> { + match borrow.get() { + UNUSED => { + borrow.set(WRITING); + Some(BorrowRefMut { _borrow: borrow }) + }, + _ => None, + } + } +} + +/// Wraps a mutable borrowed reference to a value in a `RefCell` box. +#[unstable] +pub struct RefMut<'b, T:'b> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _value: &'b mut T, + _borrow: BorrowRefMut<'b>, +} + #[unstable = "waiting for `Deref` to become stable"] impl<'b, T> Deref<T> for RefMut<'b, T> { #[inline] fn deref<'a>(&'a self) -> &'a T { - unsafe { &*self._parent.value.get() } + self._value } } @@ -443,7 +476,7 @@ impl<'b, T> Deref<T> for RefMut<'b, T> { impl<'b, T> DerefMut<T> for RefMut<'b, T> { #[inline] fn deref_mut<'a>(&'a mut self) -> &'a mut T { - unsafe { &mut *self._parent.value.get() } + self._value } } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a729596e9d2..2bebe87a14c 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -16,7 +16,8 @@ #![doc(primitive = "char")] use mem::transmute; -use option::{None, Option, Some}; +use option::Option; +use option::Option::{None, Some}; use iter::{range_step, Iterator, RangeStep}; use slice::SlicePrelude; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index df19256471e..a5ba2b03b15 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -44,7 +44,8 @@ pub use self::Ordering::*; use kinds::Sized; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; /// Trait for values that can be compared for equality and inequality. /// @@ -288,10 +289,11 @@ pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> { // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { - use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering, - Less, Greater, Equal}; + use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering}; + use cmp::Ordering::{Less, Greater, Equal}; use kinds::Sized; - use option::{Option, Some, None}; + use option::Option; + use option::Option::{Some, None}; macro_rules! partial_eq_impl( ($($t:ty)*) => ($( diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 1e31df83779..400ce76baa0 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -20,7 +20,7 @@ use fmt; use iter::{range, DoubleEndedIteratorExt}; use num::{Float, FPNaN, FPInfinite, ToPrimitive}; use num::cast; -use result::Ok; +use result::Result::Ok; use slice::{mod, SlicePrelude}; use str::StrPrelude; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1d6906c13a8..9b67cdd3e12 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -17,9 +17,10 @@ use cell::{Cell, Ref, RefMut}; use iter::{Iterator, IteratorExt, range}; use kinds::{Copy, Sized}; use mem; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use ops::Deref; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use result; use slice::SlicePrelude; use slice; @@ -34,6 +35,7 @@ mod float; pub mod rt; #[experimental = "core and I/O reconciliation may alter this definition"] +/// The type returned by formatter methods. pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 347777b587a..ece2ac6975e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -10,7 +10,7 @@ //! rustc compiler intrinsics. //! -//! The corresponding definitions are in librustc/middle/trans/foreign.rs. +//! The corresponding definitions are in librustc_trans/trans/intrinsic.rs. //! //! # Volatiles //! diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index f9595f0663d..49865bd3c7d 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -62,7 +62,8 @@ use cmp::Ord; use mem; use num::{ToPrimitive, Int}; use ops::{Add, Deref}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use uint; #[deprecated = "renamed to Extend"] pub use self::Extend as Extendable; @@ -2036,18 +2037,49 @@ for Inspect<'a, A, T> { } } -/// An iterator which just modifies the contained state throughout iteration. +/// An iterator which passes mutable state to a closure and yields the result. +/// +/// # Example: The Fibonacci Sequence +/// +/// An iterator that yields sequential Fibonacci numbers, and stops on overflow. +/// +/// ```rust +/// use std::iter::Unfold; +/// use std::num::Int; // For `.checked_add()` +/// +/// // This iterator will yield up to the last Fibonacci number before the max value of `u32`. +/// // You can simply change `u32` to `u64` in this line if you want higher values than that. +/// let mut fibonacci = Unfold::new((Some(0u32), Some(1u32)), |&(ref mut x2, ref mut x1)| { +/// // Attempt to get the next Fibonacci number +/// // `x1` will be `None` if previously overflowed. +/// let next = match (*x2, *x1) { +/// (Some(x2), Some(x1)) => x2.checked_add(x1), +/// _ => None, +/// }; +/// +/// // Shift left: ret <- x2 <- x1 <- next +/// let ret = *x2; +/// *x2 = *x1; +/// *x1 = next; +/// +/// ret +/// }); +/// +/// for i in fibonacci { +/// println!("{}", i); +/// } +/// ``` #[experimental] pub struct Unfold<'a, A, St> { f: |&mut St|: 'a -> Option<A>, - /// Internal state that will be yielded on the next iteration + /// Internal state that will be passed to the closure on the next iteration pub state: St, } #[experimental] impl<'a, A, St> Unfold<'a, A, St> { /// Creates a new iterator with the specified closure as the "iterator - /// function" and an initial state to eventually pass to the iterator + /// function" and an initial state to eventually pass to the closure #[inline] pub fn new<'a>(initial_state: St, f: |&mut St|: 'a -> Option<A>) -> Unfold<'a, A, St> { @@ -2427,7 +2459,9 @@ pub fn repeat<T: Clone>(elt: T) -> Repeat<T> { pub mod order { use cmp; use cmp::{Eq, Ord, PartialOrd, PartialEq}; - use option::{Option, Some, None}; + use cmp::Ordering::{Equal, Less, Greater}; + use option::Option; + use option::Option::{Some, None}; use super::Iterator; /// Compare `a` and `b` for equality using `Eq` @@ -2445,11 +2479,11 @@ pub mod order { pub fn cmp<A: Ord, T: Iterator<A>, S: Iterator<A>>(mut a: T, mut b: S) -> cmp::Ordering { loop { match (a.next(), b.next()) { - (None, None) => return cmp::Equal, - (None, _ ) => return cmp::Less, - (_ , None) => return cmp::Greater, + (None, None) => return Equal, + (None, _ ) => return Less, + (_ , None) => return Greater, (Some(x), Some(y)) => match x.cmp(&y) { - cmp::Equal => (), + Equal => (), non_eq => return non_eq, }, } @@ -2461,11 +2495,11 @@ pub mod order { -> Option<cmp::Ordering> { loop { match (a.next(), b.next()) { - (None, None) => return Some(cmp::Equal), - (None, _ ) => return Some(cmp::Less), - (_ , None) => return Some(cmp::Greater), + (None, None) => return Some(Equal), + (None, _ ) => return Some(Less), + (_ , None) => return Some(Greater), (Some(x), Some(y)) => match x.partial_cmp(&y) { - Some(cmp::Equal) => (), + Some(Equal) => (), non_eq => return non_eq, }, } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ce61bd97e13..e6946c83ceb 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -30,7 +30,8 @@ use kinds::Copy; use mem::size_of; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use str::{FromStr, from_str, StrPrelude}; /// Simultaneous division and remainder @@ -284,7 +285,7 @@ pub trait Int /// ``` fn checked_add(self, other: Self) -> Option<Self>; - /// Checked integer subtraction. Computes `self + other`, returning `None` + /// Checked integer subtraction. Computes `self - other`, returning `None` /// if underflow occurred. /// /// # Example @@ -297,7 +298,7 @@ pub trait Int /// ``` fn checked_sub(self, other: Self) -> Option<Self>; - /// Checked integer multiplication. Computes `self + other`, returning + /// Checked integer multiplication. Computes `self * other`, returning /// `None` if underflow or overflow occurred. /// /// # Example @@ -310,8 +311,8 @@ pub trait Int /// ``` fn checked_mul(self, other: Self) -> Option<Self>; - /// Checked integer division. Computes `self + other` returning `None` if - /// `self == 0` or the operation results in underflow or overflow. + /// Checked integer division. Computes `self / other`, returning `None` if + /// `other == 0` or the operation results in underflow or overflow. /// /// # Example /// diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4f4ec486797..ce774a66381 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -787,7 +787,7 @@ impl<'a, Sized? T> Deref<T> for &'a mut T { /// } /// ``` #[lang="deref_mut"] -pub trait DerefMut<Sized? Result>: Deref<Result> { +pub trait DerefMut<Sized? Result> for Sized? : Deref<Result> { /// The method called to mutably dereference a value fn deref_mut<'a>(&'a mut self) -> &'a mut Result; } @@ -832,53 +832,3 @@ impl<F,A,R> FnOnce<A,R> for F self.call_mut(args) } } - -#[cfg(stage0)] -mod fn_impls { - use super::Fn; - - impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, _args: ()) -> Result { - (*self)() - } - } - - impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, args: (A0,)) -> Result { - let (a0,) = args; - (*self)(a0) - } - } - - macro_rules! def_fn( - ($($args:ident)*) => ( - impl<Result$(,$args)*> - Fn<($($args,)*),Result> - for extern "Rust" fn($($args: $args,)*) -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result { - let ($($args,)*) = args; - (*self)($($args,)*) - } - } - ) - ) - - def_fn!(A0 A1) - def_fn!(A0 A1 A2) - def_fn!(A0 A1 A2 A3) - def_fn!(A0 A1 A2 A3 A4) - def_fn!(A0 A1 A2 A3 A4 A5) - def_fn!(A0 A1 A2 A3 A4 A5 A6) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) - def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) -} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index ef895a1d7fb..8ba41c3575f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -149,7 +149,8 @@ use cmp::{Eq, Ord}; use default::Default; use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator}; use mem; -use result::{Result, Ok, Err}; +use result::Result; +use result::Result::{Ok, Err}; use slice; use slice::AsSlice; use clone::Clone; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 416bc4588b4..3f6ac49786d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -90,9 +90,12 @@ use mem; use clone::Clone; use intrinsics; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; -use cmp::{PartialEq, Eq, PartialOrd, Equiv, Ordering, Less, Equal, Greater}; +use cmp::{PartialEq, Eq, PartialOrd, Equiv}; +use cmp::Ordering; +use cmp::Ordering::{Less, Equal, Greater}; pub use intrinsics::copy_memory; pub use intrinsics::copy_nonoverlapping_memory; diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 7c88106c9ec..0cf8e6affd7 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -236,7 +236,8 @@ use std::fmt::Show; use slice; use slice::AsSlice; use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator}; -use option::{None, Option, Some}; +use option::Option; +use option::Option::{None, Some}; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). /// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 85bd6adf8b8..b8df36c91bc 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -36,13 +36,15 @@ use mem::transmute; use clone::Clone; -use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Less, Equal, Greater, Equiv}; +use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord, Equiv}; +use cmp::Ordering::{Less, Equal, Greater}; use cmp; use default::Default; use iter::*; use num::Int; use ops; -use option::{None, Option, Some}; +use option::Option; +use option::Option::{None, Some}; use ptr; use ptr::RawPtr; use mem; @@ -1702,7 +1704,8 @@ pub mod raw { use mem::transmute; use ptr::RawPtr; use raw::Slice; - use option::{None, Option, Some}; + use option::Option; + use option::Option::{None, Some}; /// Form a slice from a pointer and length (as a number of units, /// not bytes). @@ -1781,12 +1784,13 @@ pub mod bytes { /// Copies data from `src` to `dst` /// - /// `src` and `dst` must not overlap. Panics if the length of `dst` - /// is less than the length of `src`. + /// Panics if the length of `dst` is less than the length of `src`. #[inline] pub fn copy_memory(dst: &mut [u8], src: &[u8]) { let len_src = src.len(); assert!(dst.len() >= len_src); + // `dst` is unaliasable, so we know statically it doesn't overlap + // with `src`. unsafe { ptr::copy_nonoverlapping_memory(dst.as_mut_ptr(), src.as_ptr(), diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 4be628f0ac3..1d59567cbe4 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -29,7 +29,8 @@ use iter::range; use kinds::Sized; use mem; use num::Int; -use option::{Option, None, Some}; +use option::Option; +use option::Option::{None, Some}; use ptr::RawPtr; use raw::{Repr, Slice}; use slice::{mod, SlicePrelude}; @@ -1209,9 +1210,11 @@ Section: Trait implementations #[allow(missing_docs)] pub mod traits { - use cmp::{Ord, Ordering, Less, Equal, Greater, PartialEq, PartialOrd, Equiv, Eq}; + use cmp::{Ordering, Ord, PartialEq, PartialOrd, Equiv, Eq}; + use cmp::Ordering::{Less, Equal, Greater}; use iter::IteratorExt; - use option::{Option, Some}; + use option::Option; + use option::Option::Some; use ops; use str::{Str, StrPrelude, eq_slice}; diff --git a/src/libcore/tuple/mod.rs b/src/libcore/tuple/mod.rs index 56ea7a4e7a1..5ad01ae6744 100644 --- a/src/libcore/tuple/mod.rs +++ b/src/libcore/tuple/mod.rs @@ -69,7 +69,8 @@ pub use unit; use clone::Clone; use cmp::*; use default::Default; -use option::{Option, Some}; +use option::Option; +use option::Option::Some; // macro for implementing n-ary tuple functions and operations macro_rules! tuple_impls { diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 0cd1ded21d6..6ee3633d36c 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -48,7 +48,8 @@ pub fn test_num<T>(ten: T, two: T) where #[cfg(test)] mod test { - use core::option::{Option, Some, None}; + use core::option::Option; + use core::option::Option::{Some, None}; use core::num::Float; use core::num::from_str_radix; diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 6b8fafbed5d..03b65b3f71c 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -18,6 +18,11 @@ #![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/", + html_playground_url = "http://play.rust-lang.org/")] + #![feature(macro_rules, globs, import_shadowing)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 1204ac18f99..e146e3c76eb 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -99,7 +99,7 @@ use self::Fail::*; use self::Optval::*; use std::fmt; -use std::result::{Err, Ok}; +use std::result::Result::{Err, Ok}; use std::result; use std::string::String; @@ -951,7 +951,7 @@ mod tests { use super::*; use super::Fail::*; - use std::result::{Err, Ok}; + use std::result::Result::{Err, Ok}; use std::result; // Tests for reqopt @@ -1392,8 +1392,8 @@ mod tests { let args_single = vec!("-e".to_string(), "foo".to_string()); let matches_single = &match getopts(args_single.as_slice(), opts.as_slice()) { - result::Ok(m) => m, - result::Err(_) => panic!() + result::Result::Ok(m) => m, + result::Result::Err(_) => panic!() }; assert!(matches_single.opts_present(&["e".to_string()])); assert!(matches_single.opts_present(&["encrypt".to_string(), "e".to_string()])); @@ -1412,8 +1412,8 @@ mod tests { "foo".to_string()); let matches_both = &match getopts(args_both.as_slice(), opts.as_slice()) { - result::Ok(m) => m, - result::Err(_) => panic!() + result::Result::Ok(m) => m, + result::Result::Err(_) => panic!() }; assert!(matches_both.opts_present(&["e".to_string()])); assert!(matches_both.opts_present(&["encrypt".to_string()])); @@ -1437,8 +1437,8 @@ mod tests { let opts = vec!(optmulti("L", "", "library directory", "LIB"), optmulti("M", "", "something", "MMMM")); let matches = &match getopts(args.as_slice(), opts.as_slice()) { - result::Ok(m) => m, - result::Err(_) => panic!() + result::Result::Ok(m) => m, + result::Result::Err(_) => panic!() }; assert!(matches.opts_present(&["L".to_string()])); assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "foo".to_string()); @@ -1453,8 +1453,8 @@ mod tests { let opts = vec!(optmulti("L", "", "library directory", "LIB"), optflagmulti("v", "verbose", "Verbose")); let matches = &match getopts(args.as_slice(), opts.as_slice()) { - result::Ok(m) => m, - result::Err(e) => panic!( "{}", e ) + result::Result::Ok(m) => m, + result::Result::Err(e) => panic!( "{}", e ) }; assert!(matches.opts_present(&["L".to_string()])); assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "verbose".to_string()); diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 6f3fbe12510..f65c4f4e3ed 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -120,7 +120,8 @@ pub mod reader { use std::io::extensions::u64_from_be_bytes; use std::mem::transmute; use std::num::Int; - use std::option::{None, Option, Some}; + use std::option::Option; + use std::option::Option::{None, Some}; use serialize; @@ -1060,7 +1061,8 @@ mod tests { use serialize::{Encodable, Decodable}; - use std::option::{None, Option, Some}; + use std::option::Option; + use std::option::Option::{None, Some}; #[test] fn test_vuint_at() { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a83f8afd396..a964609e4e6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -59,6 +59,7 @@ pub mod back { } pub mod middle { + pub mod astconv_util; pub mod astencode; pub mod borrowck; pub mod cfg; @@ -79,6 +80,7 @@ pub mod middle { pub mod fast_reject; pub mod graph; pub mod intrinsicck; + pub mod infer; pub mod lang_items; pub mod liveness; pub mod mem_categorization; @@ -93,7 +95,6 @@ pub mod middle { pub mod traits; pub mod ty; pub mod ty_fold; - pub mod typeck; pub mod weak_lang_items; } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 9a214d531d1..b0ac98c94e7 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -29,8 +29,6 @@ use self::MethodContext::*; use metadata::csearch; use middle::def::*; use middle::ty::{mod, Ty}; -use middle::typeck::astconv::ast_ty_to_ty; -use middle::typeck::{mod, infer}; use middle::{def, pat_util, stability}; use middle::const_eval::{eval_const_expr_partial, const_int, const_uint}; use util::ppaux::{ty_to_string}; @@ -84,7 +82,7 @@ impl LintPass for UnusedCasts { fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { if let ast::ExprCast(ref expr, ref ty) = e.node { - let t_t = ast_ty_to_ty(cx, &infer::new_infer_ctxt(cx.tcx), &**ty); + let t_t = ty::expr_ty(cx.tcx, e); if ty::expr_ty(cx.tcx, &**expr) == t_t { cx.span_lint(UNUSED_TYPECASTS, ty.span, "unnecessary type cast"); } @@ -1430,6 +1428,7 @@ impl LintPass for MissingDoc { ast::ItemEnum(..) => "an enum", ast::ItemStruct(..) => "a struct", ast::ItemTrait(..) => "a trait", + ast::ItemTy(..) => "a type alias", _ => return }; self.check_missing_docs_attrs(cx, Some(it.id), it.attrs.as_slice(), @@ -1589,22 +1588,22 @@ impl LintPass for Stability { } ast::ExprMethodCall(i, _, _) => { span = i.span; - let method_call = typeck::MethodCall::expr(e.id); + let method_call = ty::MethodCall::expr(e.id); match cx.tcx.method_map.borrow().get(&method_call) { Some(method) => { match method.origin { - typeck::MethodStatic(def_id) => { + ty::MethodStatic(def_id) => { def_id } - typeck::MethodStaticUnboxedClosure(def_id) => { + ty::MethodStaticUnboxedClosure(def_id) => { def_id } - typeck::MethodTypeParam(typeck::MethodParam { + ty::MethodTypeParam(ty::MethodParam { ref trait_ref, method_num: index, .. }) | - typeck::MethodTraitObject(typeck::MethodObject { + ty::MethodTraitObject(ty::MethodObject { ref trait_ref, method_num: index, .. diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index c7bed838eb9..442d3aab92d 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -26,17 +26,13 @@ use self::TargetLint::*; use middle::privacy::ExportedItems; -use middle::subst; use middle::ty::{mod, Ty}; -use middle::typeck::astconv::AstConv; -use middle::typeck::infer; use session::{early_error, Session}; use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; use util::nodemap::FnvHashMap; -use std::rc::Rc; use std::cell::RefCell; use std::tuple::Tuple2; use std::mem; @@ -541,42 +537,6 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } } -impl<'a, 'tcx> AstConv<'tcx> for Context<'a, 'tcx>{ - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - ty::lookup_item_type(self.tcx, id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>> { - ty::lookup_trait_def(self.tcx, id) - } - - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { - infer::new_infer_ctxt(self.tcx).next_ty_var() - } - - fn associated_types_of_trait_are_valid(&self, _: Ty<'tcx>, _: ast::DefId) - -> bool { - // FIXME(pcwalton): This is wrong. - true - } - - fn associated_type_binding(&self, - _: Span, - _: Option<Ty<'tcx>>, - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Ty<'tcx> { - // FIXME(pcwalton): This is wrong. - let trait_def = self.get_trait_def(trait_id); - let index = ty::associated_type_parameter_index(self.tcx, - &*trait_def, - associated_type_id); - ty::mk_param(self.tcx, subst::TypeSpace, index, associated_type_id) - } -} - impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { fn visit_item(&mut self, it: &ast::Item) { self.with_lint_attrs(it.attrs.as_slice(), |cx| { diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 20e3f27f2ae..ebf5cca6a31 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -21,7 +21,6 @@ use middle::def; use middle::lang_items; use middle::resolve; use middle::ty; -use middle::typeck; use middle::subst::VecPerParamSpace; use rbml; @@ -268,7 +267,7 @@ pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, // Given a def_id for an impl, return information about its vtables pub fn get_impl_vtables<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) - -> typeck::vtable_res<'tcx> { + -> ty::vtable_res<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_impl_vtables(&*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index ec812cea372..f352a28df69 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -30,7 +30,6 @@ use middle::resolve::{TraitItemKind, TypeTraitItemKind}; use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty::{mod, Ty}; -use middle::typeck; use middle::astencode::vtable_decoder_helpers; use std::hash::Hash; @@ -422,7 +421,7 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd, pub fn get_impl_vtables<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> typeck::vtable_res<'tcx> + -> ty::vtable_res<'tcx> { let item_doc = lookup_item(id, cdata.data()); let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs new file mode 100644 index 00000000000..6b90bcd60e7 --- /dev/null +++ b/src/librustc/middle/astconv_util.rs @@ -0,0 +1,89 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * This module contains a simple utility routine + * used by both `typeck` and `const_eval`. + * Almost certainly this could (and should) be refactored out of existence. + */ + +use middle::def; +use middle::ty::{mod, Ty}; +use syntax::ast; +use util::ppaux::Repr; + +pub const NO_REGIONS: uint = 1; +pub const NO_TPS: uint = 2; + +pub fn check_path_args(tcx: &ty::ctxt, + path: &ast::Path, + flags: uint) { + if (flags & NO_TPS) != 0u { + if path.segments.iter().any(|s| s.parameters.has_types()) { + span_err!(tcx.sess, path.span, E0109, + "type parameters are not allowed on this type"); + } + } + + if (flags & NO_REGIONS) != 0u { + if path.segments.iter().any(|s| s.parameters.has_lifetimes()) { + span_err!(tcx.sess, path.span, E0110, + "region parameters are not allowed on this type"); + } + } +} + +pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) + -> Option<Ty<'tcx>> { + match ast_ty.node { + ast::TyPath(ref path, id) => { + let a_def = match tcx.def_map.borrow().get(&id) { + None => { + tcx.sess.span_bug(ast_ty.span, + format!("unbound path {}", + path.repr(tcx)).as_slice()) + } + Some(&d) => d + }; + match a_def { + def::DefPrimTy(nty) => { + match nty { + ast::TyBool => { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + Some(ty::mk_bool()) + } + ast::TyChar => { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + Some(ty::mk_char()) + } + ast::TyInt(it) => { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + Some(ty::mk_mach_int(it)) + } + ast::TyUint(uit) => { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + Some(ty::mk_mach_uint(uit)) + } + ast::TyFloat(ft) => { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + Some(ty::mk_mach_float(ft)) + } + ast::TyStr => { + Some(ty::mk_str(tcx)) + } + } + } + _ => None + } + } + _ => None + } +} + diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 523e997a8de..113d127503f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -26,8 +26,7 @@ use metadata::tyencode; use middle::mem_categorization::Typer; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::typeck::{mod, MethodCall, MethodCallee, MethodOrigin}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, MethodCall, MethodCallee, MethodOrigin}; use util::ppaux::ty_to_string; use syntax::{ast, ast_map, ast_util, codemap, fold}; @@ -576,12 +575,12 @@ impl tr for ty::UpvarBorrow { trait read_method_callee_helper<'tcx> { fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (typeck::ExprAdjustment, MethodCallee<'tcx>); + -> (ty::ExprAdjustment, MethodCallee<'tcx>); } fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - adjustment: typeck::ExprAdjustment, + adjustment: ty::ExprAdjustment, method: &MethodCallee<'tcx>) { use serialize::Encoder; @@ -603,7 +602,7 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (typeck::ExprAdjustment, MethodCallee<'tcx>) { + -> (ty::ExprAdjustment, MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { let adjustment = this.read_struct_field("adjustment", 0, |this| { @@ -627,22 +626,22 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { impl<'tcx> tr for MethodOrigin<'tcx> { fn tr(&self, dcx: &DecodeContext) -> MethodOrigin<'tcx> { match *self { - typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(dcx)), - typeck::MethodStaticUnboxedClosure(did) => { - typeck::MethodStaticUnboxedClosure(did.tr(dcx)) + ty::MethodStatic(did) => ty::MethodStatic(did.tr(dcx)), + ty::MethodStaticUnboxedClosure(did) => { + ty::MethodStaticUnboxedClosure(did.tr(dcx)) } - typeck::MethodTypeParam(ref mp) => { - typeck::MethodTypeParam( - typeck::MethodParam { + ty::MethodTypeParam(ref mp) => { + ty::MethodTypeParam( + ty::MethodParam { // def-id is already translated when we read it out trait_ref: mp.trait_ref.clone(), method_num: mp.method_num, } ) } - typeck::MethodTraitObject(ref mo) => { - typeck::MethodTraitObject( - typeck::MethodObject { + ty::MethodTraitObject(ref mo) => { + ty::MethodTraitObject( + ty::MethodObject { trait_ref: mo.trait_ref.clone(), .. *mo } @@ -687,16 +686,16 @@ pub trait vtable_decoder_helpers<'tcx> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (typeck::ExprAdjustment, typeck::vtable_res<'tcx>); + -> (ty::ExprAdjustment, ty::vtable_res<'tcx>); fn read_vtable_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_res<'tcx>; + -> ty::vtable_res<'tcx>; fn read_vtable_param_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_param_res<'tcx>; + -> ty::vtable_param_res<'tcx>; fn read_vtable_origin(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_origin<'tcx>; + -> ty::vtable_origin<'tcx>; } impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { @@ -714,7 +713,7 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (typeck::ExprAdjustment, typeck::vtable_res<'tcx>) { + -> (ty::ExprAdjustment, ty::vtable_res<'tcx>) { self.read_struct("VtableWithKey", 2, |this| { let adjustment = this.read_struct_field("adjustment", 0, |this| { Decodable::decode(this) @@ -728,7 +727,7 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_vtable_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_res<'tcx> + -> ty::vtable_res<'tcx> { self.read_vec_per_param_space( |this| this.read_vtable_param_res(tcx, cdata)) @@ -736,14 +735,14 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_vtable_param_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_param_res<'tcx> { + -> ty::vtable_param_res<'tcx> { self.read_to_vec(|this| Ok(this.read_vtable_origin(tcx, cdata))) .unwrap().into_iter().collect() } fn read_vtable_origin(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> typeck::vtable_origin<'tcx> { + -> ty::vtable_origin<'tcx> { self.read_enum("vtable_origin", |this| { this.read_enum_variant(&["vtable_static", "vtable_param", @@ -752,7 +751,7 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { |this, i| { Ok(match i { 0 => { - typeck::vtable_static( + ty::vtable_static( this.read_enum_variant_arg(0u, |this| { Ok(this.read_def_id_nodcx(cdata)) }).unwrap(), @@ -765,7 +764,7 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { ) } 1 => { - typeck::vtable_param( + ty::vtable_param( this.read_enum_variant_arg(0u, |this| { Decodable::decode(this) }).unwrap(), @@ -775,14 +774,14 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { ) } 2 => { - typeck::vtable_unboxed_closure( + ty::vtable_unboxed_closure( this.read_enum_variant_arg(0u, |this| { Ok(this.read_def_id_nodcx(cdata)) }).unwrap() ) } 3 => { - typeck::vtable_error + ty::vtable_error } _ => panic!("bad enum variant") }) @@ -826,7 +825,7 @@ trait rbml_writer_helpers<'tcx> { closure_type: &ty::ClosureTy<'tcx>); fn emit_method_origin<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - method_origin: &typeck::MethodOrigin<'tcx>); + method_origin: &ty::MethodOrigin<'tcx>); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, @@ -860,25 +859,25 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { fn emit_method_origin<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - method_origin: &typeck::MethodOrigin<'tcx>) + method_origin: &ty::MethodOrigin<'tcx>) { use serialize::Encoder; self.emit_enum("MethodOrigin", |this| { match *method_origin { - typeck::MethodStatic(def_id) => { + ty::MethodStatic(def_id) => { this.emit_enum_variant("MethodStatic", 0, 1, |this| { Ok(this.emit_def_id(def_id)) }) } - typeck::MethodStaticUnboxedClosure(def_id) => { + ty::MethodStaticUnboxedClosure(def_id) => { this.emit_enum_variant("MethodStaticUnboxedClosure", 1, 1, |this| { Ok(this.emit_def_id(def_id)) }) } - typeck::MethodTypeParam(ref p) => { + ty::MethodTypeParam(ref p) => { this.emit_enum_variant("MethodTypeParam", 2, 1, |this| { this.emit_struct("MethodParam", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { @@ -892,7 +891,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }) } - typeck::MethodTraitObject(ref o) => { + ty::MethodTraitObject(ref o) => { this.emit_enum_variant("MethodTraitObject", 3, 1, |this| { this.emit_struct("MethodObject", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { @@ -1330,7 +1329,7 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> { trait rbml_decoder_decoder_helpers<'tcx> { fn read_method_origin<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> typeck::MethodOrigin<'tcx>; + -> ty::MethodOrigin<'tcx>; fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1409,7 +1408,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_method_origin<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> typeck::MethodOrigin<'tcx> + -> ty::MethodOrigin<'tcx> { self.read_enum("MethodOrigin", |this| { let variants = &["MethodStatic", "MethodStaticUnboxedClosure", @@ -1418,18 +1417,18 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(match i { 0 => { let def_id = this.read_def_id(dcx); - typeck::MethodStatic(def_id) + ty::MethodStatic(def_id) } 1 => { let def_id = this.read_def_id(dcx); - typeck::MethodStaticUnboxedClosure(def_id) + ty::MethodStaticUnboxedClosure(def_id) } 2 => { this.read_struct("MethodTypeParam", 2, |this| { - Ok(typeck::MethodTypeParam( - typeck::MethodParam { + Ok(ty::MethodTypeParam( + ty::MethodParam { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { Ok(this.read_trait_ref(dcx)) @@ -1446,8 +1445,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 3 => { this.read_struct("MethodTraitObject", 2, |this| { - Ok(typeck::MethodTraitObject( - typeck::MethodObject { + Ok(ty::MethodTraitObject( + ty::MethodObject { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { Ok(this.read_trait_ref(dcx)) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index b42fb8ccc41..90919609e2e 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -12,7 +12,6 @@ use middle::cfg::*; use middle::def; use middle::graph; use middle::region::CodeExtent; -use middle::typeck; use middle::ty; use syntax::ast; use syntax::ast_util; @@ -510,7 +509,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { pred: CFGIndex, func_or_rcvr: &ast::Expr, args: I) -> CFGIndex { - let method_call = typeck::MethodCall::expr(call_expr.id); + let method_call = ty::MethodCall::expr(call_expr.id); let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) { Some(method) => method.ty, None => ty::expr_ty(self.tcx, func_or_rcvr) @@ -635,7 +634,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } fn is_method_call(&self, expr: &ast::Expr) -> bool { - let method_call = typeck::MethodCall::expr(expr.id); + let method_call = ty::MethodCall::expr(expr.id); self.tcx.method_map.borrow().contains_key(&method_call) } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 8cb63fcd827..de140fd5c30 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -11,7 +11,6 @@ use middle::def::*; use middle::ty; -use middle::typeck; use util::ppaux; use syntax::ast; @@ -111,7 +110,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { } ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {} ast::ExprBinary(..) | ast::ExprUnary(..) => { - let method_call = typeck::MethodCall::expr(e.id); + let method_call = ty::MethodCall::expr(e.id); if v.tcx.method_map.borrow().contains_key(&method_call) { span_err!(v.tcx.sess, e.span, E0011, "user-defined operators are not allowed in constant \ diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index d3c7ccf65dd..2fc85afd393 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -27,7 +27,7 @@ use self::Mode::*; use middle::ty; use middle::def; -use middle::typeck; +use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; @@ -113,7 +113,7 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { fn check_static_type(&self, e: &ast::Expr) { let ty = ty::node_id_to_type(self.tcx, e.id); - let infcx = typeck::infer::new_infer_ctxt(self.tcx); + let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); let cause = traits::ObligationCause::misc(DUMMY_SP); let obligation = traits::obligation_for_builtin_bound(self.tcx, cause, ty, diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d5a292b9f09..43726f55bb9 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -17,8 +17,8 @@ pub use self::constness::*; use metadata::csearch; use middle::{astencode, def}; use middle::pat_util::def_to_path; -use middle::ty::{mod, Ty}; -use middle::typeck::{astconv, check}; +use middle::ty::{mod}; +use middle::astconv_util::{ast_ty_to_prim_ty}; use util::nodemap::DefIdMap; use syntax::ast::{mod, Expr}; @@ -277,14 +277,6 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> { } impl<'a, 'tcx, 'v> Visitor<'v> for ConstEvalVisitor<'a, 'tcx> { - fn visit_ty(&mut self, t: &ast::Ty) { - if let ast::TyFixedLengthVec(_, ref expr) = t.node { - check::check_const_in_type(self.tcx, &**expr, ty::mk_uint()); - } - - visit::walk_ty(self, t); - } - fn visit_expr_post(&mut self, e: &Expr) { self.classify(e); } @@ -504,7 +496,7 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St // populated in the ctxt, which was causing things to blow up // (#5900). Fall back to doing a limited lookup to get past it. let ety = ty::expr_ty_opt(tcx, e) - .or_else(|| astconv::ast_ty_to_prim_ty(tcx, &**target_ty)) + .or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty)) .unwrap_or_else(|| { tcx.sess.span_fatal(target_ty.span, "target type not found for const cast") diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index cf2e9a65859..03fe8782421 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -12,7 +12,7 @@ // closely. The idea is that all reachable symbols are live, codes called // from live codes are live, and everything else is dead. -use middle::{def, pat_util, privacy, ty, typeck}; +use middle::{def, pat_util, privacy, ty}; use lint; use util::nodemap::NodeSet; @@ -90,23 +90,23 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_method(&mut self, id: ast::NodeId, span: codemap::Span) { - let method_call = typeck::MethodCall::expr(id); + let method_call = ty::MethodCall::expr(id); match self.tcx.method_map.borrow().get(&method_call) { Some(method) => { match method.origin { - typeck::MethodStatic(def_id) => { + ty::MethodStatic(def_id) => { match ty::provided_source(self.tcx, def_id) { Some(p_did) => self.check_def_id(p_did), None => self.check_def_id(def_id) } } - typeck::MethodStaticUnboxedClosure(_) => {} - typeck::MethodTypeParam(typeck::MethodParam { + ty::MethodStaticUnboxedClosure(_) => {} + ty::MethodTypeParam(ty::MethodParam { ref trait_ref, method_num: index, .. }) | - typeck::MethodTraitObject(typeck::MethodObject { + ty::MethodTraitObject(ty::MethodObject { ref trait_ref, method_num: index, .. diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index e67df0332dc..dbec69f4205 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -14,7 +14,7 @@ use self::UnsafeContext::*; use middle::def; use middle::ty::{mod, Ty}; -use middle::typeck::MethodCall; +use middle::ty::MethodCall; use util::ppaux; use syntax::ast; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index cbf36aeff51..7d2bb7458ac 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -24,10 +24,9 @@ use middle::{def, region, pat_util}; use middle::mem_categorization as mc; use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::typeck::{MethodCall, MethodObject, MethodTraitObject}; -use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam}; -use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure}; -use middle::typeck; +use middle::ty::{MethodCall, MethodObject, MethodTraitObject}; +use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam}; +use middle::ty::{MethodStatic, MethodStaticUnboxedClosure}; use util::ppaux::Repr; use syntax::ast; @@ -825,7 +824,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); for i in range(0, autoderefs) { - let deref_id = typeck::MethodCall::autoderef(expr.id, i); + let deref_id = ty::MethodCall::autoderef(expr.id, i); match self.typer.node_method_ty(deref_id) { None => {} Some(method_ty) => { diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 51f8668692e..f04c519badc 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -60,14 +60,15 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. +use super::{CoerceResult, resolve_type, Coercion}; +use super::combine::{CombineFields, Combine}; +use super::sub::Sub; +use super::resolve::try_resolve_tvar_shallow; + use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{mt}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; -use middle::typeck::infer::combine::{CombineFields, Combine}; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use util::ppaux; use util::ppaux::Repr; diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/infer/combine.rs index ba6ae00b667..ab9c5b86aeb 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -32,6 +32,14 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::equate::Equate; +use super::glb::Glb; +use super::lub::Lub; +use super::sub::Sub; +use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; +use super::{InferCtxt, cres}; +use super::{MiscVariable, TypeTrace}; +use super::type_variable::{RelationDir, EqTo, SubtypeOf, SupertypeOf}; use middle::subst; use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; @@ -40,15 +48,6 @@ use middle::ty::{IntType, UintType}; use middle::ty::{BuiltinBounds}; use middle::ty::{mod, Ty}; use middle::ty_fold; -use middle::typeck::infer::equate::Equate; -use middle::typeck::infer::glb::Glb; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes; -use middle::typeck::infer::{InferCtxt, cres}; -use middle::typeck::infer::{MiscVariable, TypeTrace}; -use middle::typeck::infer::type_variable::{RelationDir, EqTo, - SubtypeOf, SupertypeOf}; use middle::ty_fold::{TypeFoldable}; use util::ppaux::Repr; diff --git a/src/librustc/middle/typeck/infer/doc.rs b/src/librustc/middle/infer/doc.rs index 0e3cc5f68c8..0e3cc5f68c8 100644 --- a/src/librustc/middle/typeck/infer/doc.rs +++ b/src/librustc/middle/infer/doc.rs diff --git a/src/librustc/middle/typeck/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 356081c199a..a79a50b1781 100644 --- a/src/librustc/middle/typeck/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -11,14 +11,14 @@ use middle::ty::{BuiltinBounds}; use middle::ty::{mod, Ty}; use middle::ty::TyVar; -use middle::typeck::infer::combine::*; -use middle::typeck::infer::{cres}; -use middle::typeck::infer::glb::Glb; -use middle::typeck::infer::InferCtxt; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::{TypeTrace, Subtype}; -use middle::typeck::infer::type_variable::{EqTo}; +use middle::infer::combine::*; +use middle::infer::{cres}; +use middle::infer::glb::Glb; +use middle::infer::InferCtxt; +use middle::infer::lub::Lub; +use middle::infer::sub::Sub; +use middle::infer::{TypeTrace, Subtype}; +use middle::infer::type_variable::{EqTo}; use util::ppaux::{Repr}; use syntax::ast::{Onceness, FnStyle}; diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 0607ccdc595..657ee088758 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -57,24 +57,25 @@ use self::FreshOrKept::*; +use super::InferCtxt; +use super::TypeTrace; +use super::SubregionOrigin; +use super::RegionVariableOrigin; +use super::ValuePairs; +use super::region_inference::RegionResolutionError; +use super::region_inference::ConcreteFailure; +use super::region_inference::SubSupConflict; +use super::region_inference::SupSupConflict; +use super::region_inference::ParamBoundFailure; +use super::region_inference::ProcessedErrors; +use super::region_inference::SameRegions; + use std::collections::HashSet; use middle::def; +use middle::infer; use middle::subst; use middle::ty::{mod, Ty}; use middle::ty::{Region, ReFree}; -use middle::typeck::infer; -use middle::typeck::infer::InferCtxt; -use middle::typeck::infer::TypeTrace; -use middle::typeck::infer::SubregionOrigin; -use middle::typeck::infer::RegionVariableOrigin; -use middle::typeck::infer::ValuePairs; -use middle::typeck::infer::region_inference::RegionResolutionError; -use middle::typeck::infer::region_inference::ConcreteFailure; -use middle::typeck::infer::region_inference::SubSupConflict; -use middle::typeck::infer::region_inference::SupSupConflict; -use middle::typeck::infer::region_inference::ParamBoundFailure; -use middle::typeck::infer::region_inference::ProcessedErrors; -use middle::typeck::infer::region_inference::SameRegions; use std::cell::{Cell, RefCell}; use std::char::from_u32; use std::rc::Rc; diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 671d2e3837c..4237a7af32f 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::combine::*; +use super::lattice::*; +use super::equate::Equate; +use super::higher_ranked::HigherRankedRelations; +use super::lub::Lub; +use super::sub::Sub; +use super::{cres, InferCtxt}; +use super::{TypeTrace, Subtype}; use middle::ty::{BuiltinBounds}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::combine::*; -use middle::typeck::infer::lattice::*; -use middle::typeck::infer::equate::Equate; -use middle::typeck::infer::higher_ranked::HigherRankedRelations; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::{cres, InferCtxt}; -use middle::typeck::infer::{TypeTrace, Subtype}; use syntax::ast::{Many, Once, MutImmutable, MutMutable}; use syntax::ast::{NormalFn, UnsafeFn}; use syntax::ast::{Onceness, FnStyle}; diff --git a/src/librustc/middle/typeck/infer/higher_ranked/doc.rs b/src/librustc/middle/infer/higher_ranked/doc.rs index 2bad3616a05..2bad3616a05 100644 --- a/src/librustc/middle/typeck/infer/higher_ranked/doc.rs +++ b/src/librustc/middle/infer/higher_ranked/doc.rs diff --git a/src/librustc/middle/typeck/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 2f80a574bb1..95805ef8b94 100644 --- a/src/librustc/middle/typeck/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,10 +11,11 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. +use super::{combine, cres, InferCtxt, HigherRankedType}; +use super::combine::Combine; +use super::region_inference::{RegionMark}; + use middle::ty::{mod, Ty, replace_late_bound_regions}; -use middle::typeck::infer::{mod, combine, cres, InferCtxt}; -use middle::typeck::infer::combine::Combine; -use middle::typeck::infer::region_inference::{RegionMark}; use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; use syntax::codemap::Span; use util::nodemap::FnvHashMap; @@ -62,7 +63,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C let (a_prime, _) = self.infcx().replace_late_bound_regions_with_fresh_var( self.trace().origin.span(), - infer::HigherRankedType, + HigherRankedType, a); // Second, we instantiate each bound region in the supertype with a @@ -131,10 +132,10 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C let span = self.trace().origin.span(); let (a_with_fresh, a_map) = self.infcx().replace_late_bound_regions_with_fresh_var( - span, infer::HigherRankedType, a); + span, HigherRankedType, a); let (b_with_fresh, _) = self.infcx().replace_late_bound_regions_with_fresh_var( - span, infer::HigherRankedType, b); + span, HigherRankedType, b); // Collect constraints. let result0 = @@ -221,10 +222,10 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), infer::HigherRankedType, a); + self.trace().origin.span(), HigherRankedType, a); let (b_with_fresh, b_map) = self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), infer::HigherRankedType, b); + self.trace().origin.span(), HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index daec959d11c..dd514ebee52 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -29,12 +29,13 @@ //! over a `LatticeValue`, which is a value defined with respect to //! a lattice. +use super::*; +use super::combine::*; +use super::glb::Glb; +use super::lub::Lub; + use middle::ty::{TyVar}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::*; -use middle::typeck::infer::combine::*; -use middle::typeck::infer::glb::Glb; -use middle::typeck::infer::lub::Lub; use util::ppaux::Repr; pub trait LatticeDir<'tcx> { diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/infer/lub.rs index e7bd1f3716c..f53ba571062 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -8,16 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::combine::*; +use super::equate::Equate; +use super::glb::Glb; +use super::higher_ranked::HigherRankedRelations; +use super::lattice::*; +use super::sub::Sub; +use super::{cres, InferCtxt}; +use super::{TypeTrace, Subtype}; + use middle::ty::{BuiltinBounds}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::combine::*; -use middle::typeck::infer::equate::Equate; -use middle::typeck::infer::glb::Glb; -use middle::typeck::infer::higher_ranked::HigherRankedRelations; -use middle::typeck::infer::lattice::*; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::{cres, InferCtxt}; -use middle::typeck::infer::{TypeTrace, Subtype}; use syntax::ast::{Many, Once}; use syntax::ast::{NormalFn, UnsafeFn}; use syntax::ast::{Onceness, FnStyle}; diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/infer/mod.rs index c5845b143af..c5845b143af 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs diff --git a/src/librustc/middle/typeck/infer/region_inference/doc.rs b/src/librustc/middle/infer/region_inference/doc.rs index b4eac4c0026..686174b7306 100644 --- a/src/librustc/middle/typeck/infer/region_inference/doc.rs +++ b/src/librustc/middle/infer/region_inference/doc.rs @@ -371,4 +371,4 @@ //! ### Skolemization //! //! For a discussion on skolemization and higher-ranked subtyping, please -//! see the module `middle::typeck::infer::higher_ranked::doc`. +//! see the module `middle::infer::higher_ranked::doc`. diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index e39fbe105dc..9155c18cb3b 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -18,14 +18,14 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use self::Classification::*; +use super::cres; +use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; + use middle::region; use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; -use middle::typeck::infer::cres; -use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace}; -use middle::typeck::infer; use middle::graph; use middle::graph::{Direction, NodeIndex}; use util::common::indenter; @@ -573,7 +573,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } None => {} } - let c = self.new_region_var(infer::MiscVariable(origin.span())); + let c = self.new_region_var(MiscVariable(origin.span())); self.combine_map(t).borrow_mut().insert(vars, c); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddCombination(t, vars)); diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index cf5efd188ed..eaf363ffc74 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -48,12 +48,13 @@ #![allow(non_upper_case_globals)] +use super::{fixup_err, fres, InferCtxt}; +use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; + use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{IntType, UintType}; use middle::ty::{mod, Ty}; use middle::ty_fold; -use middle::typeck::infer::{fixup_err, fres, InferCtxt}; -use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; use syntax::codemap::Span; use util::ppaux::{Repr, ty_to_string}; diff --git a/src/librustc/middle/typeck/infer/skolemize.rs b/src/librustc/middle/infer/skolemize.rs index 62bf1d0126a..62bf1d0126a 100644 --- a/src/librustc/middle/typeck/infer/skolemize.rs +++ b/src/librustc/middle/infer/skolemize.rs diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 65d2a513393..c470b248827 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -8,19 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::combine::*; +use super::{cres, CresCompare}; +use super::equate::Equate; +use super::glb::Glb; +use super::higher_ranked::HigherRankedRelations; +use super::InferCtxt; +use super::lub::Lub; +use super::{TypeTrace, Subtype}; +use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{BuiltinBounds}; use middle::ty::{mod, Ty}; use middle::ty::TyVar; -use middle::typeck::infer::combine::*; -use middle::typeck::infer::{cres, CresCompare}; -use middle::typeck::infer::equate::Equate; -use middle::typeck::infer::glb::Glb; -use middle::typeck::infer::higher_ranked::HigherRankedRelations; -use middle::typeck::infer::InferCtxt; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::{TypeTrace, Subtype}; -use middle::typeck::infer::type_variable::{SubtypeOf, SupertypeOf}; use util::ppaux::{Repr}; use syntax::ast::{Onceness, FnStyle, MutImmutable, MutMutable}; diff --git a/src/librustc/middle/typeck/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 3058f09a83a..3058f09a83a 100644 --- a/src/librustc/middle/typeck/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 1b3413bfb01..6f6adb84a75 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -14,8 +14,8 @@ use std::kinds::marker; use middle::ty::{expected_found, IntVarValue}; use middle::ty::{mod, Ty}; -use middle::typeck::infer::{uok, ures}; -use middle::typeck::infer::InferCtxt; +use middle::infer::{uok, ures}; +use middle::infer::InferCtxt; use std::cell::RefCell; use std::fmt::Show; use syntax::ast; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index fcc23d8ac55..523c9f33309 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,7 +111,7 @@ use self::VarKind::*; use middle::def::*; use middle::mem_categorization::Typer; -use middle::{pat_util, typeck, ty}; +use middle::{pat_util, ty}; use lint; use util::nodemap::NodeMap; @@ -1156,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } ast::ExprMethodCall(_, _, ref args) => { - let method_call = typeck::MethodCall::expr(expr.id); + let method_call = ty::MethodCall::expr(expr.id); let method_ty = self.ir.tcx.method_map.borrow().get(&method_call).unwrap().ty; let diverges = ty::ty_fn_ret(method_ty) == ty::FnDiverging; let succ = if diverges { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ce166fc5de6..cd70d8e2b48 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -74,7 +74,6 @@ pub use self::categorization::*; use middle::def; use middle::region; use middle::ty::{mod, Ty}; -use middle::typeck; use util::nodemap::{DefIdMap, NodeMap}; use util::ppaux::{ty_to_string, Repr}; @@ -283,7 +282,7 @@ pub type McResult<T> = Result<T, ()>; pub trait Typer<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>; - fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<Ty<'tcx>>; + fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>>; fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>; fn is_method_call(&self, id: ast::NodeId) -> bool; fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>; @@ -509,7 +508,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } ast::ExprIndex(ref base, _) => { - let method_call = typeck::MethodCall::expr(expr.id()); + let method_call = ty::MethodCall::expr(expr.id()); match self.typer.node_method_ty(method_call) { Some(method_ty) => { // If this is an index implemented by a method call, then it will @@ -890,12 +889,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { implicit: bool) -> cmt<'tcx> { let adjustment = match self.typer.adjustments().borrow().get(&node.id()) { - Some(adj) if ty::adjust_is_object(adj) => typeck::AutoObject, - _ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt), - _ => typeck::NoAdjustment + Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject, + _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt), + _ => ty::NoAdjustment }; - let method_call = typeck::MethodCall { + let method_call = ty::MethodCall { expr_id: node.id(), adjustment: adjustment }; @@ -980,7 +979,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - let method_call = typeck::MethodCall::expr(elt.id()); + let method_call = ty::MethodCall::expr(elt.id()); let method_ty = self.typer.node_method_ty(method_call); let element_ty = match method_ty { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 5e182ba8337..5770b601a69 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -19,8 +19,8 @@ use std::mem::replace; use metadata::csearch; use middle::{def, resolve}; use middle::ty::{mod, Ty}; -use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam, MethodTypeParam}; -use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject}; +use middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam, MethodTypeParam}; +use middle::ty::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject}; use util::nodemap::{NodeMap, NodeSet}; use syntax::{ast, ast_map}; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 96e1aacb0ce..fa02c940aa7 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -17,7 +17,6 @@ use middle::def; use middle::ty; -use middle::typeck; use middle::privacy; use session::config; use util::nodemap::NodeSet; @@ -137,9 +136,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { } } ast::ExprMethodCall(..) => { - let method_call = typeck::MethodCall::expr(expr.id); + let method_call = ty::MethodCall::expr(expr.id); match (*self.tcx.method_map.borrow())[method_call].origin { - typeck::MethodStatic(def_id) => { + ty::MethodStatic(def_id) => { if is_local(def_id) { if self.def_id_represents_local_inlined_item(def_id) { self.worklist.push(def_id.node) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b958bdce0a7..f1a75f996b0 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -2654,10 +2654,34 @@ impl<'a> Resolver<'a> { } Some(_) => { - // The import is unresolved. Bail out. - debug!("(resolving single import) unresolved import; \ - bailing out"); - return Indeterminate; + // If containing_module is the same module whose import we are resolving + // and there it has an unresolved import with the same name as `source`, + // then the user is actually trying to import an item that is declared + // in the same scope + // + // e.g + // use self::submodule; + // pub mod submodule; + // + // In this case we continue as if we resolved the import and let the + // check_for_conflicts_between_imports_and_items call below handle + // the conflict + match (module_.def_id.get(), containing_module.def_id.get()) { + (Some(id1), Some(id2)) if id1 == id2 => { + if value_result.is_unknown() { + value_result = UnboundResult; + } + if type_result.is_unknown() { + type_result = UnboundResult; + } + } + _ => { + // The import is unresolved. Bail out. + debug!("(resolving single import) unresolved import; \ + bailing out"); + return Indeterminate; + } + } } } } @@ -3018,7 +3042,7 @@ impl<'a> Resolver<'a> { fn check_for_conflicts_between_imports_and_items(&mut self, module: &Module, import_resolution: - &mut ImportResolution, + &ImportResolution, import_span: Span, name: Name) { if self.session.features.borrow().import_shadowing { @@ -3031,8 +3055,9 @@ impl<'a> Resolver<'a> { .contains_key(&name) { match import_resolution.type_target { Some(ref target) if !target.shadowable => { - let msg = format!("import `{}` conflicts with imported \ - crate in this module", + let msg = format!("import `{0}` conflicts with imported \ + crate in this module \ + (maybe you meant `use {0}::*`?)", token::get_name(name).get()); self.session.span_err(import_span, msg.as_slice()); } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 0a3e6c20316..21f57a9d573 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -589,8 +589,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { // type declarations and other outer declarations, not those // bound in *fn types*. Region substitution of the bound // regions that appear in a function signature is done using - // the specialized routine - // `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`. + // the specialized routine `ty::replace_late_regions()`. match r { ty::ReEarlyBound(_, space, i, region_name) => { match self.substs.regions { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 048f394224c..1bce353cb0c 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,7 @@ use super::util; use middle::subst; use middle::subst::Subst; use middle::ty::{mod, Ty}; -use middle::typeck::infer::{mod, InferCtxt}; +use middle::infer::{mod, InferCtxt}; use syntax::ast; use syntax::codemap::DUMMY_SP; use util::ppaux::Repr; diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 25c86be993f..653c686ab19 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,7 +10,7 @@ use middle::mem_categorization::Typer; use middle::ty; -use middle::typeck::infer::InferCtxt; +use middle::infer::InferCtxt; use std::collections::HashSet; use std::rc::Rc; use util::ppaux::Repr; diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index b8d915c06e0..e12ec44ad87 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -18,7 +18,7 @@ pub use self::ObligationCauseCode::*; use middle::mem_categorization::Typer; use middle::subst; use middle::ty::{mod, Ty}; -use middle::typeck::infer::InferCtxt; +use middle::infer::InferCtxt; use std::rc::Rc; use std::slice::Items; use syntax::ast; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 2604204d9e6..0e6a0c19f70 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -30,8 +30,8 @@ use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::ty::{mod, Ty}; -use middle::typeck::infer; -use middle::typeck::infer::{InferCtxt, TypeSkolemizer}; +use middle::infer; +use middle::infer::{InferCtxt, TypeSkolemizer}; use middle::ty_fold::TypeFoldable; use std::cell::RefCell; use std::collections::hash_map::HashMap; diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 1084807ef4a..1b7998a9263 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -11,7 +11,7 @@ use middle::subst; use middle::subst::{ParamSpace, Substs, VecPerParamSpace}; -use middle::typeck::infer::InferCtxt; +use middle::infer::InferCtxt; use middle::ty::{mod, Ty}; use std::collections::HashSet; use std::fmt; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 35aed356303..994f0c2090a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -35,6 +35,9 @@ pub use self::ImplOrTraitItem::*; pub use self::BoundRegion::*; pub use self::sty::*; pub use self::IntVarValue::*; +pub use self::ExprAdjustment::*; +pub use self::vtable_origin::*; +pub use self::MethodOrigin::*; use back::svh::Svh; use session::Session; @@ -53,7 +56,6 @@ use middle::stability; use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; -use middle::typeck; use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable}; use middle; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; @@ -90,6 +92,17 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; // Data types +/// The complete set of all analyses described in this module. This is +/// produced by the driver and fed to trans and later passes. +pub struct CrateAnalysis<'tcx> { + pub exp_map2: middle::resolve::ExportMap2, + pub exported_items: middle::privacy::ExportedItems, + pub public_items: middle::privacy::PublicItems, + pub ty_cx: ty::ctxt<'tcx>, + pub reachable: NodeSet, + pub name: String, +} + #[deriving(PartialEq, Eq, Hash)] pub struct field<'tcx> { pub name: ast::Name, @@ -412,7 +425,161 @@ pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Opti } } +#[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd, Show)] +pub struct param_index { + pub space: subst::ParamSpace, + pub index: uint +} + +#[deriving(Clone, Show)] +pub enum MethodOrigin<'tcx> { + // fully statically resolved method + MethodStatic(ast::DefId), + + // fully statically resolved unboxed closure invocation + MethodStaticUnboxedClosure(ast::DefId), + + // method invoked on a type parameter with a bounded trait + MethodTypeParam(MethodParam<'tcx>), + + // method invoked on a trait instance + MethodTraitObject(MethodObject<'tcx>), + +} + +// details for a method invoked with a receiver whose type is a type parameter +// with a bounded trait. +#[deriving(Clone, Show)] +pub struct MethodParam<'tcx> { + // the precise trait reference that occurs as a bound -- this may + // be a supertrait of what the user actually typed. + pub trait_ref: Rc<ty::TraitRef<'tcx>>, + + // index of uint in the list of methods for the trait + pub method_num: uint, +} + +// details for a method invoked with a receiver whose type is an object +#[deriving(Clone, Show)] +pub struct MethodObject<'tcx> { + // the (super)trait containing the method to be invoked + pub trait_ref: Rc<ty::TraitRef<'tcx>>, + + // the actual base trait id of the object + pub object_trait_id: ast::DefId, + + // index of the method to be invoked amongst the trait's methods + pub method_num: uint, + + // index into the actual runtime vtable. + // the vtable is formed by concatenating together the method lists of + // the base object trait and all supertraits; this is the index into + // that vtable + pub real_index: uint, +} + +#[deriving(Clone)] +pub struct MethodCallee<'tcx> { + pub origin: MethodOrigin<'tcx>, + pub ty: Ty<'tcx>, + pub substs: subst::Substs<'tcx> +} + +/// With method calls, we store some extra information in +/// side tables (i.e method_map). We use +/// MethodCall as a key to index into these tables instead of +/// just directly using the expression's NodeId. The reason +/// for this being that we may apply adjustments (coercions) +/// with the resulting expression also needing to use the +/// side tables. The problem with this is that we don't +/// assign a separate NodeId to this new expression +/// and so it would clash with the base expression if both +/// needed to add to the side tables. Thus to disambiguate +/// we also keep track of whether there's an adjustment in +/// our key. +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct MethodCall { + pub expr_id: ast::NodeId, + pub adjustment: ExprAdjustment +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)] +pub enum ExprAdjustment { + NoAdjustment, + AutoDeref(uint), + AutoObject +} + +impl MethodCall { + pub fn expr(id: ast::NodeId) -> MethodCall { + MethodCall { + expr_id: id, + adjustment: NoAdjustment + } + } + + pub fn autoobject(id: ast::NodeId) -> MethodCall { + MethodCall { + expr_id: id, + adjustment: AutoObject + } + } + + pub fn autoderef(expr_id: ast::NodeId, autoderef: uint) -> MethodCall { + MethodCall { + expr_id: expr_id, + adjustment: AutoDeref(1 + autoderef) + } + } +} + +// maps from an expression id that corresponds to a method call to the details +// of the method to be invoked +pub type MethodMap<'tcx> = RefCell<FnvHashMap<MethodCall, MethodCallee<'tcx>>>; +pub type vtable_param_res<'tcx> = Vec<vtable_origin<'tcx>>; + +// Resolutions for bounds of all parameters, left to right, for a given path. +pub type vtable_res<'tcx> = VecPerParamSpace<vtable_param_res<'tcx>>; + +#[deriving(Clone)] +pub enum vtable_origin<'tcx> { + /* + Statically known vtable. def_id gives the impl item + from whence comes the vtable, and tys are the type substs. + vtable_res is the vtable itself. + */ + vtable_static(ast::DefId, subst::Substs<'tcx>, vtable_res<'tcx>), + + /* + Dynamic vtable, comes from a parameter that has a bound on it: + fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a + vtable_param origin + + The first argument is the param index (identifying T in the example), + and the second is the bound number (identifying baz) + */ + vtable_param(param_index, uint), + + /* + Vtable automatically generated for an unboxed closure. The def ID is the + ID of the closure expression. + */ + vtable_unboxed_closure(ast::DefId), + + /* + Asked to determine the vtable for ty_err. This is the value used + for the vtables of `Self` in a virtual call like `foo.bar()` + where `foo` is of object type. The same value is also used when + type errors occur. + */ + vtable_error, +} + + +// For every explicit cast into an object type, maps from the cast +// expr to the associated trait ref. +pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::TraitRef<'tcx>>>>; /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. @@ -473,7 +640,7 @@ pub struct ctxt<'tcx> { /// Maps from node-id of a trait object cast (like `foo as /// Box<Trait>`) to the trait reference. - pub object_cast_map: typeck::ObjectCastMap<'tcx>, + pub object_cast_map: ObjectCastMap<'tcx>, pub map: ast_map::Map<'tcx>, pub intrinsic_defs: RefCell<DefIdMap<Ty<'tcx>>>, @@ -548,7 +715,7 @@ pub struct ctxt<'tcx> { pub extern_const_statics: RefCell<DefIdMap<ast::NodeId>>, pub extern_const_variants: RefCell<DefIdMap<ast::NodeId>>, - pub method_map: typeck::MethodMap<'tcx>, + pub method_map: MethodMap<'tcx>, pub dependency_formats: RefCell<dependency_format::Dependencies>, @@ -3658,7 +3825,7 @@ pub fn adjust_ty<'tcx>(cx: &ctxt<'tcx>, expr_id: ast::NodeId, unadjusted_ty: Ty<'tcx>, adjustment: Option<&AutoAdjustment<'tcx>>, - method_type: |typeck::MethodCall| -> Option<Ty<'tcx>>) + method_type: |MethodCall| -> Option<Ty<'tcx>>) -> Ty<'tcx> { if let ty_err = unadjusted_ty.sty { @@ -3699,7 +3866,7 @@ pub fn adjust_ty<'tcx>(cx: &ctxt<'tcx>, if !ty::type_is_error(adjusted_ty) { for i in range(0, adj.autoderefs) { - let method_call = typeck::MethodCall::autoderef(expr_id, i); + let method_call = MethodCall::autoderef(expr_id, i); match method_type(method_call) { Some(method_ty) => { if let ty::FnConverging(result_type) = ty_fn_ret(method_ty) { @@ -3830,7 +3997,7 @@ pub enum ExprKind { } pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { - if tcx.method_map.borrow().contains_key(&typeck::MethodCall::expr(expr.id)) { + if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) { // Overloaded operations are generally calls, and hence they are // generated via DPS, but there are a few exceptions: return match expr.node { @@ -5747,7 +5914,7 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> { Ok(ty::node_id_to_type(self, id)) } - fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<Ty<'tcx>> { + fn node_method_ty(&self, method_call: MethodCall) -> Option<Ty<'tcx>> { self.method_map.borrow().get(&method_call).map(|method| method.ty) } @@ -5756,7 +5923,7 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> { } fn is_method_call(&self, id: ast::NodeId) -> bool { - self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) + self.method_map.borrow().contains_key(&MethodCall::expr(id)) } fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> { @@ -6010,3 +6177,55 @@ impl<'tcx> Repr<'tcx> for TyTrait<'tcx> { self.bounds.repr(tcx)) } } + +impl<'tcx> Repr<'tcx> for vtable_origin<'tcx> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + match *self { + vtable_static(def_id, ref tys, ref vtable_res) => { + format!("vtable_static({}:{}, {}, {})", + def_id, + ty::item_path_str(tcx, def_id), + tys.repr(tcx), + vtable_res.repr(tcx)) + } + + vtable_param(x, y) => { + format!("vtable_param({}, {})", x, y) + } + + vtable_unboxed_closure(def_id) => { + format!("vtable_unboxed_closure({})", def_id) + } + + vtable_error => { + format!("vtable_error") + } + } + } +} + +pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + method: &ty::Method<'tcx>) + -> subst::Substs<'tcx> +{ + /*! + * Substitutes the values for the receiver's type parameters + * that are found in method, leaving the method's type parameters + * intact. + */ + + let meth_tps: Vec<Ty> = + method.generics.types.get_slice(subst::FnSpace) + .iter() + .map(|def| ty::mk_param_from_def(tcx, def)) + .collect(); + let meth_regions: Vec<ty::Region> = + method.generics.regions.get_slice(subst::FnSpace) + .iter() + .map(|def| ty::ReEarlyBound(def.def_id.node, def.space, + def.index, def.name)) + .collect(); + trait_ref.substs.clone().with_method(meth_tps, meth_regions) +} + diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index de9eb426498..77092025349 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -38,7 +38,6 @@ use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty::{mod, Ty}; use middle::traits; -use middle::typeck; use std::rc::Rc; use syntax::owned_slice::OwnedSlice; use util::ppaux::Repr; @@ -304,23 +303,23 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for typeck::MethodOrigin<'tcx> { - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> typeck::MethodOrigin<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> { + fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::MethodOrigin<'tcx> { match *self { - typeck::MethodStatic(def_id) => { - typeck::MethodStatic(def_id) + ty::MethodStatic(def_id) => { + ty::MethodStatic(def_id) } - typeck::MethodStaticUnboxedClosure(def_id) => { - typeck::MethodStaticUnboxedClosure(def_id) + ty::MethodStaticUnboxedClosure(def_id) => { + ty::MethodStaticUnboxedClosure(def_id) } - typeck::MethodTypeParam(ref param) => { - typeck::MethodTypeParam(typeck::MethodParam { + ty::MethodTypeParam(ref param) => { + ty::MethodTypeParam(ty::MethodParam { trait_ref: param.trait_ref.fold_with(folder), method_num: param.method_num }) } - typeck::MethodTraitObject(ref object) => { - typeck::MethodTraitObject(typeck::MethodObject { + ty::MethodTraitObject(ref object) => { + ty::MethodTraitObject(ty::MethodObject { trait_ref: object.trait_ref.fold_with(folder), object_trait_id: object.object_trait_id, method_num: object.method_num, @@ -331,22 +330,22 @@ impl<'tcx> TypeFoldable<'tcx> for typeck::MethodOrigin<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for typeck::vtable_origin<'tcx> { - fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> typeck::vtable_origin<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::vtable_origin<'tcx> { + fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::vtable_origin<'tcx> { match *self { - typeck::vtable_static(def_id, ref substs, ref origins) => { + ty::vtable_static(def_id, ref substs, ref origins) => { let r_substs = substs.fold_with(folder); let r_origins = origins.fold_with(folder); - typeck::vtable_static(def_id, r_substs, r_origins) + ty::vtable_static(def_id, r_substs, r_origins) } - typeck::vtable_param(n, b) => { - typeck::vtable_param(n, b) + ty::vtable_param(n, b) => { + ty::vtable_param(n, b) } - typeck::vtable_unboxed_closure(def_id) => { - typeck::vtable_unboxed_closure(def_id) + ty::vtable_unboxed_closure(def_id) => { + ty::vtable_unboxed_closure(def_id) } - typeck::vtable_error => { - typeck::vtable_error + ty::vtable_error => { + ty::vtable_error } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 33de2c9abe9..cbc9dd9145b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -114,6 +114,59 @@ pub struct Options { pub alt_std_name: Option<String> } +pub enum Input { + /// Load source from file + File(Path), + /// The string is the source + Str(String) +} + +impl Input { + pub fn filestem(&self) -> String { + match *self { + Input::File(ref ifile) => ifile.filestem_str().unwrap().to_string(), + Input::Str(_) => "rust_out".to_string(), + } + } +} + +#[deriving(Clone)] +pub struct OutputFilenames { + pub out_directory: Path, + pub out_filestem: String, + pub single_output_file: Option<Path>, + pub extra: String, +} + +impl OutputFilenames { + pub fn path(&self, flavor: OutputType) -> Path { + match self.single_output_file { + Some(ref path) => return path.clone(), + None => {} + } + self.temp_path(flavor) + } + + pub fn temp_path(&self, flavor: OutputType) -> Path { + let base = self.out_directory.join(self.filestem()); + match flavor { + OutputTypeBitcode => base.with_extension("bc"), + OutputTypeAssembly => base.with_extension("s"), + OutputTypeLlvmAssembly => base.with_extension("ll"), + OutputTypeObject => base.with_extension("o"), + OutputTypeExe => base, + } + } + + pub fn with_extension(&self, extension: &str) -> Path { + self.out_directory.join(self.filestem()).with_extension(extension) + } + + pub fn filestem(&self) -> String { + format!("{}{}", self.out_filestem, self.extra) + } +} + pub fn host_triple() -> &'static str { // Get the host triple out of the build environment. This ensures that our // idea of the host triple is the same as for the set of libraries we've diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index b739a97f734..1283e89c29d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -23,8 +23,6 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; -use middle::typeck; -use middle::typeck::check::regionmanip; use std::rc::Rc; use syntax::abi; @@ -1018,7 +1016,7 @@ impl<'tcx> Repr<'tcx> for ty::FnOutput<'tcx> { } } -impl<'tcx> Repr<'tcx> for typeck::MethodCallee<'tcx> { +impl<'tcx> Repr<'tcx> for ty::MethodCallee<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("MethodCallee {{origin: {}, ty: {}, {}}}", self.origin.repr(tcx), @@ -1027,26 +1025,26 @@ impl<'tcx> Repr<'tcx> for typeck::MethodCallee<'tcx> { } } -impl<'tcx> Repr<'tcx> for typeck::MethodOrigin<'tcx> { +impl<'tcx> Repr<'tcx> for ty::MethodOrigin<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match self { - &typeck::MethodStatic(def_id) => { + &ty::MethodStatic(def_id) => { format!("MethodStatic({})", def_id.repr(tcx)) } - &typeck::MethodStaticUnboxedClosure(def_id) => { + &ty::MethodStaticUnboxedClosure(def_id) => { format!("MethodStaticUnboxedClosure({})", def_id.repr(tcx)) } - &typeck::MethodTypeParam(ref p) => { + &ty::MethodTypeParam(ref p) => { p.repr(tcx) } - &typeck::MethodTraitObject(ref p) => { + &ty::MethodTraitObject(ref p) => { p.repr(tcx) } } } } -impl<'tcx> Repr<'tcx> for typeck::MethodParam<'tcx> { +impl<'tcx> Repr<'tcx> for ty::MethodParam<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("MethodParam({},{})", self.trait_ref.repr(tcx), @@ -1054,7 +1052,7 @@ impl<'tcx> Repr<'tcx> for typeck::MethodParam<'tcx> { } } -impl<'tcx> Repr<'tcx> for typeck::MethodObject<'tcx> { +impl<'tcx> Repr<'tcx> for ty::MethodObject<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("MethodObject({},{},{})", self.trait_ref.repr(tcx), @@ -1293,25 +1291,6 @@ impl<'tcx> Repr<'tcx> for ty::ExplicitSelfCategory { } } - -impl<'tcx> Repr<'tcx> for regionmanip::WfConstraint<'tcx> { - fn repr(&self, tcx: &ctxt) -> String { - match *self { - regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => { - format!("RegionSubRegionConstraint({}, {})", - r_a.repr(tcx), - r_b.repr(tcx)) - } - - regionmanip::RegionSubParamConstraint(_, r, p) => { - format!("RegionSubParamConstraint({}, {})", - r.repr(tcx), - p.repr(tcx)) - } - } - } -} - impl<'tcx> UserString<'tcx> for ParamTy { fn user_string(&self, tcx: &ctxt) -> String { let id = self.idx; diff --git a/src/librustc_trans/driver/driver.rs b/src/librustc_driver/driver.rs index d3281ae1c19..437b0257a97 100644 --- a/src/librustc_trans/driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -8,26 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::Input::*; - -use back::link; -use back::write; -use session::Session; -use session::config; -use lint; -use llvm::{ContextRef, ModuleRef}; -use metadata::common::LinkMeta; -use metadata::creader; -use middle::{stability, ty, typeck, reachable}; -use middle::dependency_format; -use middle; -use plugin::load::Plugins; -use plugin::registry::Registry; -use plugin; -use trans; - -use util::common::time; -use util::nodemap::{NodeSet}; +use rustc::session::Session; +use rustc::session::config::{mod, Input, OutputFilenames}; +use rustc::lint; +use rustc::metadata::creader; +use rustc::middle::{stability, ty, reachable}; +use rustc::middle::dependency_format; +use rustc::middle; +use rustc::plugin::load::Plugins; +use rustc::plugin::registry::Registry; +use rustc::plugin; +use rustc::util::common::time; +use rustc_trans::back::link; +use rustc_trans::back::write; +use rustc_trans::save; +use rustc_trans::trans; +use rustc_typeck as typeck; use serialize::{json, Encodable}; @@ -35,7 +31,6 @@ use std::io; use std::io::fs; use std::os; use arena::TypedArena; -use save; use syntax::ast; use syntax::ast_map; use syntax::attr; @@ -113,36 +108,19 @@ pub fn anon_src() -> String { pub fn source_name(input: &Input) -> String { match *input { // FIXME (#9639): This needs to handle non-utf8 paths - FileInput(ref ifile) => ifile.as_str().unwrap().to_string(), - StrInput(_) => anon_src() + Input::File(ref ifile) => ifile.as_str().unwrap().to_string(), + Input::Str(_) => anon_src() } } -pub enum Input { - /// Load source from file - FileInput(Path), - /// The string is the source - StrInput(String) -} - -impl Input { - fn filestem(&self) -> String { - match *self { - FileInput(ref ifile) => ifile.filestem_str().unwrap().to_string(), - StrInput(_) => "rust_out".to_string(), - } - } -} - - pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) -> ast::Crate { let krate = time(sess.time_passes(), "parsing", (), |_| { match *input { - FileInput(ref file) => { + Input::File(ref file) => { parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess) } - StrInput(ref src) => { + Input::Str(ref src) => { parse::parse_crate_from_source_str(anon_src().to_string(), src.to_string(), cfg.clone(), @@ -342,23 +320,13 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session, map } -pub struct CrateAnalysis<'tcx> { - pub exp_map2: middle::resolve::ExportMap2, - pub exported_items: middle::privacy::ExportedItems, - pub public_items: middle::privacy::PublicItems, - pub ty_cx: ty::ctxt<'tcx>, - pub reachable: NodeSet, - pub name: String, -} - - /// Run the resolution, typechecking, region checking and other /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, ast_map: ast_map::Map<'tcx>, type_arena: &'tcx TypedArena<ty::TyS<'tcx>>, - name: String) -> CrateAnalysis<'tcx> { + name: String) -> ty::CrateAnalysis<'tcx> { let time_passes = sess.time_passes(); let krate = ast_map.krate(); @@ -473,7 +441,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, time(time_passes, "lint checking", (), |_| lint::check_crate(&ty_cx, &exported_items)); - CrateAnalysis { + ty::CrateAnalysis { exp_map2: exp_map2, ty_cx: ty_cx, exported_items: exported_items, @@ -485,7 +453,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, pub fn phase_save_analysis(sess: &Session, krate: &ast::Crate, - analysis: &CrateAnalysis, + analysis: &ty::CrateAnalysis, odir: &Option<Path>) { if (sess.opts.debugging_opts & config::SAVE_ANALYSIS) == 0 { return; @@ -494,25 +462,10 @@ pub fn phase_save_analysis(sess: &Session, save::process_crate(sess, krate, analysis, odir)); } -pub struct ModuleTranslation { - pub llcx: ContextRef, - pub llmod: ModuleRef, -} - -pub struct CrateTranslation { - pub modules: Vec<ModuleTranslation>, - pub metadata_module: ModuleTranslation, - pub link: LinkMeta, - pub metadata: Vec<u8>, - pub reachable: Vec<String>, - pub crate_formats: dependency_format::Dependencies, - pub no_builtins: bool, -} - /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. -pub fn phase_4_translate_to_llvm<'tcx>(analysis: CrateAnalysis<'tcx>) - -> (ty::ctxt<'tcx>, CrateTranslation) { +pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>) + -> (ty::ctxt<'tcx>, trans::CrateTranslation) { let time_passes = analysis.ty_cx.sess.time_passes(); time(time_passes, "resolving dependency formats", (), |_| @@ -520,13 +473,13 @@ pub fn phase_4_translate_to_llvm<'tcx>(analysis: CrateAnalysis<'tcx>) // Option dance to work around the lack of stack once closures. time(time_passes, "translation", analysis, |analysis| - trans::base::trans_crate(analysis)) + trans::trans_crate(analysis)) } /// Run LLVM itself, producing a bitcode file, assembly file or object file /// as a side effect. pub fn phase_5_run_llvm_passes(sess: &Session, - trans: &CrateTranslation, + trans: &trans::CrateTranslation, outputs: &OutputFilenames) { if sess.opts.cg.no_integrated_as { let output_type = config::OutputTypeAssembly; @@ -554,7 +507,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session, /// Run the linker on any artifacts that resulted from the LLVM run. /// This should produce either a finished executable or library. pub fn phase_6_link_output(sess: &Session, - trans: &CrateTranslation, + trans: &trans::CrateTranslation, outputs: &OutputFilenames) { let old_path = os::getenv("PATH").unwrap_or_else(||String::new()); let mut new_path = sess.host_filesearch().get_tools_search_paths(); @@ -639,8 +592,8 @@ fn write_out_deps(sess: &Session, // Use default filename: crate source filename with extension replaced // by ".d" (true, None) => match *input { - FileInput(..) => outputs.with_extension("d"), - StrInput(..) => { + Input::File(..) => outputs.with_extension("d"), + Input::Str(..) => { sess.warn("can not write --dep-info without a filename \ when compiling stdin."); return @@ -751,43 +704,6 @@ pub fn collect_crate_metadata(session: &Session, session.opts.cg.metadata.clone() } -#[deriving(Clone)] -pub struct OutputFilenames { - pub out_directory: Path, - pub out_filestem: String, - pub single_output_file: Option<Path>, - extra: String, -} - -impl OutputFilenames { - pub fn path(&self, flavor: config::OutputType) -> Path { - match self.single_output_file { - Some(ref path) => return path.clone(), - None => {} - } - self.temp_path(flavor) - } - - pub fn temp_path(&self, flavor: config::OutputType) -> Path { - let base = self.out_directory.join(self.filestem()); - match flavor { - config::OutputTypeBitcode => base.with_extension("bc"), - config::OutputTypeAssembly => base.with_extension("s"), - config::OutputTypeLlvmAssembly => base.with_extension("ll"), - config::OutputTypeObject => base.with_extension("o"), - config::OutputTypeExe => base, - } - } - - pub fn with_extension(&self, extension: &str) -> Path { - self.out_directory.join(self.filestem()).with_extension(extension) - } - - fn filestem(&self) -> String { - format!("{}{}", self.out_filestem, self.extra) - } -} - pub fn build_output_filenames(input: &Input, odir: &Option<Path>, ofile: &Option<Path>, diff --git a/src/librustc_trans/driver/mod.rs b/src/librustc_driver/lib.rs index 658be9169af..33c009cf329 100644 --- a/src/librustc_trans/driver/mod.rs +++ b/src/librustc_driver/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,15 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use syntax::diagnostic; +//! The Rust compiler. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![crate_name = "rustc_driver"] +#![experimental] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/")] + +#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)] +#![feature(slicing_syntax, unsafe_destructor)] +#![feature(rustc_diagnostic_macros)] + +extern crate arena; +extern crate flate; +extern crate getopts; +extern crate graphviz; +extern crate libc; +extern crate rustc; +extern crate rustc_typeck; +extern crate rustc_back; +extern crate rustc_trans; +#[phase(plugin, link)] extern crate log; +#[phase(plugin, link)] extern crate syntax; +extern crate serialize; +extern crate "rustc_llvm" as llvm; -use back::link; -use driver::driver::{Input, FileInput, StrInput}; -use session::{config, Session, build_session}; -use lint::Lint; -use lint; -use metadata; +pub use syntax::diagnostic; +use rustc_trans::back::link; +use rustc::session::{config, Session, build_session}; +use rustc::session::config::Input; +use rustc::lint::Lint; +use rustc::lint; +use rustc::metadata; use rustc::DIAGNOSTICS; use std::any::AnyRefExt; @@ -24,14 +55,15 @@ use std::io; use std::os; use std::task::TaskBuilder; -use session::early_error; +use rustc::session::early_error; use syntax::ast; use syntax::parse; use syntax::diagnostic::Emitter; use syntax::diagnostics; -use getopts; +#[cfg(test)] +pub mod test; pub mod driver; pub mod pretty; @@ -89,9 +121,9 @@ fn run_compiler(args: &[String]) { if ifile == "-" { let contents = io::stdin().read_to_end().unwrap(); let src = String::from_utf8(contents).unwrap(); - (StrInput(src), None) + (Input::Str(src), None) } else { - (FileInput(Path::new(ifile)), Some(Path::new(ifile))) + (Input::File(Path::new(ifile)), Some(Path::new(ifile))) } } _ => early_error("multiple input filenames provided") @@ -116,11 +148,11 @@ fn run_compiler(args: &[String]) { let r = matches.opt_strs("Z"); if r.contains(&("ls".to_string())) { match input { - FileInput(ref ifile) => { + Input::File(ref ifile) => { let mut stdout = io::stdout(); list_metadata(&sess, &(*ifile), &mut stdout).unwrap(); } - StrInput(_) => { + Input::Str(_) => { early_error("can not list metadata for stdin"); } } @@ -411,12 +443,12 @@ fn print_crate_info(sess: &Session, fn parse_crate_attrs(sess: &Session, input: &Input) -> Vec<ast::Attribute> { let result = match *input { - FileInput(ref ifile) => { + Input::File(ref ifile) => { parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess) } - StrInput(ref src) => { + Input::Str(ref src) => { parse::parse_crate_attrs_from_source_str( driver::anon_src().to_string(), src.to_string(), @@ -438,13 +470,7 @@ pub fn list_metadata(sess: &Session, path: &Path, /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. pub fn monitor(f: proc():Send) { - // FIXME: This is a hack for newsched since it doesn't support split stacks. - // rustc needs a lot of stack! When optimizations are disabled, it needs - // even *more* stack than usual as well. - #[cfg(rtopt)] - static STACK_SIZE: uint = 6000000; // 6MB - #[cfg(not(rtopt))] - static STACK_SIZE: uint = 20000000; // 20MB + static STACK_SIZE: uint = 32000000; // 32MB let (tx, rx) = channel(); let w = io::ChanWriter::new(tx); @@ -507,3 +533,9 @@ pub fn monitor(f: proc():Send) { } } +pub fn main() { + let args = std::os::args(); + let result = run(args); + std::os::set_exit_status(result); +} + diff --git a/src/librustc_driver/mod.rs b/src/librustc_driver/mod.rs new file mode 100644 index 00000000000..1fbbc9c0521 --- /dev/null +++ b/src/librustc_driver/mod.rs @@ -0,0 +1,10 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + diff --git a/src/librustc_trans/driver/pretty.rs b/src/librustc_driver/pretty.rs index 7bb83d7c2a8..b6441ab4944 100644 --- a/src/librustc_trans/driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -15,18 +15,18 @@ pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; -use back::link; +use rustc_trans::back::link; -use session::{config, Session}; -use driver::driver::{mod, CrateAnalysis}; +use driver; -use middle::ty; -use middle::borrowck::{mod, FnPartsWithCFG}; -use middle::borrowck::graphviz as borrowck_dot; -use middle::cfg; -use middle::cfg::graphviz::LabelledCFG; - -use util::ppaux; +use rustc::middle::ty; +use rustc::middle::borrowck::{mod, FnPartsWithCFG}; +use rustc::middle::borrowck::graphviz as borrowck_dot; +use rustc::middle::cfg; +use rustc::middle::cfg::graphviz::LabelledCFG; +use rustc::session::Session; +use rustc::session::config::{mod, Input}; +use rustc::util::ppaux; use syntax::ast; use syntax::ast_map::{mod, blocks, NodePrinter}; @@ -242,7 +242,7 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { struct TypedAnnotation<'tcx> { - analysis: CrateAnalysis<'tcx>, + analysis: ty::CrateAnalysis<'tcx>, } impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> { @@ -409,7 +409,7 @@ fn needs_expansion(ppm: &PpMode) -> bool { pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, - input: &driver::Input, + input: &Input, ppm: PpMode, opt_uii: Option<UserIdentifiedItem>, ofile: Option<Path>) { @@ -536,7 +536,7 @@ pub fn pretty_print_input(sess: Session, } fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>, - analysis: CrateAnalysis, + analysis: ty::CrateAnalysis, code: blocks::Code, mut out: W) -> io::IoResult<()> { let ty_cx = &analysis.ty_cx; diff --git a/src/librustc_trans/test.rs b/src/librustc_driver/test.rs index 41fbe855769..9404802cb68 100644 --- a/src/librustc_trans/test.rs +++ b/src/librustc_driver/test.rs @@ -10,28 +10,28 @@ //! # Standalone Tests for the Inference Module -use driver::diagnostic; -use driver::diagnostic::Emitter; -use driver::driver; -use middle::lang_items; -use middle::region::{mod, CodeExtent}; -use middle::resolve; -use middle::resolve_lifetime; -use middle::stability; -use middle::subst; -use middle::subst::Subst; -use middle::ty::{mod, Ty}; -use middle::typeck::infer::combine::Combine; -use middle::typeck::infer; -use middle::typeck::infer::lub::Lub; -use middle::typeck::infer::glb::Glb; -use session::{mod,config}; +use diagnostic; +use diagnostic::Emitter; +use driver; +use rustc_typeck::middle::lang_items; +use rustc_typeck::middle::region::{mod, CodeExtent}; +use rustc_typeck::middle::resolve; +use rustc_typeck::middle::resolve_lifetime; +use rustc_typeck::middle::stability; +use rustc_typeck::middle::subst; +use rustc_typeck::middle::subst::Subst; +use rustc_typeck::middle::ty::{mod, Ty}; +use rustc_typeck::middle::infer::combine::Combine; +use rustc_typeck::middle::infer; +use rustc_typeck::middle::infer::lub::Lub; +use rustc_typeck::middle::infer::glb::Glb; +use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString}; +use rustc::session::{mod,config}; use syntax::{abi, ast, ast_map, ast_util}; use syntax::codemap; use syntax::codemap::{Span, CodeMap, DUMMY_SP}; use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help}; use syntax::parse::token; -use util::ppaux::{ty_to_string, Repr, UserString}; use arena::TypedArena; @@ -108,7 +108,7 @@ fn test_env(source_string: &str, let sess = session::build_session_(options, None, span_diagnostic_handler); let krate_config = Vec::new(); - let input = driver::StrInput(source_string.to_string()); + let input = config::Input::Str(source_string.to_string()); let krate = driver::phase_1_parse_input(&sess, krate_config, &input); let krate = driver::phase_2_configure_and_expand(&sess, krate, "test", None) .expect("phase 2 aborted"); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index d8cdffe2100..6057f9d9081 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -13,15 +13,13 @@ use super::archive; use super::rpath; use super::rpath::RPathConfig; use super::svh::Svh; -use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput}; use session::config; use session::config::NoDebugInfo; -use session::config::{OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; +use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; use session::Session; use metadata::common::LinkMeta; use metadata::{encoder, cstore, filesearch, csearch, creader}; -use trans::context::CrateContext; -use trans::common::gensym_name; +use trans::{CrateContext, CrateTranslation, gensym_name}; use middle::ty::{mod, Ty}; use util::common::time; use util::ppaux; @@ -156,7 +154,7 @@ pub fn find_crate_name(sess: Option<&Session>, if let Some((attr, s)) = attr_crate_name { return validate(s.get().to_string(), Some(attr.span)); } - if let FileInput(ref path) = *input { + if let Input::File(ref path) = *input { if let Some(s) = path.filestem_str() { return validate(s.to_string(), None); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index b923bb076c3..e5ffe2675d6 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,13 +10,13 @@ use back::lto; use back::link::{get_cc_prog, remove}; -use driver::driver::{CrateTranslation, ModuleTranslation, OutputFilenames}; -use session::config::{NoDebugInfo, Passes, SomePasses, AllPasses}; +use session::config::{OutputFilenames, NoDebugInfo, Passes, SomePasses, AllPasses}; use session::Session; use session::config; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; use llvm::SMDiagnosticRef; +use trans::{CrateTranslation, ModuleTranslation}; use util::common::time; use syntax::codemap; use syntax::diagnostic; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 4dc8c4d1736..4e25921e0b2 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -65,17 +65,7 @@ pub mod back { pub mod trans; pub mod save; -pub mod driver; pub mod lib { pub use llvm; } - -pub fn main() { - let args = std::os::args(); - let result = driver::run(args); - std::os::set_exit_status(result); -} - -#[cfg(test)] -pub mod test; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 7a41be1dbe4..1482422b8d0 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -27,10 +27,9 @@ //! the format of the output away from extracting it from the compiler. //! DxrVisitor walks the AST and processes it. -use driver::driver::CrateAnalysis; use session::Session; -use middle::{def, typeck}; +use middle::def; use middle::ty::{mod, Ty}; use std::cell::Cell; @@ -68,7 +67,7 @@ fn generated_code(span: Span) -> bool { struct DxrVisitor<'l, 'tcx: 'l> { sess: &'l Session, - analysis: &'l CrateAnalysis<'tcx>, + analysis: &'l ty::CrateAnalysis<'tcx>, collected_paths: Vec<(NodeId, ast::Path, bool, recorder::Row)>, collecting: bool, @@ -912,10 +911,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ex: &ast::Expr, args: &Vec<P<ast::Expr>>) { let method_map = self.analysis.ty_cx.method_map.borrow(); - let method_callee = &(*method_map)[typeck::MethodCall::expr(ex.id)]; + let method_callee = &(*method_map)[ty::MethodCall::expr(ex.id)]; let (def_id, decl_id) = match method_callee.origin { - typeck::MethodStatic(def_id) | - typeck::MethodStaticUnboxedClosure(def_id) => { + ty::MethodStatic(def_id) | + ty::MethodStaticUnboxedClosure(def_id) => { // method invoked on an object with a concrete type (not a static method) let decl_id = match ty::trait_item_of_item(&self.analysis.ty_cx, @@ -936,14 +935,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }; (Some(def_id), decl_id) } - typeck::MethodTypeParam(ref mp) => { + ty::MethodTypeParam(ref mp) => { // method invoked on a type parameter let trait_item = ty::trait_item(&self.analysis.ty_cx, mp.trait_ref.def_id, mp.method_num); (None, Some(trait_item.def_id())) } - typeck::MethodTraitObject(ref mo) => { + ty::MethodTraitObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, mo.trait_ref.def_id, @@ -1473,7 +1472,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { pub fn process_crate(sess: &Session, krate: &ast::Crate, - analysis: &CrateAnalysis, + analysis: &ty::CrateAnalysis, odir: &Option<Path>) { if generated_code(krate.span) { return; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 84a6b59934f..9d0e096c71d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -28,9 +28,11 @@ pub use self::ValueOrigin::*; pub use self::scalar_type::*; +use super::CrateTranslation; +use super::ModuleTranslation; + use back::link::{mangle_exported_name}; use back::{link, abi}; -use driver::driver::{CrateAnalysis, CrateTranslation, ModuleTranslation}; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -1078,12 +1080,6 @@ pub fn store_ty(cx: Block, v: ValueRef, dst: ValueRef, t: Ty) { }; } -pub fn ignore_lhs(_bcx: Block, local: &ast::Local) -> bool { - match local.pat.node { - ast::PatWild(ast::PatWildSingle) => true, _ => false - } -} - pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &ast::Local) -> Block<'blk, 'tcx> { debug!("init_local(bcx={}, local.id={})", bcx.to_str(), local.id); @@ -2916,12 +2912,6 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, llfn } -pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef { - unsafe { - return llvm::LLVMConstPtrToInt(v, ccx.int_type().to_ref()); - } -} - pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>, ie: encoder::EncodeInlinedItem<'a>) -> encoder::EncodeParams<'a, 'tcx> { @@ -3055,9 +3045,9 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) { } } -pub fn trans_crate<'tcx>(analysis: CrateAnalysis<'tcx>) +pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>) -> (ty::ctxt<'tcx>, CrateTranslation) { - let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis; + let ty::CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis; let krate = tcx.map.krate(); // Before we touch LLVM, make sure that multithreading is enabled. diff --git a/src/librustc_trans/trans/cabi.rs b/src/librustc_trans/trans/cabi.rs index 0214bf29eee..518b0ba73f8 100644 --- a/src/librustc_trans/trans/cabi.rs +++ b/src/librustc_trans/trans/cabi.rs @@ -65,8 +65,8 @@ impl ArgType { ArgType { kind: Indirect, ty: ty, - cast: option::None, - pad: option::None, + cast: option::Option::None, + pad: option::Option::None, attr: attr } } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 176fe7096e7..746109ef113 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -49,8 +49,7 @@ use trans::monomorphize; use trans::type_::Type; use trans::type_of; use middle::ty::{mod, Ty}; -use middle::typeck::coherence::make_substs_for_receiver_types; -use middle::typeck::MethodCall; +use middle::ty::MethodCall; use util::ppaux::Repr; use util::ppaux::ty_to_string; @@ -573,7 +572,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( // Compute the first substitution let first_subst = - make_substs_for_receiver_types(tcx, &*trait_ref, &*method) + ty::make_substs_for_receiver_types(tcx, &*trait_ref, &*method) .erase_regions(); // And compose them diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index febb33f6c54..a8256176c26 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -19,6 +19,7 @@ use llvm; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef}; use llvm::{True, False, Bool}; use middle::def; +use middle::infer; use middle::lang_items::LangItem; use middle::mem_categorization as mc; use middle::region; @@ -36,8 +37,6 @@ use middle::traits; use middle::ty::{mod, Ty}; use middle::ty_fold; use middle::ty_fold::TypeFoldable; -use middle::typeck; -use middle::typeck::infer; use util::ppaux::Repr; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; @@ -273,11 +272,6 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } } - pub fn out_arg_pos(&self) -> uint { - assert!(self.caller_expects_out_pointer); - 0u - } - pub fn env_arg_pos(&self) -> uint { if self.caller_expects_out_pointer { 1u @@ -468,7 +462,7 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { Ok(node_id_type(self, id)) } - fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<Ty<'tcx>> { + fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> { self.tcx() .method_map .borrow() @@ -481,7 +475,7 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { } fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tcx().method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) + self.tcx().method_map.borrow().contains_key(&ty::MethodCall::expr(id)) } fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> { @@ -870,7 +864,7 @@ pub enum ExprOrMethodCall { ExprId(ast::NodeId), // Type parameters for a method call like `a.foo::<int>()` - MethodCall(typeck::MethodCall) + MethodCall(ty::MethodCall) } pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 8220645cec7..fd9d6b8f2c3 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -347,10 +347,6 @@ impl<'tcx> SharedCrateContext<'tcx> { &self.link_meta } - pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell<Sha256> { - &self.symbol_hasher - } - pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { &self.tcx } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 3d32f6045a7..a1574aa2f0e 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -27,7 +27,7 @@ use trans::meth; use trans::type_::Type; use trans; use middle::ty; -use middle::typeck::MethodCall; +use middle::ty::MethodCall; use session::config::FullDebugInfo; use util::ppaux::Repr; use util::ppaux; diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index f0fd94958ee..532ef690818 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -352,13 +352,6 @@ impl<'tcx> Datum<'tcx, Expr> { |_| bcx.sess().bug("assert_lvalue given rvalue")) } - /// Asserts that this datum *is* an lvalue and returns it. - pub fn assert_rvalue(self, bcx: Block) -> Datum<'tcx, Rvalue> { - self.match_kind( - |_| bcx.sess().bug("assert_rvalue given lvalue"), - |r| r) - } - pub fn store_to_dest<'blk>(self, bcx: Block<'blk, 'tcx>, dest: expr::Dest, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 646ee601a4c..d130dc0a55b 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -41,15 +41,23 @@ use middle::def; use middle::mem_categorization::Typer; use middle::subst::{mod, Subst}; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; -use trans::{debuginfo, glue, machine, meth, inline, tvec, type_of}; use trans::base::*; use trans::build::*; use trans::cleanup::{mod, CleanupMethods}; use trans::common::*; use trans::datum::*; -use middle::ty::{mod, struct_fields, tup_fields}; -use middle::ty::{AdjustDerefRef, AdjustAddEnv, AutoUnsafe, AutoPtr, Ty}; -use middle::typeck::{mod, MethodCall}; +use trans::debuginfo; +use trans::glue; +use trans::machine; +use trans::meth; +use trans::inline; +use trans::tvec; +use trans::type_of; +use middle::ty::{struct_fields, tup_fields}; +use middle::ty::{AdjustDerefRef, AdjustAddEnv, AutoUnsafe}; +use middle::ty::{AutoPtr}; +use middle::ty::{mod, Ty}; +use middle::ty::MethodCall; use util::common::indenter; use util::ppaux::Repr; use trans::machine::{llsize_of, llsize_of_alloc}; @@ -2091,7 +2099,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // path (below) to dereference that `&T`. let datum = match method_call.adjustment { // Always perform an AutoPtr when applying an overloaded auto-deref - typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), + ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), _ => datum }; diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index ef431243b31..94ff526debd 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -31,8 +31,7 @@ use trans::machine; use trans::type_::Type; use trans::type_of::*; use middle::ty::{mod, Ty}; -use middle::typeck; -use middle::typeck::MethodCall; +use middle::ty::MethodCall; use util::ppaux::Repr; use std::c_str::ToCStr; @@ -119,8 +118,8 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, .unwrap(); match origin { - typeck::MethodStatic(did) | - typeck::MethodStaticUnboxedClosure(did) => { + ty::MethodStatic(did) | + ty::MethodStaticUnboxedClosure(did) => { Callee { bcx: bcx, data: Fn(callee::trans_fn_ref(bcx, @@ -129,7 +128,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - typeck::MethodTypeParam(typeck::MethodParam { + ty::MethodTypeParam(ty::MethodParam { ref trait_ref, method_num }) => { @@ -147,7 +146,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_num, origin) } - typeck::MethodTraitObject(ref mt) => { + ty::MethodTraitObject(ref mt) => { let self_expr = match self_expr { Some(self_expr) => self_expr, None => { diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index fe7697447ac..c00c477f4b8 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -8,40 +8,64 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub mod doc; -pub mod macros; -pub mod inline; -pub mod monomorphize; -pub mod controlflow; -pub mod glue; -pub mod datum; -pub mod callee; -pub mod expr; -pub mod common; -pub mod context; -pub mod consts; -pub mod type_of; -pub mod build; -pub mod builder; -pub mod base; -pub mod _match; -pub mod closure; -pub mod tvec; -pub mod meth; -pub mod cabi; -pub mod cabi_x86; -pub mod cabi_x86_64; -pub mod cabi_x86_win64; -pub mod cabi_arm; -pub mod cabi_mips; -pub mod foreign; -pub mod intrinsic; -pub mod debuginfo; -pub mod machine; -pub mod adt; -pub mod asm; -pub mod type_; -pub mod value; -pub mod basic_block; -pub mod llrepr; -pub mod cleanup; +use llvm::{ContextRef, ModuleRef}; +use metadata::common::LinkMeta; +use middle::dependency_format; + +pub use self::base::trans_crate; +pub use self::context::CrateContext; +pub use self::common::gensym_name; + +mod doc; +mod macros; +mod inline; +mod monomorphize; +mod controlflow; +mod glue; +mod datum; +mod callee; +mod expr; +mod common; +mod context; +mod consts; +mod type_of; +mod build; +mod builder; +mod base; +mod _match; +mod closure; +mod tvec; +mod meth; +mod cabi; +mod cabi_x86; +mod cabi_x86_64; +mod cabi_x86_win64; +mod cabi_arm; +mod cabi_mips; +mod foreign; +mod intrinsic; +mod debuginfo; +mod machine; +mod adt; +mod asm; +mod type_; +mod value; +mod basic_block; +mod llrepr; +mod cleanup; + +pub struct ModuleTranslation { + pub llcx: ContextRef, + pub llmod: ModuleRef, +} + +pub struct CrateTranslation { + pub modules: Vec<ModuleTranslation>, + pub metadata_module: ModuleTranslation, + pub link: LinkMeta, + pub metadata: Vec<u8>, + pub reachable: Vec<String>, + pub crate_formats: dependency_format::Dependencies, + pub no_builtins: bool, +} + diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 89c004fc645..d95ad9a11c8 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -46,17 +46,17 @@ //! Note that the self region for the `foo` defaulted to `&` in the first //! case but `&a` in the second. Basically, defaults that appear inside //! an rptr (`&r.T`) use the region `r` that appears in the rptr. + +use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty::{mod, Ty}; -use middle::typeck::lookup_def_tcx; -use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope, - ShiftedRscope, BindingRscope}; -use middle::typeck::rscope; -use middle::typeck::TypeAndSubsts; +use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope, + ShiftedRscope, BindingRscope}; +use TypeAndSubsts; use util::common::ErrorReported; use util::nodemap::DefIdMap; use util::ppaux::{mod, Repr, UserString}; @@ -428,9 +428,9 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, where AC: AstConv<'tcx>, RS: RegionScope { - match lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + match ::lookup_def_tcx(this.tcx(), + ast_trait_ref.path.span, + ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, self_ty, &ast_trait_ref.path)); @@ -553,74 +553,6 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( } } -pub const NO_REGIONS: uint = 1; -pub const NO_TPS: uint = 2; - -fn check_path_args(tcx: &ty::ctxt, - path: &ast::Path, - flags: uint) { - if (flags & NO_TPS) != 0u { - if path.segments.iter().any(|s| s.parameters.has_types()) { - span_err!(tcx.sess, path.span, E0109, - "type parameters are not allowed on this type"); - } - } - - if (flags & NO_REGIONS) != 0u { - if path.segments.iter().any(|s| s.parameters.has_lifetimes()) { - span_err!(tcx.sess, path.span, E0110, - "region parameters are not allowed on this type"); - } - } -} - -pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) - -> Option<Ty<'tcx>> { - match ast_ty.node { - ast::TyPath(ref path, id) => { - let a_def = match tcx.def_map.borrow().get(&id) { - None => { - tcx.sess.span_bug(ast_ty.span, - format!("unbound path {}", - path.repr(tcx)).as_slice()) - } - Some(&d) => d - }; - match a_def { - def::DefPrimTy(nty) => { - match nty { - ast::TyBool => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_bool()) - } - ast::TyChar => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_char()) - } - ast::TyInt(it) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_int(it)) - } - ast::TyUint(uit) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_uint(uit)) - } - ast::TyFloat(ft) => { - check_path_args(tcx, path, NO_TPS | NO_REGIONS); - Some(ty::mk_mach_float(ft)) - } - ast::TyStr => { - Some(ty::mk_str(tcx)) - } - } - } - _ => None - } - } - _ => None - } -} - /// Converts the given AST type to a built-in type. A "built-in type" is, at /// present, either a core numeric type, a string, or `Box`. pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( @@ -1544,7 +1476,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, for &ast_bound in ast_bounds.iter() { match *ast_bound { ast::TraitTyParamBound(ref b) => { - match lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { + match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { def::DefTrait(trait_did) => { match trait_def_ids.get(&trait_did) { // Already seen this trait. We forbid diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index cdfd607d067..7dcf0aa3e21 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,13 +9,13 @@ // except according to those terms. use middle::def; +use middle::infer::{mod, resolve}; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; -use middle::typeck::check::{check_expr, check_expr_has_type, demand, FnCtxt}; -use middle::typeck::check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; -use middle::typeck::infer::{mod, resolve}; -use middle::typeck::require_same_types; +use check::{check_expr, check_expr_has_type, demand, FnCtxt}; +use check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; +use require_same_types; use util::nodemap::FnvHashMap; use std::cmp; diff --git a/src/librustc/middle/typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 0a93b3a5ec7..34030ae4493 100644 --- a/src/librustc/middle/typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -14,11 +14,11 @@ use super::check_fn; use super::{Expectation, ExpectCastableToType, ExpectHasType, NoExpectation}; use super::FnCtxt; +use astconv; +use middle::infer; use middle::subst; use middle::ty::{mod, Ty}; -use middle::typeck::astconv; -use middle::typeck::infer; -use middle::typeck::rscope::RegionScope; +use rscope::RegionScope; use syntax::abi; use syntax::ast; use syntax::ast_util; diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 1e45d059b84..9eb0e17b8e5 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -9,14 +9,13 @@ // except according to those terms. +use check::FnCtxt; use middle::ty::{mod, Ty}; -use middle::typeck::check::FnCtxt; -use middle::typeck::infer; -use middle::typeck::infer::resolve_type; -use middle::typeck::infer::resolve::try_resolve_tvar_shallow; +use middle::infer; +use middle::infer::resolve_type; +use middle::infer::resolve::try_resolve_tvar_shallow; -use std::result::{Err, Ok}; -use std::result; +use std::result::Result::{Err, Ok}; use syntax::ast; use syntax::codemap::Span; use util::ppaux::Repr; @@ -29,12 +28,6 @@ pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) } -pub fn subtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, true, actual, expected, - |sp, a, e, s| { fcx.report_mismatched_types(sp, e, a, s) }) -} - pub fn suptype_with_fn<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, b_is_expected: bool, @@ -44,8 +37,8 @@ pub fn suptype_with_fn<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // n.b.: order of actual, expected is reversed match infer::mk_subty(fcx.infcx(), b_is_expected, infer::Misc(sp), ty_b, ty_a) { - result::Ok(()) => { /* ok */ } - result::Err(ref err) => { + Ok(()) => { /* ok */ } + Err(ref err) => { handle_err(sp, ty_a, ty_b, err); } } @@ -75,8 +68,8 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, try_resolve_tvar_shallow).unwrap_or(expected) } else { expected }; match fcx.mk_assignty(expr, expr_ty, expected) { - result::Ok(()) => { /* ok */ } - result::Err(ref err) => { + Ok(()) => { /* ok */ } + Err(ref err) => { fcx.report_mismatched_types(sp, expected, expr_ty, err); } } diff --git a/src/librustc/middle/typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e866627be3d..1fe73f0478d 100644 --- a/src/librustc/middle/typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,13 +10,14 @@ use super::probe; +use check::{mod, FnCtxt, NoPreference, PreferMutLvalue}; use middle::subst::{mod, Subst}; use middle::traits; use middle::ty::{mod, Ty}; -use middle::typeck::check::{mod, FnCtxt, NoPreference, PreferMutLvalue}; -use middle::typeck::{MethodCall, MethodCallee, MethodObject, MethodOrigin, - MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; -use middle::typeck::infer::{mod, InferCtxt}; +use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, + MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; +use middle::infer; +use middle::infer::InferCtxt; use middle::ty_fold::HigherRankedFoldable; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/typeck/check/method/doc.rs b/src/librustc_typeck/check/method/doc.rs index 6129e38e39c..6129e38e39c 100644 --- a/src/librustc/middle/typeck/check/method/doc.rs +++ b/src/librustc_typeck/check/method/doc.rs diff --git a/src/librustc/middle/typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 34c3292f8cd..f87a4c9294b 100644 --- a/src/librustc/middle/typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,19 +10,17 @@ //! Method lookup: the secret sauce of Rust. See `doc.rs`. +use astconv::AstConv; +use check::{FnCtxt}; +use check::{impl_self_ty}; +use check::vtable; +use check::vtable::select_new_fcx_obligations; use middle::subst; use middle::subst::{Subst}; use middle::traits; use middle::ty::*; use middle::ty; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::{FnCtxt}; -use middle::typeck::check::{impl_self_ty}; -use middle::typeck::check::vtable; -use middle::typeck::check::vtable::select_new_fcx_obligations; -use middle::typeck::infer; -use middle::typeck::{MethodCallee}; -use middle::typeck::{MethodParam, MethodTypeParam}; +use middle::infer; use util::ppaux::{Repr, UserString}; use std::rc::Rc; diff --git a/src/librustc/middle/typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 484d72130e6..6ff276edbce 100644 --- a/src/librustc/middle/typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -12,17 +12,17 @@ use super::{MethodError,Ambiguity,NoMatch}; use super::MethodIndex; use super::{CandidateSource,ImplSource,TraitSource}; +use check; +use check::{FnCtxt, NoPreference}; use middle::fast_reject; use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{mod, Ty}; +use middle::ty::{MethodObject}; use middle::ty_fold::HigherRankedFoldable; -use middle::typeck::check; -use middle::typeck::check::{FnCtxt, NoPreference}; -use middle::typeck::{MethodObject}; -use middle::typeck::infer; -use middle::typeck::infer::InferCtxt; +use middle::infer; +use middle::infer::InferCtxt; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; use std::collections::HashSet; diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 641cbd11d64..cdf34c7f4d2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -31,7 +31,7 @@ can be broken down into several distinct phases: In the process of checking, various constraints will be placed on these type variables through the subtyping relationships requested - through the `demand` module. The `typeck::infer` module is in charge + through the `demand` module. The `infer` module is in charge of resolving those constraints. - regionck: after main is complete, the regionck pass goes over all @@ -82,8 +82,10 @@ pub use self::Expectation::*; use self::IsBinopAssignment::*; use self::TupleArgumentsFlag::*; -use session::Session; +use astconv::{mod, ast_region_to_region, ast_ty_to_ty, AstConv}; +use check::_match::pat_ctxt; use middle::{const_eval, def, traits}; +use middle::infer; use middle::lang_items::IteratorItem; use middle::mem_categorization::{mod, McResult}; use middle::pat_util::{mod, pat_id_map}; @@ -93,12 +95,12 @@ use middle::ty::{FnSig, VariantInfo, Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{mod, Ty}; use middle::ty::liberate_late_bound_regions; +use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; use middle::ty_fold::TypeFolder; -use middle::typeck::astconv::{mod, ast_region_to_region, ast_ty_to_ty, AstConv}; -use middle::typeck::check::_match::pat_ctxt; -use middle::typeck::rscope::RegionScope; -use middle::typeck::{mod, CrateCtxt, infer, lookup_def_ccx, no_params, require_same_types}; -use middle::typeck::{MethodCall, MethodCallee, MethodMap, ObjectCastMap, TypeAndSubsts}; +use rscope::RegionScope; +use session::Session; +use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; +use TypeAndSubsts; use middle::lang_items::TypeIdLangItem; use lint; use util::common::{block_query, indenter, loop_query}; @@ -279,7 +281,7 @@ impl<'a, 'tcx> mem_categorization::Typer<'tcx> for FnCtxt<'a, 'tcx> { fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> { Ok(self.node_ty(id)) } - fn node_method_ty(&self, method_call: typeck::MethodCall) + fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> { self.inh.method_map.borrow().get(&method_call).map(|m| m.ty) } @@ -287,7 +289,7 @@ impl<'a, 'tcx> mem_categorization::Typer<'tcx> for FnCtxt<'a, 'tcx> { &self.inh.adjustments } fn is_method_call(&self, id: ast::NodeId) -> bool { - self.inh.method_map.borrow().contains_key(&typeck::MethodCall::expr(id)) + self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id)) } fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> { self.tcx().temporary_scope(rvalue_id) @@ -359,6 +361,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> { check_item(self.ccx, i); visit::walk_item(self, i); } + + fn visit_ty(&mut self, t: &ast::Ty) { + match t.node { + ast::TyFixedLengthVec(_, ref expr) => { + check_const_in_type(self.ccx, &**expr, ty::mk_uint()); + } + _ => {} + } + + visit::walk_ty(self, t); + } } pub fn check_item_types(ccx: &CrateCtxt) { @@ -1734,8 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), ty_trait, span); - + vtable::check_object_safety(self.tcx(), &ty_trait.principal, span); // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: vtable::register_object_cast_obligations(self, @@ -1860,13 +1872,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Fetch type of `expr` after applying adjustments that have been recorded in the fcx. - pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> { - let adjustments = self.inh.adjustments.borrow(); - let adjustment = adjustments.get(&expr.id); - self.adjust_expr_ty(expr, adjustment) - } - /// Apply `adjustment` to the type of `expr` pub fn adjust_expr_ty(&self, expr: &ast::Expr, @@ -1919,16 +1924,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup) } - pub fn can_mk_subty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) - -> Result<(), ty::type_err<'tcx>> { - infer::can_mk_subty(self.infcx(), sub, sup) - } - - pub fn can_mk_eqty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) - -> Result<(), ty::type_err<'tcx>> { - infer::can_mk_eqty(self.infcx(), sub, sup) - } - pub fn mk_assignty(&self, expr: &ast::Expr, sub: Ty<'tcx>, @@ -3260,7 +3255,7 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(method) => { let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. - let method_call = ::middle::typeck::MethodCall::expr(op_ex.id); + let method_call = ::middle::ty::MethodCall::expr(op_ex.id); fcx.inh.method_map.borrow_mut().insert(method_call, method); match check_method_argument_types(fcx, op_ex.span, @@ -4670,25 +4665,18 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Checks a constant appearing in a type. At the moment this is just the /// length expression in a fixed-length vector, but someday it might be /// extended to type-level numeric literals. -pub fn check_const_in_type<'tcx>(tcx: &ty::ctxt<'tcx>, - expr: &ast::Expr, - expected_type: Ty<'tcx>) { - // Synthesize a crate context. The trait map is not needed here (though I - // imagine it will be if we have associated statics --pcwalton), so we - // leave it blank. - let ccx = CrateCtxt { - trait_map: NodeMap::new(), - tcx: tcx, - }; - let inh = static_inherited_fields(&ccx); - let fcx = blank_fn_ctxt(&ccx, &inh, ty::FnConverging(expected_type), expr.id); +fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>, + expr: &ast::Expr, + expected_type: Ty<'tcx>) { + let inh = static_inherited_fields(ccx); + let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id); check_const_with_ty(&fcx, expr.span, expr, expected_type); } -pub fn check_const(ccx: &CrateCtxt, - sp: Span, - e: &ast::Expr, - id: ast::NodeId) { +fn check_const(ccx: &CrateCtxt, + sp: Span, + e: &ast::Expr, + id: ast::NodeId) { let inh = static_inherited_fields(ccx); let rty = ty::node_id_to_type(ccx.tcx, id); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); @@ -4696,10 +4684,10 @@ pub fn check_const(ccx: &CrateCtxt, check_const_with_ty(&fcx, sp, e, declty); } -pub fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - _: Span, - e: &ast::Expr, - declty: Ty<'tcx>) { +fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + _: Span, + e: &ast::Expr, + declty: Ty<'tcx>) { // Gather locals in statics (because of block expressions). // This is technically unnecessary because locals in static items are forbidden, // but prevents type checking from blowing up before const checking can properly diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 08f7f9cf5e3..2aec4393de9 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -114,20 +114,19 @@ //! then mean that all later passes would have to check for these figments //! and report an error, and it just seems like more mess in the end.) +use astconv::AstConv; +use check::FnCtxt; +use check::regionmanip; +use check::vtable; use middle::def; use middle::mem_categorization as mc; use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; -use middle::ty::{mod, Ty}; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::FnCtxt; -use middle::typeck::check::regionmanip; -use middle::typeck::check::vtable; -use middle::typeck::infer::resolve_and_force_all_but_regions; -use middle::typeck::infer::resolve_type; -use middle::typeck::infer; -use middle::typeck::MethodCall; +use middle::ty::{mod, Ty, MethodCall}; +use middle::infer::resolve_and_force_all_but_regions; +use middle::infer::resolve_type; +use middle::infer; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; use util::ppaux::{ty_to_string, Repr}; diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index 55214618aa9..92dfd8b5f56 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -380,3 +380,22 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { } } } + +impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + RegionSubRegionConstraint(_, r_a, r_b) => { + format!("RegionSubRegionConstraint({}, {})", + r_a.repr(tcx), + r_b.repr(tcx)) + } + + RegionSubParamConstraint(_, r, p) => { + format!("RegionSubParamConstraint({}, {})", + r.repr(tcx), + p.repr(tcx)) + } + } + } +} + diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 84cb74b4de2..b9f7eb3f271 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use check::{FnCtxt, structurally_resolved_type}; use middle::subst::{SelfSpace, FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; @@ -15,9 +16,7 @@ use middle::traits::{Obligation, obligation_for_builtin_bound}; use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; use middle::traits::{ObligationCause}; use middle::ty::{mod, Ty}; -use middle::typeck::check::{FnCtxt, - structurally_resolved_type}; -use middle::typeck::infer; +use middle::infer; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; @@ -46,7 +45,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Ensure that if ~T is cast to ~Trait, then T : Trait push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - check_object_safety(fcx.tcx(), object_trait, source_expr.span); + check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); } (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, @@ -70,7 +69,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, target_region, referent_region); - check_object_safety(fcx.tcx(), object_trait, source_expr.span); + check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); } } @@ -134,17 +133,32 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // self by value, has no type parameters and does not use the `Self` type, except // in self position. pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TyTrait<'tcx>, + object_trait: &ty::TraitRef<'tcx>, + span: Span) { + + let mut object = object_trait.clone(); + if object.substs.types.len(SelfSpace) == 0 { + object.substs.types.push(SelfSpace, ty::mk_err()); + } + + let object = Rc::new(object); + for tr in traits::supertraits(tcx, object) { + check_object_safety_inner(tcx, &*tr, span); + } +} + +fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, + object_trait: &ty::TraitRef<'tcx>, span: Span) { // Skip the fn_once lang item trait since only the compiler should call // `call_once` which is the method which takes self by value. What could go // wrong? match tcx.lang_items.fn_once_trait() { - Some(def_id) if def_id == object_trait.principal.def_id => return, + Some(def_id) if def_id == object_trait.def_id => return, _ => {} } - let trait_items = ty::trait_items(tcx, object_trait.principal.def_id); + let trait_items = ty::trait_items(tcx, object_trait.def_id); let mut errors = Vec::new(); for item in trait_items.iter() { @@ -158,7 +172,7 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, let mut errors = errors.iter().flat_map(|x| x.iter()).peekable(); if errors.peek().is_some() { - let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id); + let trait_name = ty::item_path_str(tcx, object_trait.def_id); span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", trait_name); diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 8535ec4fa6e..1769c588ec1 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use astconv::AstConv; +use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; +use CrateCtxt; use middle::region; use middle::subst; use middle::subst::{Subst}; @@ -15,9 +18,6 @@ use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::liberate_late_bound_regions; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; -use middle::typeck::CrateCtxt; use util::ppaux::Repr; use std::collections::HashSet; diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 23af30b44d9..777f354bec1 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -13,18 +13,17 @@ // substitutions. use self::ResolveReason::*; +use astconv::AstConv; +use check::FnCtxt; use middle::def; use middle::pat_util; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::FnCtxt; -use middle::typeck::infer::{force_all, resolve_all, resolve_region}; -use middle::typeck::infer::resolve_type; -use middle::typeck::infer; -use middle::typeck::{MethodCall, MethodCallee}; -use middle::typeck::write_substs_to_tcx; -use middle::typeck::write_ty_to_tcx; +use middle::infer::{force_all, resolve_all, resolve_region}; +use middle::infer::resolve_type; +use middle::infer; +use write_substs_to_tcx; +use write_ty_to_tcx; use util::ppaux::Repr; use std::cell::Cell; diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 758608b79c2..b8642ddde40 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -19,7 +19,6 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst; -use middle::subst::{Substs}; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{TypeTraitItemId, lookup_item_type}; use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err}; @@ -31,10 +30,10 @@ use middle::ty::{ty_closure}; use middle::ty::type_is_ty_var; use middle::subst::Subst; use middle::ty; -use middle::typeck::CrateCtxt; -use middle::typeck::infer::combine::Combine; -use middle::typeck::infer::InferCtxt; -use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use CrateCtxt; +use middle::infer::combine::Combine; +use middle::infer::InferCtxt; +use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -477,27 +476,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } -/// Substitutes the values for the receiver's type parameters that are found in method, leaving the -/// method's type parameters intact. -pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - method: &ty::Method<'tcx>) - -> subst::Substs<'tcx> -{ - let meth_tps: Vec<Ty> = - method.generics.types.get_slice(subst::FnSpace) - .iter() - .map(|def| ty::mk_param_from_def(tcx, def)) - .collect(); - let meth_regions: Vec<ty::Region> = - method.generics.regions.get_slice(subst::FnSpace) - .iter() - .map(|def| ty::ReEarlyBound(def.def_id.node, def.space, - def.index, def.name)) - .collect(); - trait_ref.substs.clone().with_method(meth_tps, meth_regions) -} - fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, impl_id: ast::DefId, impl_poly_type: &ty::Polytype<'tcx>, @@ -507,7 +485,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, provided_source: Option<ast::DefId>) -> ty::Method<'tcx> { - let combined_substs = make_substs_for_receiver_types(tcx, trait_ref, method); + let combined_substs = ty::make_substs_for_receiver_types(tcx, trait_ref, method); debug!("subst_receiver_types_in_method_ty: combined_substs={}", combined_substs.repr(tcx)); diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index dc3afaae35f..dc3afaae35f 100644 --- a/src/librustc/middle/typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs diff --git a/src/librustc/middle/typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 9f10a58f458..0e74d4578d9 100644 --- a/src/librustc/middle/typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -13,8 +13,7 @@ use middle::traits; use middle::ty; -use middle::typeck::infer::{new_infer_ctxt}; -use middle::typeck::infer; +use middle::infer::{mod, new_infer_ctxt}; use syntax::ast::{DefId}; use syntax::ast::{LOCAL_CRATE}; use syntax::ast; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc_typeck/collect.rs index 6e989dd73db..717e886029a 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -32,6 +32,9 @@ as `ty_param()` instances. use self::ConvertMethodContext::*; use self::CreateTypeParametersForAssociatedTypesFlag::*; +use astconv::{AstConv, ty_of_arg}; +use astconv::{ast_ty_to_ty, ast_region_to_region}; +use astconv; use metadata::csearch; use middle::def; use middle::lang_items::SizedTraitLangItem; @@ -43,13 +46,9 @@ use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{Polytype}; use middle::ty::{mod, Ty}; use middle::ty_fold::TypeFolder; -use middle::typeck::astconv::{AstConv, ty_of_arg}; -use middle::typeck::astconv::{ast_ty_to_ty, ast_region_to_region}; -use middle::typeck::astconv; -use middle::typeck::infer; -use middle::typeck::rscope::*; -use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; -use middle::typeck; +use middle::infer; +use rscope::*; +use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; @@ -2159,13 +2158,13 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( base_type.repr(crate_context.tcx), base_type_free.repr(crate_context.tcx)); let infcx = infer::new_infer_ctxt(crate_context.tcx); - drop(typeck::require_same_types(crate_context.tcx, - Some(&infcx), - false, - explicit_self.span, - base_type_free, - required_type_free, - || { + drop(::require_same_types(crate_context.tcx, + Some(&infcx), + false, + explicit_self.span, + base_type_free, + required_type_free, + || { format!("mismatched self type: expected `{}`", ppaux::ty_to_string(crate_context.tcx, required_type)) })); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs new file mode 100644 index 00000000000..36e81f18103 --- /dev/null +++ b/src/librustc_typeck/diagnostics.rs @@ -0,0 +1,151 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +register_diagnostic!(E0001, r##" + This error suggests that the expression arm corresponding to the noted pattern + will never be reached as for all possible values of the expression being matched, + one of the preceeding patterns will match. + + This means that perhaps some of the preceeding patterns are too general, this + one is too specific or the ordering is incorrect. +"##) + +register_diagnostics!( + E0002, + E0003, + E0004, + E0005, + E0006, + E0007, + E0008, + E0009, + E0010, + E0011, + E0012, + E0013, + E0014, + E0015, + E0016, + E0017, + E0018, + E0019, + E0020, + E0022, + E0023, + E0024, + E0025, + E0026, + E0027, + E0029, + E0030, + E0031, + E0033, + E0034, + E0035, + E0036, + E0038, + E0040, + E0044, + E0045, + E0046, + E0049, + E0050, + E0051, + E0052, + E0053, + E0054, + E0055, + E0056, + E0057, + E0059, + E0060, + E0061, + E0062, + E0063, + E0066, + E0067, + E0068, + E0069, + E0070, + E0071, + E0072, + E0073, + E0074, + E0075, + E0076, + E0077, + E0079, + E0080, + E0081, + E0082, + E0083, + E0084, + E0085, + E0086, + E0087, + E0088, + E0089, + E0090, + E0091, + E0092, + E0093, + E0094, + E0100, + E0101, + E0102, + E0103, + E0104, + E0106, + E0107, + E0108, + E0109, + E0110, + E0116, + E0117, + E0118, + E0119, + E0120, + E0121, + E0122, + E0124, + E0127, + E0128, + E0129, + E0130, + E0131, + E0132, + E0133, + E0134, + E0135, + E0136, + E0137, + E0138, + E0139, + E0140, + E0141, + E0152, + E0153, + E0157, + E0158, + E0159, + E0161, + E0162, + E0163, + E0164, + E0165, + E0166, + E0167, + E0168, + E0169, + E0171, + E0172 +) diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc_typeck/lib.rs index 501dfcb2e2d..2f5b473567f 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc_typeck/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* +/*! typeck.rs, an introduction @@ -57,16 +57,40 @@ independently: all subtyping and assignment constraints are met. In essence, the check module specifies the constraints, and the infer module solves them. +# Note + +This API is completely unstable and subject to change. + */ +#![crate_name = "rustc_typeck"] +#![experimental] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/")] + +#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)] +#![feature(slicing_syntax, tuple_indexing, unsafe_destructor)] +#![feature(rustc_diagnostic_macros)] #![allow(non_camel_case_types)] -pub use self::ExprAdjustment::*; -pub use self::vtable_origin::*; -pub use self::MethodOrigin::*; +#[phase(plugin, link)] extern crate log; +#[phase(plugin, link)] extern crate syntax; + +extern crate arena; +extern crate rustc; + +pub use rustc::lint; +pub use rustc::metadata; +pub use rustc::middle; +pub use rustc::session; +pub use rustc::util; use middle::def; use middle::resolve; +use middle::infer; use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty::{mod, Ty}; @@ -74,222 +98,40 @@ use session::config; use util::common::time; use util::ppaux::Repr; use util::ppaux; -use util::nodemap::{NodeMap, FnvHashMap}; -use std::cell::RefCell; -use std::rc::Rc; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; -pub mod check; -pub mod rscope; -pub mod astconv; -pub mod infer; -pub mod collect; -pub mod coherence; -pub mod variance; - -#[deriving(Clone, Encodable, Decodable, PartialEq, PartialOrd, Show)] -pub struct param_index { - pub space: subst::ParamSpace, - pub index: uint -} - -#[deriving(Clone, Show)] -pub enum MethodOrigin<'tcx> { - // fully statically resolved method - MethodStatic(ast::DefId), - - // fully statically resolved unboxed closure invocation - MethodStaticUnboxedClosure(ast::DefId), +#[cfg(stage0)] +mod diagnostics; - // method invoked on a type parameter with a bounded trait - MethodTypeParam(MethodParam<'tcx>), - - // method invoked on a trait instance - MethodTraitObject(MethodObject<'tcx>), - -} - -// details for a method invoked with a receiver whose type is a type parameter -// with a bounded trait. -#[deriving(Clone, Show)] -pub struct MethodParam<'tcx> { - // the precise trait reference that occurs as a bound -- this may - // be a supertrait of what the user actually typed. - pub trait_ref: Rc<ty::TraitRef<'tcx>>, - - // index of uint in the list of methods for the trait - pub method_num: uint, -} - -// details for a method invoked with a receiver whose type is an object -#[deriving(Clone, Show)] -pub struct MethodObject<'tcx> { - // the (super)trait containing the method to be invoked - pub trait_ref: Rc<ty::TraitRef<'tcx>>, - - // the actual base trait id of the object - pub object_trait_id: ast::DefId, - - // index of the method to be invoked amongst the trait's methods - pub method_num: uint, - - // index into the actual runtime vtable. - // the vtable is formed by concatenating together the method lists of - // the base object trait and all supertraits; this is the index into - // that vtable - pub real_index: uint, -} - -#[deriving(Clone)] -pub struct MethodCallee<'tcx> { - pub origin: MethodOrigin<'tcx>, - pub ty: Ty<'tcx>, - pub substs: subst::Substs<'tcx> -} - -/// With method calls, we store some extra information in -/// side tables (i.e method_map). We use -/// MethodCall as a key to index into these tables instead of -/// just directly using the expression's NodeId. The reason -/// for this being that we may apply adjustments (coercions) -/// with the resulting expression also needing to use the -/// side tables. The problem with this is that we don't -/// assign a separate NodeId to this new expression -/// and so it would clash with the base expression if both -/// needed to add to the side tables. Thus to disambiguate -/// we also keep track of whether there's an adjustment in -/// our key. -#[deriving(Clone, PartialEq, Eq, Hash, Show)] -pub struct MethodCall { - pub expr_id: ast::NodeId, - pub adjustment: ExprAdjustment -} - -#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)] -pub enum ExprAdjustment { - NoAdjustment, - AutoDeref(uint), - AutoObject -} +mod check; +mod rscope; +mod astconv; +mod collect; +mod coherence; +mod variance; -pub struct TypeAndSubsts<'tcx> { +struct TypeAndSubsts<'tcx> { pub substs: subst::Substs<'tcx>, pub ty: Ty<'tcx>, } -impl MethodCall { - pub fn expr(id: ast::NodeId) -> MethodCall { - MethodCall { - expr_id: id, - adjustment: NoAdjustment - } - } - - pub fn autoobject(id: ast::NodeId) -> MethodCall { - MethodCall { - expr_id: id, - adjustment: AutoObject - } - } - - pub fn autoderef(expr_id: ast::NodeId, autoderef: uint) -> MethodCall { - MethodCall { - expr_id: expr_id, - adjustment: AutoDeref(1 + autoderef) - } - } -} - -// maps from an expression id that corresponds to a method call to the details -// of the method to be invoked -pub type MethodMap<'tcx> = RefCell<FnvHashMap<MethodCall, MethodCallee<'tcx>>>; - -pub type vtable_param_res<'tcx> = Vec<vtable_origin<'tcx>>; - -// Resolutions for bounds of all parameters, left to right, for a given path. -pub type vtable_res<'tcx> = VecPerParamSpace<vtable_param_res<'tcx>>; - -#[deriving(Clone)] -pub enum vtable_origin<'tcx> { - /* - Statically known vtable. def_id gives the impl item - from whence comes the vtable, and tys are the type substs. - vtable_res is the vtable itself. - */ - vtable_static(ast::DefId, subst::Substs<'tcx>, vtable_res<'tcx>), - - /* - Dynamic vtable, comes from a parameter that has a bound on it: - fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a - vtable_param origin - - The first argument is the param index (identifying T in the example), - and the second is the bound number (identifying baz) - */ - vtable_param(param_index, uint), - - /* - Vtable automatically generated for an unboxed closure. The def ID is the - ID of the closure expression. - */ - vtable_unboxed_closure(ast::DefId), - - /* - Asked to determine the vtable for ty_err. This is the value used - for the vtables of `Self` in a virtual call like `foo.bar()` - where `foo` is of object type. The same value is also used when - type errors occur. - */ - vtable_error, -} - -impl<'tcx> Repr<'tcx> for vtable_origin<'tcx> { - fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - match *self { - vtable_static(def_id, ref tys, ref vtable_res) => { - format!("vtable_static({}:{}, {}, {})", - def_id, - ty::item_path_str(tcx, def_id), - tys.repr(tcx), - vtable_res.repr(tcx)) - } - - vtable_param(x, y) => { - format!("vtable_param({}, {})", x, y) - } - - vtable_unboxed_closure(def_id) => { - format!("vtable_unboxed_closure({})", def_id) - } - - vtable_error => { - format!("vtable_error") - } - } - } -} - -// For every explicit cast into an object type, maps from the cast -// expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::TraitRef<'tcx>>>>; - -pub struct CrateCtxt<'a, 'tcx: 'a> { +struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. trait_map: resolve::TraitMap, tcx: &'a ty::ctxt<'tcx> } // Functions that write types into the node type table -pub fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { +fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty)); assert!(!ty::type_needs_infer(ty)); tcx.node_types.borrow_mut().insert(node_id, ty); } -pub fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, +fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, item_substs: ty::ItemSubsts<'tcx>) { if !item_substs.is_noop() { @@ -302,7 +144,7 @@ pub fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, tcx.item_substs.borrow_mut().insert(node_id, item_substs); } } -pub fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { +fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { match tcx.def_map.borrow().get(&id) { Some(x) => x.clone(), _ => { @@ -311,12 +153,12 @@ pub fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { } } -pub fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) +fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) -> def::Def { lookup_def_tcx(ccx.tcx, sp, id) } -pub fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> { +fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> { ty::Polytype { generics: ty::Generics {types: VecPerParamSpace::empty(), regions: VecPerParamSpace::empty()}, @@ -324,7 +166,7 @@ pub fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> { } } -pub fn require_same_types<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, +fn require_same_types<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, t1_is_expected: bool, span: Span, diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 3bca24f479f..3bca24f479f 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc_typeck/variance.rs index ade3144ce41..ade3144ce41 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc_typeck/variance.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6f1ddaff360..7e02891160a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,7 +39,6 @@ use syntax::parse::token; use syntax::ptr::P; use rustc_trans::back::link; -use rustc_trans::driver::driver; use rustc::metadata::cstore; use rustc::metadata::csearch; use rustc::metadata::decoder; @@ -48,6 +47,7 @@ use rustc::middle::subst; use rustc::middle::subst::VecPerParamSpace; use rustc::middle::ty; use rustc::middle::stability; +use rustc::session::config; use std::rc::Rc; use std::u32; @@ -131,7 +131,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> { externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); // Figure out the name of this crate - let input = driver::FileInput(cx.src.clone()); + let input = config::Input::File(cx.src.clone()); let name = link::find_crate_name(None, self.attrs.as_slice(), &input); // Clean the crate, translating the entire libsyntax AST to one that is diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b040a4bfd2a..4cd88bca51e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -9,7 +9,7 @@ // except according to those terms. pub use self::MaybeTyped::*; -use rustc_trans::driver::driver; +use rustc_driver::driver; use rustc::session::{mod, config}; use rustc::middle::{privacy, ty}; use rustc::lint; @@ -83,7 +83,7 @@ pub fn run_core(libs: Vec<Path>, cfgs: Vec<String>, externs: Externs, // Parse, resolve, and typecheck the given crate. - let input = driver::FileInput(cpath.clone()); + let input = config::Input::File(cpath.clone()); let warning_lint = lint::builtin::WARNINGS.name_lower(); @@ -122,7 +122,7 @@ pub fn run_core(libs: Vec<Path>, cfgs: Vec<String>, externs: Externs, let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest); let type_arena = TypedArena::new(); - let driver::CrateAnalysis { + let ty::CrateAnalysis { exported_items, public_items, ty_cx, .. } = driver::phase_3_run_analysis_passes(sess, ast_map, &type_arena, name); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6e0b76d441b..9861d18ce51 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -23,7 +23,6 @@ use syntax::ast_util; use clean; use stability_summary::ModuleSummary; -use html::item_type; use html::item_type::ItemType; use html::render; use html::render::{cache, CURRENT_LOCATION_KEY}; @@ -283,7 +282,7 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, url.push_str("/"); } match shortty { - item_type::Module => { + ItemType::Module => { url.push_str(fqp.last().unwrap().as_slice()); url.push_str("/index.html"); } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index cb3ad9d063f..0ad12b957ba 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -9,7 +9,6 @@ // except according to those terms. //! Item types. -pub use self::ItemType::*; use std::fmt; use clean; @@ -35,8 +34,7 @@ pub enum ItemType { Method = 10, StructField = 11, Variant = 12, - ForeignFunction = 13, - ForeignStatic = 14, + // we used to have ForeignFunction and ForeignStatic. they are retired now. Macro = 15, Primitive = 16, AssociatedType = 17, @@ -44,27 +42,62 @@ pub enum ItemType { } impl ItemType { + pub fn from_item(item: &clean::Item) -> ItemType { + match item.inner { + clean::ModuleItem(..) => ItemType::Module, + clean::StructItem(..) => ItemType::Struct, + clean::EnumItem(..) => ItemType::Enum, + clean::FunctionItem(..) => ItemType::Function, + clean::TypedefItem(..) => ItemType::Typedef, + clean::StaticItem(..) => ItemType::Static, + clean::ConstantItem(..) => ItemType::Constant, + clean::TraitItem(..) => ItemType::Trait, + clean::ImplItem(..) => ItemType::Impl, + clean::ViewItemItem(..) => ItemType::ViewItem, + clean::TyMethodItem(..) => ItemType::TyMethod, + clean::MethodItem(..) => ItemType::Method, + clean::StructFieldItem(..) => ItemType::StructField, + clean::VariantItem(..) => ItemType::Variant, + clean::ForeignFunctionItem(..) => ItemType::Function, // no ForeignFunction + clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic + clean::MacroItem(..) => ItemType::Macro, + clean::PrimitiveItem(..) => ItemType::Primitive, + clean::AssociatedTypeItem(..) => ItemType::AssociatedType, + } + } + + pub fn from_type_kind(kind: clean::TypeKind) -> ItemType { + match kind { + clean::TypeStruct => ItemType::Struct, + clean::TypeEnum => ItemType::Enum, + clean::TypeFunction => ItemType::Function, + clean::TypeTrait => ItemType::Trait, + clean::TypeModule => ItemType::Module, + clean::TypeStatic => ItemType::Static, + clean::TypeVariant => ItemType::Variant, + clean::TypeTypedef => ItemType::Typedef, + } + } + pub fn to_static_str(&self) -> &'static str { match *self { - Module => "mod", - Struct => "struct", - Enum => "enum", - Function => "fn", - Typedef => "type", - Static => "static", - Trait => "trait", - Impl => "impl", - ViewItem => "viewitem", - TyMethod => "tymethod", - Method => "method", - StructField => "structfield", - Variant => "variant", - ForeignFunction => "ffi", - ForeignStatic => "ffs", - Macro => "macro", - Primitive => "primitive", - AssociatedType => "associatedtype", - Constant => "constant", + ItemType::Module => "mod", + ItemType::Struct => "struct", + ItemType::Enum => "enum", + ItemType::Function => "fn", + ItemType::Typedef => "type", + ItemType::Static => "static", + ItemType::Trait => "trait", + ItemType::Impl => "impl", + ItemType::ViewItem => "viewitem", + ItemType::TyMethod => "tymethod", + ItemType::Method => "method", + ItemType::StructField => "structfield", + ItemType::Variant => "variant", + ItemType::Macro => "macro", + ItemType::Primitive => "primitive", + ItemType::AssociatedType => "associatedtype", + ItemType::Constant => "constant", } } } @@ -75,27 +108,3 @@ impl fmt::Show for ItemType { } } -pub fn shortty(item: &clean::Item) -> ItemType { - match item.inner { - clean::ModuleItem(..) => Module, - clean::StructItem(..) => Struct, - clean::EnumItem(..) => Enum, - clean::FunctionItem(..) => Function, - clean::TypedefItem(..) => Typedef, - clean::StaticItem(..) => Static, - clean::ConstantItem(..) => Constant, - clean::TraitItem(..) => Trait, - clean::ImplItem(..) => Impl, - clean::ViewItemItem(..) => ViewItem, - clean::TyMethodItem(..) => TyMethod, - clean::MethodItem(..) => Method, - clean::StructFieldItem(..) => StructField, - clean::VariantItem(..) => Variant, - clean::ForeignFunctionItem(..) => ForeignFunction, - clean::ForeignStaticItem(..) => ForeignStatic, - clean::MacroItem(..) => Macro, - clean::PrimitiveItem(..) => Primitive, - clean::AssociatedTypeItem(..) => AssociatedType, - } -} - diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 896d070c155..23f31580619 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -160,6 +160,7 @@ r##"<!DOCTYPE html> } pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> { + // <script> triggers a redirect before refresh, so this is fine. write!(dst, r##"<!DOCTYPE html> <html lang="en"> @@ -167,6 +168,8 @@ r##"<!DOCTYPE html> <meta http-equiv="refresh" content="0;URL={url}"> </head> <body> + <p>Redirecting to <a href="{url}">{url}</a>...</p> + <script>location.replace("{url}" + location.search + location.hash);</script> </body> </html>"##, url = url, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2be703e2458..9eee8e04f0c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -61,8 +61,7 @@ use fold::DocFolder; use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability}; use html::format::{ConciseStability, TyParamBounds, WhereClause}; use html::highlight; -use html::item_type::{ItemType, shortty}; -use html::item_type; +use html::item_type::ItemType; use html::layout; use html::markdown::Markdown; use html::markdown; @@ -314,19 +313,8 @@ pub fn run(mut krate: clean::Crate, let paths: HashMap<ast::DefId, (Vec<String>, ItemType)> = analysis.as_ref().map(|a| { let paths = a.external_paths.borrow_mut().take().unwrap(); - paths.into_iter().map(|(k, (v, t))| { - (k, (v, match t { - clean::TypeStruct => item_type::Struct, - clean::TypeEnum => item_type::Enum, - clean::TypeFunction => item_type::Function, - clean::TypeTrait => item_type::Trait, - clean::TypeModule => item_type::Module, - clean::TypeStatic => item_type::Static, - clean::TypeVariant => item_type::Variant, - clean::TypeTypedef => item_type::Typedef, - })) - }).collect() - }).unwrap_or(HashMap::new()); + paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))).collect() + }).unwrap_or(HashMap::new()); let mut cache = Cache { impls: HashMap::new(), external_paths: paths.iter().map(|(&k, v)| (k, v.ref0().clone())) @@ -359,7 +347,7 @@ pub fn run(mut krate: clean::Crate, for &(n, ref e) in krate.externs.iter() { cache.extern_locations.insert(n, extern_location(e, &cx.dst)); let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; - cache.paths.insert(did, (vec![e.name.to_string()], item_type::Module)); + cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. @@ -642,6 +630,11 @@ fn mkdir(path: &Path) -> io::IoResult<()> { } } +/// Returns a documentation-level item type from the item. +fn shortty(item: &clean::Item) -> ItemType { + ItemType::from_item(item) +} + /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a /// static HTML tree. @@ -855,13 +848,13 @@ impl DocFolder for Cache { let last = self.parent_stack.last().unwrap(); let did = *last; let path = match self.paths.get(&did) { - Some(&(_, item_type::Trait)) => + Some(&(_, ItemType::Trait)) => Some(self.stack[..self.stack.len() - 1]), // The current stack not necessarily has correlation for // where the type was defined. On the other hand, // `paths` always has the right information if present. - Some(&(ref fqp, item_type::Struct)) | - Some(&(ref fqp, item_type::Enum)) => + Some(&(ref fqp, ItemType::Struct)) | + Some(&(ref fqp, ItemType::Enum)) => Some(fqp[..fqp.len() - 1]), Some(..) => Some(self.stack.as_slice()), None => None @@ -929,7 +922,7 @@ impl DocFolder for Cache { clean::VariantItem(..) if !self.privmod => { let mut stack = self.stack.clone(); stack.pop(); - self.paths.insert(item.def_id, (stack, item_type::Enum)); + self.paths.insert(item.def_id, (stack, ItemType::Enum)); } clean::PrimitiveItem(..) if item.visibility.is_some() => { @@ -1251,6 +1244,10 @@ impl Context { for item in m.items.iter() { if self.ignore_private_item(item) { continue } + // avoid putting foreign items to the sidebar. + if let &clean::ForeignFunctionItem(..) = &item.inner { continue } + if let &clean::ForeignStaticItem(..) = &item.inner { continue } + let short = shortty(item).to_static_str(); let myname = match item.name { None => continue, @@ -1435,7 +1432,8 @@ impl<'a> fmt::Show for Item<'a> { clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t), clean::MacroItem(ref m) => item_macro(fmt, self.item, m), clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p), - clean::StaticItem(ref i) => item_static(fmt, self.item, i), + clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => + item_static(fmt, self.item, i), clean::ConstantItem(ref c) => item_constant(fmt, self.item, c), _ => Ok(()) } @@ -1490,45 +1488,48 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, !cx.ignore_private_item(&items[*i]) }).collect::<Vec<uint>>(); + // the order of item types in the listing + fn reorder(ty: ItemType) -> u8 { + match ty { + ItemType::ViewItem => 0, + ItemType::Primitive => 1, + ItemType::Module => 2, + ItemType::Macro => 3, + ItemType::Struct => 4, + ItemType::Enum => 5, + ItemType::Constant => 6, + ItemType::Static => 7, + ItemType::Trait => 8, + ItemType::Function => 9, + ItemType::Typedef => 10, + _ => 11 + ty as u8, + } + } + fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering { - if shortty(i1) == shortty(i2) { + let ty1 = shortty(i1); + let ty2 = shortty(i2); + if ty1 == ty2 { return i1.name.cmp(&i2.name); } - match (&i1.inner, &i2.inner) { - (&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => { - match (&a.inner, &b.inner) { - (&clean::ExternCrate(..), _) => Less, - (_, &clean::ExternCrate(..)) => Greater, - _ => idx1.cmp(&idx2), + + let tycmp = reorder(ty1).cmp(&reorder(ty2)); + if let Equal = tycmp { + // for reexports, `extern crate` takes precedence. + match (&i1.inner, &i2.inner) { + (&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => { + match (&a.inner, &b.inner) { + (&clean::ExternCrate(..), _) => return Less, + (_, &clean::ExternCrate(..)) => return Greater, + _ => {} + } } + (_, _) => {} } - (&clean::ViewItemItem(..), _) => Less, - (_, &clean::ViewItemItem(..)) => Greater, - (&clean::PrimitiveItem(..), _) => Less, - (_, &clean::PrimitiveItem(..)) => Greater, - (&clean::ModuleItem(..), _) => Less, - (_, &clean::ModuleItem(..)) => Greater, - (&clean::MacroItem(..), _) => Less, - (_, &clean::MacroItem(..)) => Greater, - (&clean::StructItem(..), _) => Less, - (_, &clean::StructItem(..)) => Greater, - (&clean::EnumItem(..), _) => Less, - (_, &clean::EnumItem(..)) => Greater, - (&clean::ConstantItem(..), _) => Less, - (_, &clean::ConstantItem(..)) => Greater, - (&clean::StaticItem(..), _) => Less, - (_, &clean::StaticItem(..)) => Greater, - (&clean::ForeignFunctionItem(..), _) => Less, - (_, &clean::ForeignFunctionItem(..)) => Greater, - (&clean::ForeignStaticItem(..), _) => Less, - (_, &clean::ForeignStaticItem(..)) => Greater, - (&clean::TraitItem(..), _) => Less, - (_, &clean::TraitItem(..)) => Greater, - (&clean::FunctionItem(..), _) => Less, - (_, &clean::FunctionItem(..)) => Greater, - (&clean::TypedefItem(..), _) => Less, - (_, &clean::TypedefItem(..)) => Greater, - _ => idx1.cmp(&idx2), + + idx1.cmp(&idx2) + } else { + tycmp } } @@ -1545,26 +1546,24 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, try!(write!(w, "</table>")); } curty = myty; - let (short, name) = match myitem.inner { - clean::ModuleItem(..) => ("modules", "Modules"), - clean::StructItem(..) => ("structs", "Structs"), - clean::EnumItem(..) => ("enums", "Enums"), - clean::FunctionItem(..) => ("functions", "Functions"), - clean::TypedefItem(..) => ("types", "Type Definitions"), - clean::StaticItem(..) => ("statics", "Statics"), - clean::ConstantItem(..) => ("constants", "Constants"), - clean::TraitItem(..) => ("traits", "Traits"), - clean::ImplItem(..) => ("impls", "Implementations"), - clean::ViewItemItem(..) => ("reexports", "Reexports"), - clean::TyMethodItem(..) => ("tymethods", "Type Methods"), - clean::MethodItem(..) => ("methods", "Methods"), - clean::StructFieldItem(..) => ("fields", "Struct Fields"), - clean::VariantItem(..) => ("variants", "Variants"), - clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"), - clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"), - clean::MacroItem(..) => ("macros", "Macros"), - clean::PrimitiveItem(..) => ("primitives", "Primitive Types"), - clean::AssociatedTypeItem(..) => ("associated-types", "Associated Types"), + let (short, name) = match myty.unwrap() { + ItemType::Module => ("modules", "Modules"), + ItemType::Struct => ("structs", "Structs"), + ItemType::Enum => ("enums", "Enums"), + ItemType::Function => ("functions", "Functions"), + ItemType::Typedef => ("types", "Type Definitions"), + ItemType::Static => ("statics", "Statics"), + ItemType::Constant => ("constants", "Constants"), + ItemType::Trait => ("traits", "Traits"), + ItemType::Impl => ("impls", "Implementations"), + ItemType::ViewItem => ("reexports", "Reexports"), + ItemType::TyMethod => ("tymethods", "Type Methods"), + ItemType::Method => ("methods", "Methods"), + ItemType::StructField => ("fields", "Struct Fields"), + ItemType::Variant => ("variants", "Variants"), + ItemType::Macro => ("macros", "Macros"), + ItemType::Primitive => ("primitives", "Primitive Types"), + ItemType::AssociatedType => ("associated-types", "Associated Types"), }; try!(write!(w, "<h2 id='{id}' class='section-header'>\ diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 7c6f7ed3fe2..978af31cdc6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -313,7 +313,8 @@ for (var i = results.length - 1; i > 0; i -= 1) { if (results[i].word === results[i - 1].word && results[i].item.ty === results[i - 1].item.ty && - results[i].item.path === results[i - 1].item.path) + results[i].item.path === results[i - 1].item.path && + (results[i].item.parent || {}).name === (results[i - 1].item.parent || {}).name) { results[i].id = -1; } @@ -566,8 +567,8 @@ "method", "structfield", "variant", - "ffi", - "ffs", + "ffi", // retained for backward compatibility + "ffs", // retained for backward compatibility "macro", "primitive", "associatedtype", @@ -707,8 +708,8 @@ var code = $('<code>').append(structs[j]); $.each(code.find('a'), function(idx, a) { var href = $(a).attr('href'); - if (!href.startsWith('http')) { - $(a).attr('href', rootPath + $(a).attr('href')); + if (href && !href.startsWith('http')) { + $(a).attr('href', rootPath + href); } }); var li = $('<li>').append(code); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cc946a6ca4a..66108bea988 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,6 +12,10 @@ #![experimental] #![crate_type = "dylib"] #![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/", + html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] #![feature(globs, if_let, macro_rules, phase, slicing_syntax, tuple_indexing)] @@ -21,6 +25,7 @@ extern crate getopts; extern crate libc; extern crate rustc; extern crate rustc_trans; +extern crate rustc_driver; extern crate serialize; extern crate syntax; extern crate "test" as testing; @@ -163,7 +168,7 @@ pub fn main_args(args: &[String]) -> int { usage(args[0].as_slice()); return 0; } else if matches.opt_present("version") { - match rustc_trans::driver::version("rustdoc", &matches) { + match rustc_driver::version("rustdoc", &matches) { Some(err) => { println!("{}", err); return 1 diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 2a5972bb3d9..7ca7ae4b211 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -19,7 +19,7 @@ use std::string::String; use std::collections::{HashSet, HashMap}; use testing; use rustc::session::{mod, config}; -use rustc_trans::driver::driver; +use rustc_driver::driver; use syntax::ast; use syntax::codemap::{CodeMap, dummy_spanned}; use syntax::diagnostic; @@ -42,7 +42,7 @@ pub fn run(input: &str, crate_name: Option<String>) -> int { let input_path = Path::new(input); - let input = driver::FileInput(input_path.clone()); + let input = config::Input::File(input_path.clone()); let sessopts = config::Options { maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()), @@ -110,7 +110,7 @@ fn runtest(test: &str, cratename: &str, libs: Vec<Path>, externs: core::Externs, // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = maketest(test, Some(cratename), true, as_test_harness); - let input = driver::StrInput(test.to_string()); + let input = config::Input::Str(test.to_string()); let sessopts = config::Options { maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()), diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 403ca9d1432..8fc3c23e88f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -19,7 +19,8 @@ use core::kinds::Sized; use fmt; use iter::IteratorExt; use mem; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use slice::{SlicePrelude, AsSlice}; use str::{Str, StrPrelude}; use string::{String, IntoString}; diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index d8023dd3e4e..8a90c06f038 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -149,9 +149,9 @@ macro_rules! bitflags { #[inline] pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { if (bits & !$BitFlags::all().bits()) != 0 { - ::std::option::None + ::std::option::Option::None } else { - ::std::option::Some($BitFlags { bits: bits }) + ::std::option::Option::Some($BitFlags { bits: bits }) } } @@ -261,7 +261,7 @@ macro_rules! bitflags { #[allow(non_upper_case_globals)] mod tests { use hash; - use option::{Some, None}; + use option::Option::{Some, None}; use ops::{BitOr, BitAnd, BitXor, Sub, Not}; bitflags! { diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index 1f94d7b4fa6..f89876f7245 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -38,7 +38,8 @@ use kinds::Send; use mem; use ops::Drop; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use ptr::RawPtr; use ptr; use raw; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index cf09c93f917..8f879bd50d0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -25,8 +25,10 @@ use kinds::Sized; use mem::{mod, replace}; use num::{Int, UnsignedInt}; use ops::{Deref, Index, IndexMut}; -use option::{Some, None, Option}; -use result::{Result, Ok, Err}; +use option::Option; +use option::Option::{Some, None}; +use result::Result; +use result::Result::{Ok, Err}; use super::table; use super::table::{ diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b40622171d5..fd32d207e79 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -19,8 +19,8 @@ use fmt; use hash::{Hash, Hasher, RandomSipHasher}; use iter::{Iterator, IteratorExt, FromIterator, FilterMap, Chain, Repeat, Zip, Extend, repeat}; use iter; -use option::{Some, None}; -use result::{Ok, Err}; +use option::Option::{Some, None}; +use result::Result::{Ok, Err}; use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index f41ccea0aaf..de06a1e0bbd 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -21,7 +21,8 @@ use mem::{min_align_of, size_of}; use mem; use num::{Int, UnsignedInt}; use ops::{Deref, DerefMut, Drop}; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; diff --git a/src/libstd/collections/lru_cache.rs b/src/libstd/collections/lru_cache.rs index 94bea37d187..adbc135364b 100644 --- a/src/libstd/collections/lru_cache.rs +++ b/src/libstd/collections/lru_cache.rs @@ -44,10 +44,11 @@ use hash::Hash; use iter::{range, Iterator, Extend}; use mem; use ops::Drop; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; use boxed::Box; use ptr; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; // FIXME(conventions): implement iterators? // FIXME(conventions): implement indexing? diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 2b66e91c00d..d291ed72567 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -354,6 +354,8 @@ mod select; mod shared; mod stream; mod sync; +mod mpsc_queue; +mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by /// one task @@ -628,24 +630,26 @@ impl<T: Send> Sender<T> { #[unstable] impl<T: Send> Clone for Sender<T> { fn clone(&self) -> Sender<T> { - let (packet, sleeper) = match *unsafe { self.inner() } { + let (packet, sleeper, guard) = match *unsafe { self.inner() } { Oneshot(ref p) => { let a = Arc::new(UnsafeCell::new(shared::Packet::new())); unsafe { - (*a.get()).postinit_lock(); + let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { - oneshot::UpSuccess | oneshot::UpDisconnected => (a, None), - oneshot::UpWoke(task) => (a, Some(task)) + oneshot::UpSuccess | + oneshot::UpDisconnected => (a, None, guard), + oneshot::UpWoke(task) => (a, Some(task), guard) } } } Stream(ref p) => { let a = Arc::new(UnsafeCell::new(shared::Packet::new())); unsafe { - (*a.get()).postinit_lock(); + let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { - stream::UpSuccess | stream::UpDisconnected => (a, None), - stream::UpWoke(task) => (a, Some(task)), + stream::UpSuccess | + stream::UpDisconnected => (a, None, guard), + stream::UpWoke(task) => (a, Some(task), guard), } } } @@ -657,7 +661,7 @@ impl<T: Send> Clone for Sender<T> { }; unsafe { - (*packet.get()).inherit_blocker(sleeper); + (*packet.get()).inherit_blocker(sleeper, guard); let tmp = Sender::new(Shared(packet.clone())); mem::swap(self.inner_mut(), tmp.inner_mut()); diff --git a/src/libstd/sync/mpsc_queue.rs b/src/libstd/comm/mpsc_queue.rs index 09212e4dfb6..d4249abc3dd 100644 --- a/src/libstd/sync/mpsc_queue.rs +++ b/src/libstd/comm/mpsc_queue.rs @@ -132,15 +132,6 @@ impl<T: Send> Queue<T> { if self.head.load(Acquire) == tail {Empty} else {Inconsistent} } } - - /// Attempts to pop data from this queue, but doesn't attempt too hard. This - /// will canonicalize inconsistent states to a `None` value. - pub fn casual_pop(&self) -> Option<T> { - match self.pop() { - Data(t) => Some(t), - Empty | Inconsistent => None, - } - } } #[unsafe_destructor] diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 6396edbdbd1..13b5e10fcd3 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -26,12 +26,11 @@ use alloc::boxed::Box; use core::cmp; use core::int; use rustrt::local::Local; -use rustrt::mutex::NativeMutex; use rustrt::task::{Task, BlockedTask}; use rustrt::thread::Thread; -use sync::atomic; -use sync::mpsc_queue as mpsc; +use sync::{atomic, Mutex, MutexGuard}; +use comm::mpsc_queue as mpsc; const DISCONNECTED: int = int::MIN; const FUDGE: int = 1024; @@ -56,7 +55,7 @@ pub struct Packet<T> { // this lock protects various portions of this implementation during // select() - select_lock: NativeMutex, + select_lock: Mutex<()>, } pub enum Failure { @@ -76,7 +75,7 @@ impl<T: Send> Packet<T> { channels: atomic::AtomicInt::new(2), port_dropped: atomic::AtomicBool::new(false), sender_drain: atomic::AtomicInt::new(0), - select_lock: unsafe { NativeMutex::new() }, + select_lock: Mutex::new(()), }; return p; } @@ -86,8 +85,8 @@ impl<T: Send> Packet<T> { // In other case mutex data will be duplicated while cloning // and that could cause problems on platforms where it is // represented by opaque data structure - pub fn postinit_lock(&mut self) { - unsafe { self.select_lock.lock_noguard() } + pub fn postinit_lock(&self) -> MutexGuard<()> { + self.select_lock.lock() } // This function is used at the creation of a shared packet to inherit a @@ -95,7 +94,9 @@ impl<T: Send> Packet<T> { // tasks in select(). // // This can only be called at channel-creation time - pub fn inherit_blocker(&mut self, task: Option<BlockedTask>) { + pub fn inherit_blocker(&mut self, + task: Option<BlockedTask>, + guard: MutexGuard<()>) { match task { Some(task) => { assert_eq!(self.cnt.load(atomic::SeqCst), 0); @@ -135,7 +136,7 @@ impl<T: Send> Packet<T> { // interfere with this method. After we unlock this lock, we're // signifying that we're done modifying self.cnt and self.to_wake and // the port is ready for the world to continue using it. - unsafe { self.select_lock.unlock_noguard() } + drop(guard); } pub fn send(&mut self, t: T) -> Result<(), T> { @@ -441,7 +442,7 @@ impl<T: Send> Packet<T> { // done with. Without this bounce, we can race with inherit_blocker // about looking at and dealing with to_wake. Once we have acquired the // lock, we are guaranteed that inherit_blocker is done. - unsafe { + { let _guard = self.select_lock.lock(); } diff --git a/src/libstd/sync/spsc_queue.rs b/src/libstd/comm/spsc_queue.rs index f0eabe61737..a6b4ab71bac 100644 --- a/src/libstd/sync/spsc_queue.rs +++ b/src/libstd/comm/spsc_queue.rs @@ -40,7 +40,6 @@ use core::prelude::*; use alloc::boxed::Box; use core::mem; use core::cell::UnsafeCell; -use alloc::arc::Arc; use sync::atomic::{AtomicPtr, Relaxed, AtomicUint, Acquire, Release}; @@ -74,39 +73,6 @@ pub struct Queue<T> { cache_subtractions: AtomicUint, } -/// A safe abstraction for the consumer in a single-producer single-consumer -/// queue. -pub struct Consumer<T> { - inner: Arc<Queue<T>> -} - -impl<T: Send> Consumer<T> { - /// Attempts to pop the value from the head of the queue, returning `None` - /// if the queue is empty. - pub fn pop(&mut self) -> Option<T> { - self.inner.pop() - } - - /// Attempts to peek at the head of the queue, returning `None` if the queue - /// is empty. - pub fn peek<'a>(&'a mut self) -> Option<&'a mut T> { - self.inner.peek() - } -} - -/// A safe abstraction for the producer in a single-producer single-consumer -/// queue. -pub struct Producer<T> { - inner: Arc<Queue<T>> -} - -impl<T: Send> Producer<T> { - /// Pushes a new value onto the queue. - pub fn push(&mut self, t: T) { - self.inner.push(t) - } -} - impl<T: Send> Node<T> { fn new() -> *mut Node<T> { unsafe { @@ -118,30 +84,6 @@ impl<T: Send> Node<T> { } } -/// Creates a new queue with a consumer-producer pair. -/// -/// The producer returned is connected to the consumer to push all data to -/// the consumer. -/// -/// # Arguments -/// -/// * `bound` - This queue implementation is implemented with a linked -/// list, and this means that a push is always a malloc. In -/// order to amortize this cost, an internal cache of nodes is -/// maintained to prevent a malloc from always being -/// necessary. This bound is the limit on the size of the -/// cache (if desired). If the value is 0, then the cache has -/// no bound. Otherwise, the cache will never grow larger than -/// `bound` (although the queue itself could be much larger. -pub fn queue<T: Send>(bound: uint) -> (Consumer<T>, Producer<T>) { - let q = unsafe { Queue::new(bound) }; - let arc = Arc::new(q); - let consumer = Consumer { inner: arc.clone() }; - let producer = Producer { inner: arc }; - - (consumer, producer) -} - impl<T: Send> Queue<T> { /// Creates a new queue. /// @@ -296,78 +238,88 @@ impl<T: Send> Drop for Queue<T> { mod test { use prelude::*; - use super::{queue}; + use sync::Arc; + use super::Queue; #[test] fn smoke() { - let (mut consumer, mut producer) = queue(0); - producer.push(1i); - producer.push(2); - assert_eq!(consumer.pop(), Some(1i)); - assert_eq!(consumer.pop(), Some(2)); - assert_eq!(consumer.pop(), None); - producer.push(3); - producer.push(4); - assert_eq!(consumer.pop(), Some(3)); - assert_eq!(consumer.pop(), Some(4)); - assert_eq!(consumer.pop(), None); + unsafe { + let queue = Queue::new(0); + queue.push(1i); + queue.push(2); + assert_eq!(queue.pop(), Some(1i)); + assert_eq!(queue.pop(), Some(2)); + assert_eq!(queue.pop(), None); + queue.push(3); + queue.push(4); + assert_eq!(queue.pop(), Some(3)); + assert_eq!(queue.pop(), Some(4)); + assert_eq!(queue.pop(), None); + } } #[test] fn peek() { - let (mut consumer, mut producer) = queue(0); - producer.push(vec![1i]); + unsafe { + let queue = Queue::new(0); + queue.push(vec![1i]); + + // Ensure the borrowchecker works + match queue.peek() { + Some(vec) => match vec.as_slice() { + // Note that `pop` is not allowed here due to borrow + [1] => {} + _ => return + }, + None => unreachable!() + } - // Ensure the borrowchecker works - match consumer.peek() { - Some(vec) => match vec.as_slice() { - // Note that `pop` is not allowed here due to borrow - [1] => {} - _ => return - }, - None => unreachable!() + queue.pop(); } - - consumer.pop(); } #[test] fn drop_full() { - let (_, mut producer) = queue(0); - producer.push(box 1i); - producer.push(box 2i); + unsafe { + let q = Queue::new(0); + q.push(box 1i); + q.push(box 2i); + } } #[test] fn smoke_bound() { - let (mut consumer, mut producer) = queue(1); - producer.push(1i); - producer.push(2); - assert_eq!(consumer.pop(), Some(1)); - assert_eq!(consumer.pop(), Some(2)); - assert_eq!(consumer.pop(), None); - producer.push(3); - producer.push(4); - assert_eq!(consumer.pop(), Some(3)); - assert_eq!(consumer.pop(), Some(4)); - assert_eq!(consumer.pop(), None); + unsafe { + let q = Queue::new(0); + q.push(1i); + q.push(2); + assert_eq!(q.pop(), Some(1)); + assert_eq!(q.pop(), Some(2)); + assert_eq!(q.pop(), None); + q.push(3); + q.push(4); + assert_eq!(q.pop(), Some(3)); + assert_eq!(q.pop(), Some(4)); + assert_eq!(q.pop(), None); + } } #[test] fn stress() { - stress_bound(0); - stress_bound(1); + unsafe { + stress_bound(0); + stress_bound(1); + } - fn stress_bound(bound: uint) { - let (consumer, mut producer) = queue(bound); + unsafe fn stress_bound(bound: uint) { + let q = Arc::new(Queue::new(bound)); let (tx, rx) = channel(); + let q2 = q.clone(); spawn(proc() { - // Move the consumer to a local mutable slot - let mut consumer = consumer; for _ in range(0u, 100000) { loop { - match consumer.pop() { + match q2.pop() { Some(1i) => break, Some(_) => panic!(), None => {} @@ -377,7 +329,7 @@ mod test { tx.send(()); }); for _ in range(0i, 100000) { - producer.push(1); + q.push(1); } rx.recv(); } diff --git a/src/libstd/comm/stream.rs b/src/libstd/comm/stream.rs index 23d042960b1..06ab4f4427a 100644 --- a/src/libstd/comm/stream.rs +++ b/src/libstd/comm/stream.rs @@ -32,7 +32,7 @@ use rustrt::task::{Task, BlockedTask}; use rustrt::thread::Thread; use sync::atomic; -use sync::spsc_queue as spsc; +use comm::spsc_queue as spsc; use comm::Receiver; const DISCONNECTED: int = int::MIN; diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index 3cd0c0eeaf2..aa0c8b53c2e 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -225,8 +225,8 @@ pub mod dl { } pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, String> { - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; + use sync::{StaticMutex, MUTEX_INIT}; + static LOCK: StaticMutex = MUTEX_INIT; unsafe { // dlerror isn't thread safe, so we need to lock around this entire // sequence @@ -280,7 +280,8 @@ pub mod dl { use libc; use os; use ptr; - use result::{Ok, Err, Result}; + use result::Result; + use result::Result::{Ok, Err}; use slice::SlicePrelude; use str::StrPrelude; use str; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 82ad893f88a..9ad2655f6e9 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -78,7 +78,8 @@ //! } //! ``` -use option::{Option, None}; +use option::Option; +use option::Option::None; use kinds::Send; use string::String; diff --git a/src/libstd/failure.rs b/src/libstd/failure.rs index d839c1484e5..58a41f4d7d5 100644 --- a/src/libstd/failure.rs +++ b/src/libstd/failure.rs @@ -16,8 +16,9 @@ use cell::RefCell; use fmt; use io::{Writer, IoResult}; use kinds::Send; -use option::{Some, None, Option}; -use result::Ok; +use option::Option; +use option::Option::{Some, None}; +use result::Result::Ok; use rt::backtrace; use rustrt::{Stderr, Stdio}; use rustrt::local::Local; diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index 7e1bfd704a9..6a2047d1cef 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -406,7 +406,7 @@ use io::Writer; use io; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use string; use vec::Vec; diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index fba9e4f2e25..0b2c6843c96 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -16,8 +16,9 @@ use cmp; use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; use iter::ExactSizeIterator; use ops::Drop; -use option::{Some, None, Option}; -use result::{Ok, Err}; +use option::Option; +use option::Option::{Some, None}; +use result::Result::{Ok, Err}; use slice::{SlicePrelude}; use slice; use vec::Vec; diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index a90b6bbbb8e..3de0a7be95e 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -12,8 +12,8 @@ use clone::Clone; use cmp; use comm::{Sender, Receiver}; use io; -use option::{None, Some}; -use result::{Ok, Err}; +use option::Option::{None, Some}; +use result::Result::{Ok, Err}; use slice::{bytes, CloneSliceAllocPrelude, SlicePrelude}; use super::{Buffer, Reader, Writer, IoResult}; use vec::Vec; diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index 4b2ffb4d559..1bdf99f6d6d 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -19,9 +19,10 @@ use io::{IoError, IoResult, Reader}; use io; use iter::Iterator; use num::Int; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use ptr::RawPtr; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use slice::{SlicePrelude, AsSlice}; /// An iterator that reads a single byte on each iteration, diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index fd6b57d096a..86b2dc4d940 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -53,15 +53,17 @@ use clone::Clone; use io::standard_error; use io::{FilePermission, Write, Open, FileAccess, FileMode, FileType}; -use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; +use io::{IoResult, IoError, InvalidInput}; +use io::{FileStat, SeekStyle, Seek, Writer, Reader}; use io::{Read, Truncate, ReadWrite, Append}; use io::UpdateIoError; use io; use iter::{Iterator, Extend}; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; use path::{Path, GenericPath}; use path; -use result::{Err, Ok}; +use result::Result::{Err, Ok}; use slice::SlicePrelude; use string::String; use vec::Vec; @@ -134,13 +136,26 @@ impl File { pub fn open_mode(path: &Path, mode: FileMode, access: FileAccess) -> IoResult<File> { - fs_imp::open(path, mode, access).map(|fd| { - File { - path: path.clone(), - fd: fd, - last_nread: -1 + fs_imp::open(path, mode, access).and_then(|fd| { + // On *BSD systems, we can open a directory as a file and read from it: + // fd=open("/tmp", O_RDONLY); read(fd, buf, N); + // due to an old tradition before the introduction of opendir(3). + // We explicitly reject it because there are few use cases. + if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) && + try!(fd.fstat()).kind == FileType::Directory { + Err(IoError { + kind: InvalidInput, + desc: "is a directory", + detail: None + }) + } else { + Ok(File { + path: path.clone(), + fd: fd, + last_nread: -1 + }) } - }).update_err("couldn't open file", |e| { + }).update_err("couldn't open path as file", |e| { format!("{}; path={}; mode={}; access={}", e, path.display(), mode_string(mode), access_string(access)) }) @@ -237,7 +252,7 @@ impl File { } /// Queries information about the underlying file. - pub fn stat(&mut self) -> IoResult<FileStat> { + pub fn stat(&self) -> IoResult<FileStat> { self.fd.fstat() .update_err("couldn't fstat file", |e| format!("{}; path={}", e, self.path.display())) @@ -886,7 +901,7 @@ mod test { let filename = &tmpdir.join("file_that_does_not_exist.txt"); let result = File::open_mode(filename, Open, Read); - error!(result, "couldn't open file"); + error!(result, "couldn't open path as file"); if cfg!(unix) { error!(result, "no such file or directory"); } diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 6a9b10d2a7b..43e02d62b0b 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -15,8 +15,8 @@ #![allow(deprecated)] use cmp::min; -use option::None; -use result::{Err, Ok}; +use option::Option::None; +use result::Result::{Err, Ok}; use io; use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; use slice::{mod, AsSlice, SlicePrelude}; @@ -278,20 +278,29 @@ impl<'a> BufWriter<'a> { impl<'a> Writer for BufWriter<'a> { #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - // return an error if the entire write does not fit in the buffer - let cap = if self.pos >= self.buf.len() { 0 } else { self.buf.len() - self.pos }; - if buf.len() > cap { - return Err(IoError { - kind: io::OtherIoError, - desc: "Trying to write past end of buffer", - detail: None - }) + fn write(&mut self, src: &[u8]) -> IoResult<()> { + let dst = self.buf[mut self.pos..]; + let dst_len = dst.len(); + + if dst_len == 0 { + return Err(io::standard_error(io::EndOfFile)); } - slice::bytes::copy_memory(self.buf[mut self.pos..], buf); - self.pos += buf.len(); - Ok(()) + let src_len = src.len(); + + if dst_len >= src_len { + slice::bytes::copy_memory(dst, src); + + self.pos += src_len; + + Ok(()) + } else { + slice::bytes::copy_memory(dst, src[..dst_len]); + + self.pos += dst_len; + + Err(io::standard_error(io::ShortWrite(dst_len))) + } } } @@ -302,7 +311,7 @@ impl<'a> Seek for BufWriter<'a> { #[inline] fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { let new = try!(combine(style, self.pos, self.buf.len(), pos)); - self.pos = new as uint; + self.pos = min(new as uint, self.buf.len()); Ok(()) } } @@ -315,10 +324,10 @@ impl<'a> Seek for BufWriter<'a> { /// # #![allow(unused_must_use)] /// use std::io::BufReader; /// -/// let mut buf = [0, 1, 2, 3]; -/// let mut r = BufReader::new(&mut buf); +/// let buf = [0, 1, 2, 3]; +/// let mut r = BufReader::new(&buf); /// -/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2, 3)); +/// assert_eq!(r.read_to_end().unwrap(), vec![0, 1, 2, 3]); /// ``` pub struct BufReader<'a> { buf: &'a [u8], @@ -419,7 +428,7 @@ mod test { #[test] fn test_buf_writer() { - let mut buf = [0 as u8, ..8]; + let mut buf = [0 as u8, ..9]; { let mut writer = BufWriter::new(&mut buf); assert_eq!(writer.tell(), Ok(0)); @@ -431,9 +440,10 @@ mod test { writer.write(&[]).unwrap(); assert_eq!(writer.tell(), Ok(8)); - assert!(writer.write(&[1]).is_err()); + assert_eq!(writer.write(&[8, 9]).unwrap_err().kind, io::ShortWrite(1)); + assert_eq!(writer.write(&[10]).unwrap_err().kind, io::EndOfFile); } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; assert_eq!(buf.as_slice(), b); } @@ -474,7 +484,7 @@ mod test { match writer.write(&[0, 0]) { Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, io::OtherIoError), + Err(e) => assert_eq!(e.kind, io::ShortWrite(1)), } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 5ed10eab15b..e0857fd27ff 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -32,7 +32,7 @@ //! ```rust //! use std::io; //! -//! for line in io::stdin().lines() { +//! for line in io::stdin().lock().lines() { //! print!("{}", line.unwrap()); //! } //! ``` @@ -233,10 +233,12 @@ use int; use iter::{Iterator, IteratorExt}; use mem::transmute; use ops::{BitOr, BitXor, BitAnd, Sub, Not}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use os; use boxed::Box; -use result::{Ok, Err, Result}; +use result::Result; +use result::Result::{Ok, Err}; use sys; use slice::{AsSlice, SlicePrelude}; use str::{Str, StrPrelude}; @@ -1413,10 +1415,10 @@ pub trait Buffer: Reader { /// # Example /// /// ```rust - /// use std::io; + /// use std::io::BufReader; /// - /// let mut reader = io::stdin(); - /// let input = reader.read_line().ok().unwrap_or("nothing".to_string()); + /// let mut reader = BufReader::new(b"hello\nworld"); + /// assert_eq!("hello\n", &*reader.read_line().unwrap()); /// ``` /// /// # Error diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index 7de78692130..fea8372733c 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -22,7 +22,8 @@ pub use self::Protocol::*; use iter::IteratorExt; use io::{IoResult}; use io::net::ip::{SocketAddr, IpAddr}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use sys; use vec::Vec; diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs index 4812e911cc4..9c0fbbe274b 100644 --- a/src/libstd/io/net/ip.rs +++ b/src/libstd/io/net/ip.rs @@ -21,8 +21,9 @@ use fmt; use io::{mod, IoResult, IoError}; use io::net; use iter::{Iterator, IteratorExt}; -use option::{Option, None, Some}; -use result::{Ok, Err}; +use option::Option; +use option::Option::{None, Some}; +use result::Result::{Ok, Err}; use str::{FromStr, StrPrelude}; use slice::{CloneSlicePrelude, SlicePrelude}; use vec::Vec; diff --git a/src/libstd/io/net/mod.rs b/src/libstd/io/net/mod.rs index 5b1747876d7..09e5639bea9 100644 --- a/src/libstd/io/net/mod.rs +++ b/src/libstd/io/net/mod.rs @@ -11,8 +11,8 @@ //! Networking I/O use io::{IoError, IoResult, InvalidInput}; -use option::None; -use result::{Ok, Err}; +use option::Option::None; +use result::Result::{Ok, Err}; use self::ip::{SocketAddr, ToSocketAddr}; pub use self::addrinfo::get_host_addresses; diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index aa223417591..a7b1b077eff 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -19,11 +19,12 @@ use clone::Clone; use io::IoResult; -use result::Err; +use result::Result::Err; use io::net::ip::{SocketAddr, ToSocketAddr}; use io::{Reader, Writer, Listener, Acceptor}; use io::{standard_error, TimedOut}; -use option::{None, Some, Option}; +use option::Option; +use option::Option::{None, Some}; use time::Duration; use sys::tcp::TcpStream as TcpStreamImp; diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index a7239ca0f2f..a2ad365dd2a 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -19,7 +19,7 @@ use clone::Clone; use io::net::ip::{SocketAddr, IpAddr, ToSocketAddr}; use io::{Reader, Writer, IoResult}; use option::Option; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use sys::udp::UdpSocket as UdpSocketImp; use sys_common; diff --git a/src/libstd/io/result.rs b/src/libstd/io/result.rs index 305bcf9ecbc..32965d23971 100644 --- a/src/libstd/io/result.rs +++ b/src/libstd/io/result.rs @@ -15,7 +15,7 @@ //! as a `Reader` without unwrapping the result first. use clone::Clone; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; impl<W: Writer> Writer for IoResult<W> { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 665000eae88..cf2df0da7fe 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -29,22 +29,28 @@ use self::StdSource::*; use boxed::Box; use cell::RefCell; +use clone::Clone; use failure::LOCAL_STDERR; use fmt; -use io::{Reader, Writer, IoResult, IoError, OtherIoError, +use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; use kinds::Send; use libc; use mem; -use option::{Option, Some, None}; -use result::{Ok, Err}; +use option::Option; +use option::Option::{Some, None}; +use ops::{Deref, DerefMut}; +use result::Result::{Ok, Err}; use rustrt; use rustrt::local::Local; use rustrt::task::Task; use slice::SlicePrelude; use str::StrPrelude; +use string::String; use sys::{fs, tty}; +use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT}; use uint; +use vec::Vec; // And so begins the tale of acquiring a uv handle to a stdio stream on all // platforms in all situations. Our story begins by splitting the world into two @@ -90,28 +96,135 @@ thread_local!(static LOCAL_STDOUT: RefCell<Option<Box<Writer + Send>>> = { RefCell::new(None) }) -/// Creates a new non-blocking handle to the stdin of the current process. -/// -/// The returned handled is buffered by default with a `BufferedReader`. If -/// buffered access is not desired, the `stdin_raw` function is provided to -/// provided unbuffered access to stdin. +/// A synchronized wrapper around a buffered reader from stdin +#[deriving(Clone)] +pub struct StdinReader { + inner: Arc<Mutex<BufferedReader<StdReader>>>, +} + +/// A guard for exlusive access to `StdinReader`'s internal `BufferedReader`. +pub struct StdinReaderGuard<'a> { + inner: MutexGuard<'a, BufferedReader<StdReader>>, +} + +impl<'a> Deref<BufferedReader<StdReader>> for StdinReaderGuard<'a> { + fn deref(&self) -> &BufferedReader<StdReader> { + &*self.inner + } +} + +impl<'a> DerefMut<BufferedReader<StdReader>> for StdinReaderGuard<'a> { + fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> { + &mut *self.inner + } +} + +impl StdinReader { + /// Locks the `StdinReader`, granting the calling thread exclusive access + /// to the underlying `BufferedReader`. + /// + /// This provides access to methods like `chars` and `lines`. + /// + /// ## Example + /// + /// ```rust + /// use std::io; + /// + /// for line in io::stdin().lock().lines() { + /// println!("{}", line.unwrap()); + /// } + /// ``` + pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> { + StdinReaderGuard { + inner: self.inner.lock() + } + } + + /// Like `Buffer::read_line`. + /// + /// The read is performed atomically - concurrent read calls in other + /// threads will not interleave with this one. + pub fn read_line(&mut self) -> IoResult<String> { + self.inner.lock().read_line() + } + + /// Like `Buffer::read_until`. + /// + /// The read is performed atomically - concurrent read calls in other + /// threads will not interleave with this one. + pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> { + self.inner.lock().read_until(byte) + } + + /// Like `Buffer::read_char`. + /// + /// The read is performed atomically - concurrent read calls in other + /// threads will not interleave with this one. + pub fn read_char(&mut self) -> IoResult<char> { + self.inner.lock().read_char() + } +} + +impl Reader for StdinReader { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + self.inner.lock().read(buf) + } + + // We have to manually delegate all of these because the default impls call + // read more than once and we don't want those calls to interleave (or + // incur the costs of repeated locking). + + fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult<uint> { + self.inner.lock().read_at_least(min, buf) + } + + fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec<u8>) -> IoResult<uint> { + self.inner.lock().push_at_least(min, len, buf) + } + + fn read_to_end(&mut self) -> IoResult<Vec<u8>> { + self.inner.lock().read_to_end() + } + + fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { + self.inner.lock().read_le_uint_n(nbytes) + } + + fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> { + self.inner.lock().read_be_uint_n(nbytes) + } +} + +/// Creates a new handle to the stdin of the current process. /// -/// Care should be taken when creating multiple handles to the stdin of a -/// process. Because this is a buffered reader by default, it's possible for -/// pending input to be unconsumed in one reader and unavailable to other -/// readers. It is recommended that only one handle at a time is created for the -/// stdin of a process. +/// The returned handle is a wrapper around a global `BufferedReader` shared +/// by all threads. If buffered access is not desired, the `stdin_raw` function +/// is provided to provided unbuffered access to stdin. /// /// See `stdout()` for more notes about this function. -pub fn stdin() -> BufferedReader<StdReader> { - // The default buffer capacity is 64k, but apparently windows doesn't like - // 64k reads on stdin. See #13304 for details, but the idea is that on - // windows we use a slightly smaller buffer that's been seen to be - // acceptable. - if cfg!(windows) { - BufferedReader::with_capacity(8 * 1024, stdin_raw()) - } else { - BufferedReader::new(stdin_raw()) +pub fn stdin() -> StdinReader { + // We're following the same strategy as kimundi's lazy_static library + static mut STDIN: *const StdinReader = 0 as *const StdinReader; + static ONCE: Once = ONCE_INIT; + + unsafe { + ONCE.doit(|| { + // The default buffer capacity is 64k, but apparently windows doesn't like + // 64k reads on stdin. See #13304 for details, but the idea is that on + // windows we use a slightly smaller buffer that's been seen to be + // acceptable. + let stdin = if cfg!(windows) { + BufferedReader::with_capacity(8 * 1024, stdin_raw()) + } else { + BufferedReader::new(stdin_raw()) + }; + let stdin = StdinReader { + inner: Arc::new(Mutex::new(stdin)) + }; + STDIN = mem::transmute(box stdin); + }); + + (*STDIN).clone() } } diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs index 4788ba79b7f..f3a11939995 100644 --- a/src/libstd/io/tempfile.rs +++ b/src/libstd/io/tempfile.rs @@ -14,10 +14,11 @@ use io::{fs, IoResult}; use io; use libc; use ops::Drop; -use option::{Option, None, Some}; +use option::Option; +use option::Option::{None, Some}; use os; use path::{Path, GenericPath}; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use sync::atomic; /// A wrapper for a path to temporary directory implementing automatic diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f6b73f037f2..d4274d7e401 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -106,7 +106,7 @@ #![allow(unknown_features)] #![feature(macro_rules, globs, linkage)] #![feature(default_type_params, phase, lang_items, unsafe_destructor)] -#![feature(import_shadowing, slicing_syntax)] +#![feature(import_shadowing, slicing_syntax, tuple_indexing)] // Don't link to std. We are std. #![no_std] diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0abd030a163..ba9bcc05546 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -40,14 +40,16 @@ use libc::{c_void, c_int}; use libc; use boxed::Box; use ops::Drop; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; use os; use path::{Path, GenericPath, BytesContainer}; use sys; use sys::os as os_imp; use ptr::RawPtr; use ptr; -use result::{Err, Ok, Result}; +use result::Result; +use result::Result::{Err, Ok}; use slice::{AsSlice, SlicePrelude, PartialEqSlicePrelude}; use slice::CloneSliceAllocPrelude; use str::{Str, StrPrelude, StrAllocating}; @@ -160,7 +162,8 @@ pub fn getcwd() -> IoResult<Path> { pub mod windows { use libc::types::os::arch::extra::DWORD; use libc; - use option::{None, Option}; + use option::Option; + use option::Option::None; use option; use os::TMPBUF_SZ; use slice::{SlicePrelude}; @@ -196,7 +199,7 @@ pub mod windows { // set `res` to None and continue. let s = String::from_utf16(sub) .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16"); - res = option::Some(s) + res = option::Option::Some(s) } } return res; @@ -209,14 +212,12 @@ Accessing environment variables is not generally threadsafe. Serialize access through a global lock. */ fn with_env_lock<T>(f: || -> T) -> T { - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use sync::{StaticMutex, MUTEX_INIT}; - static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; + static LOCK: StaticMutex = MUTEX_INIT; - unsafe { - let _guard = LOCK.lock(); - f() - } + let _guard = LOCK.lock(); + f() } /// Returns a vector of (variable, value) pairs, for all the environment @@ -1799,7 +1800,7 @@ mod tests { fn test_setenv() { let n = make_rand_name(); setenv(n.as_slice(), "VALUE"); - assert_eq!(getenv(n.as_slice()), option::Some("VALUE".to_string())); + assert_eq!(getenv(n.as_slice()), option::Option::Some("VALUE".to_string())); } #[test] @@ -1807,7 +1808,7 @@ mod tests { let n = make_rand_name(); setenv(n.as_slice(), "VALUE"); unsetenv(n.as_slice()); - assert_eq!(getenv(n.as_slice()), option::None); + assert_eq!(getenv(n.as_slice()), option::Option::None); } #[test] @@ -1816,9 +1817,9 @@ mod tests { let n = make_rand_name(); setenv(n.as_slice(), "1"); setenv(n.as_slice(), "2"); - assert_eq!(getenv(n.as_slice()), option::Some("2".to_string())); + assert_eq!(getenv(n.as_slice()), option::Option::Some("2".to_string())); setenv(n.as_slice(), ""); - assert_eq!(getenv(n.as_slice()), option::Some("".to_string())); + assert_eq!(getenv(n.as_slice()), option::Option::Some("".to_string())); } // Windows GetEnvironmentVariable requires some extra work to make sure @@ -1835,7 +1836,7 @@ mod tests { let n = make_rand_name(); setenv(n.as_slice(), s.as_slice()); debug!("{}", s.clone()); - assert_eq!(getenv(n.as_slice()), option::Some(s)); + assert_eq!(getenv(n.as_slice()), option::Option::Some(s)); } #[test] @@ -1872,7 +1873,7 @@ mod tests { // MingW seems to set some funky environment variables like // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned // from env() but not visible from getenv(). - assert!(v2.is_none() || v2 == option::Some(v)); + assert!(v2.is_none() || v2 == option::Option::Some(v)); } } @@ -1959,7 +1960,7 @@ mod tests { #[test] fn memory_map_rw() { - use result::{Ok, Err}; + use result::Result::{Ok, Err}; let chunk = match os::MemoryMap::new(16, &[ os::MapReadable, @@ -1978,7 +1979,7 @@ mod tests { #[test] fn memory_map_file() { - use result::{Ok, Err}; + use result::Result::{Ok, Err}; use os::*; use libc::*; use io::fs; diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index b17106e811f..01b42395471 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -66,7 +66,8 @@ use c_str::CString; use clone::Clone; use fmt; use iter::IteratorExt; -use option::{Option, None, Some}; +use option::Option; +use option::Option::{None, Some}; use str; use str::{CowString, MaybeOwned, Str, StrPrelude}; use string::String; diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index f6778588add..d6d27daf4ae 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -17,7 +17,8 @@ use hash; use io::Writer; use iter::{DoubleEndedIteratorExt, AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; -use option::{Option, None, Some}; +use option::Option; +use option::Option::{None, Some}; use kinds::Sized; use str::{FromStr, Str}; use str; diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 13891a63330..08e318d32b9 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -23,7 +23,8 @@ use io::Writer; use iter::{AdditiveIterator, DoubleEndedIteratorExt, Extend}; use iter::{Iterator, IteratorExt, Map}; use mem; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use slice::{AsSlice, SlicePrelude}; use str::{CharSplits, FromStr, Str, StrAllocating, StrVector, StrPrelude}; use string::String; diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index da690f5d154..413d9267152 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -227,7 +227,7 @@ use io::IoResult; use iter::{Iterator, IteratorExt}; use mem; use rc::Rc; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use vec::Vec; #[cfg(not(target_word_size="64"))] diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 2a4d8347c30..37628b65388 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -23,7 +23,7 @@ mod imp { use path::Path; use rand::Rng; use rand::reader::ReaderRng; - use result::{Ok, Err}; + use result::Result::{Ok, Err}; use slice::SlicePrelude; use mem; use os::errno; @@ -173,7 +173,7 @@ mod imp { use mem; use os; use rand::Rng; - use result::{Ok}; + use result::Result::{Ok}; use self::libc::{c_int, size_t}; use slice::{SlicePrelude}; @@ -240,7 +240,7 @@ mod imp { use ops::Drop; use os; use rand::Rng; - use result::{Ok, Err}; + use result::Result::{Ok, Err}; use self::libc::{DWORD, BYTE, LPCSTR, BOOL}; use self::libc::types::os::arch::extra::{LONG_PTR}; use slice::{SlicePrelude}; diff --git a/src/libstd/rand/reader.rs b/src/libstd/rand/reader.rs index 796bf7853f7..ca6322247c2 100644 --- a/src/libstd/rand/reader.rs +++ b/src/libstd/rand/reader.rs @@ -12,7 +12,7 @@ use io::Reader; use rand::Rng; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use slice::SlicePrelude; /// An RNG that reads random bytes straight from a `Reader`. This will diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 0103fe670e7..3698a91855c 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -14,9 +14,9 @@ use io::{IoResult, Writer}; use iter::{Iterator, IteratorExt}; -use option::{Some, None}; +use option::Option::{Some, None}; use os; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use str::{StrPrelude, from_str}; use sync::atomic; use unicode::char::UnicodeChar; @@ -236,9 +236,10 @@ mod imp { use io::{IoResult, Writer}; use libc; use mem; - use option::{Some, None, Option}; - use result::{Ok, Err}; - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use option::Option; + use option::Option::{Some, None}; + use result::Result::{Ok, Err}; + use sync::{StaticMutex, MUTEX_INIT}; /// As always - iOS on arm uses SjLj exceptions and /// _Unwind_Backtrace is even not available there. Still, @@ -264,8 +265,8 @@ mod imp { // while it doesn't requires lock for work as everything is // local, it still displays much nicer backtraces when a // couple of tasks panic simultaneously - static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + static LOCK: StaticMutex = MUTEX_INIT; + let _g = LOCK.lock(); try!(writeln!(w, "stack backtrace:")); // 100 lines should be enough @@ -297,8 +298,8 @@ mod imp { // is semi-reasonable in terms of printing anyway, and we know that all // I/O done here is blocking I/O, not green I/O, so we don't have to // worry about this being a native vs green mutex. - static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + static LOCK: StaticMutex = MUTEX_INIT; + let _g = LOCK.lock(); try!(writeln!(w, "stack backtrace:")); @@ -664,10 +665,10 @@ mod imp { use libc; use mem; use ops::Drop; - use option::{Some, None}; + use option::Option::{Some, None}; use path::Path; - use result::{Ok, Err}; - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use result::Result::{Ok, Err}; + use sync::{StaticMutex, MUTEX_INIT}; use slice::SlicePrelude; use str::StrPrelude; use dynamic_lib::DynamicLibrary; @@ -928,8 +929,8 @@ mod imp { pub fn write(w: &mut Writer) -> IoResult<()> { // According to windows documentation, all dbghelp functions are // single-threaded. - static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + static LOCK: StaticMutex = MUTEX_INIT; + let _g = LOCK.lock(); // Open up dbghelp.dll, we don't link to it explicitly because it can't // always be found. Additionally, it's nice having fewer dependencies. diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 92657d1b59b..ce359c7b0e0 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -9,7 +9,8 @@ // except according to those terms. use libc::uintptr_t; -use option::{Some, None, Option}; +use option::Option; +use option::Option::{Some, None}; use os; use str::{FromStr, from_str, Str}; use sync::atomic; diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs new file mode 100644 index 00000000000..5e6dc6ec650 --- /dev/null +++ b/src/libstd/sync/barrier.rs @@ -0,0 +1,116 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sync::{Mutex, Condvar}; + +/// A barrier enables multiple tasks to synchronize the beginning +/// of some computation. +/// +/// ```rust +/// use std::sync::{Arc, Barrier}; +/// +/// let barrier = Arc::new(Barrier::new(10)); +/// for _ in range(0u, 10) { +/// let c = barrier.clone(); +/// // The same messages will be printed together. +/// // You will NOT see any interleaving. +/// spawn(proc() { +/// println!("before wait"); +/// c.wait(); +/// println!("after wait"); +/// }); +/// } +/// ``` +pub struct Barrier { + lock: Mutex<BarrierState>, + cvar: Condvar, + num_threads: uint, +} + +// The inner state of a double barrier +struct BarrierState { + count: uint, + generation_id: uint, +} + +impl Barrier { + /// Create a new barrier that can block a given number of threads. + /// + /// A barrier will block `n`-1 threads which call `wait` and then wake up + /// all threads at once when the `n`th thread calls `wait`. + pub fn new(n: uint) -> Barrier { + Barrier { + lock: Mutex::new(BarrierState { + count: 0, + generation_id: 0, + }), + cvar: Condvar::new(), + num_threads: n, + } + } + + /// Block the current thread until all threads has rendezvoused here. + /// + /// Barriers are re-usable after all threads have rendezvoused once, and can + /// be used continuously. + pub fn wait(&self) { + let mut lock = self.lock.lock(); + let local_gen = lock.generation_id; + lock.count += 1; + if lock.count < self.num_threads { + // We need a while loop to guard against spurious wakeups. + // http://en.wikipedia.org/wiki/Spurious_wakeup + while local_gen == lock.generation_id && + lock.count < self.num_threads { + self.cvar.wait(&lock); + } + } else { + lock.count = 0; + lock.generation_id += 1; + self.cvar.notify_all(); + } + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + + use sync::{Arc, Barrier}; + use comm::Empty; + + #[test] + fn test_barrier() { + let barrier = Arc::new(Barrier::new(10)); + let (tx, rx) = channel(); + + for _ in range(0u, 9) { + let c = barrier.clone(); + let tx = tx.clone(); + spawn(proc() { + c.wait(); + tx.send(true); + }); + } + + // At this point, all spawned tasks should be blocked, + // so we shouldn't get anything from the port + assert!(match rx.try_recv() { + Err(Empty) => true, + _ => false, + }); + + barrier.wait(); + // Now, the barrier is cleared and we should get data. + for _ in range(0u, 9) { + rx.recv(); + } + } +} diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs new file mode 100644 index 00000000000..0fdd57b2792 --- /dev/null +++ b/src/libstd/sync/condvar.rs @@ -0,0 +1,365 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; + +use sync::atomic::{mod, AtomicUint}; +use sync::{mutex, StaticMutexGuard}; +use sys_common::condvar as sys; +use sys_common::mutex as sys_mutex; +use time::Duration; + +/// A Condition Variable +/// +/// Condition variables represent the ability to block a thread such that it +/// consumes no CPU time while waiting for an event to occur. Condition +/// variables are typically associated with a boolean predicate (a condition) +/// and a mutex. The predicate is always verified inside of the mutex before +/// determining that thread must block. +/// +/// Functions in this module will block the current **thread** of execution and +/// are bindings to system-provided condition variables where possible. Note +/// that this module places one additional restriction over the system condition +/// variables: each condvar can be used with precisely one mutex at runtime. Any +/// attempt to use multiple mutexes on the same condition variable will result +/// in a runtime panic. If this is not desired, then the unsafe primitives in +/// `sys` do not have this restriction but may result in undefined behavior. +/// +/// # Example +/// +/// ``` +/// use std::sync::{Arc, Mutex, Condvar}; +/// +/// let pair = Arc::new((Mutex::new(false), Condvar::new())); +/// let pair2 = pair.clone(); +/// +/// // Inside of our lock, spawn a new thread, and then wait for it to start +/// spawn(proc() { +/// let &(ref lock, ref cvar) = &*pair2; +/// let mut started = lock.lock(); +/// *started = true; +/// cvar.notify_one(); +/// }); +/// +/// // wait for the thread to start up +/// let &(ref lock, ref cvar) = &*pair; +/// let started = lock.lock(); +/// while !*started { +/// cvar.wait(&started); +/// } +/// ``` +pub struct Condvar { inner: Box<StaticCondvar> } + +/// Statically allocated condition variables. +/// +/// This structure is identical to `Condvar` except that it is suitable for use +/// in static initializers for other structures. +/// +/// # Example +/// +/// ``` +/// use std::sync::{StaticCondvar, CONDVAR_INIT}; +/// +/// static CVAR: StaticCondvar = CONDVAR_INIT; +/// ``` +pub struct StaticCondvar { + inner: sys::Condvar, + mutex: AtomicUint, +} + +/// Constant initializer for a statically allocated condition variable. +pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { + inner: sys::CONDVAR_INIT, + mutex: atomic::INIT_ATOMIC_UINT, +}; + +/// A trait for vaules which can be passed to the waiting methods of condition +/// variables. This is implemented by the mutex guards in this module. +/// +/// Note that this trait should likely not be implemented manually unless you +/// really know what you're doing. +pub trait AsMutexGuard { + #[allow(missing_docs)] + unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard; +} + +impl Condvar { + /// Creates a new condition variable which is ready to be waited on and + /// notified. + pub fn new() -> Condvar { + Condvar { + inner: box StaticCondvar { + inner: unsafe { sys::Condvar::new() }, + mutex: AtomicUint::new(0), + } + } + } + + /// Block the current thread until this condition variable receives a + /// notification. + /// + /// This function will atomically unlock the mutex specified (represented by + /// `guard`) and block the current thread. This means that any calls to + /// `notify_*()` which happen logically after the mutex is unlocked are + /// candidates to wake this thread up. When this function call returns, the + /// lock specified will have been re-acquired. + /// + /// Note that this function is susceptible to spurious wakeups. Condition + /// variables normally have a boolean predicate associated with them, and + /// the predicate must always be checked each time this function returns to + /// protect against spurious wakeups. + /// + /// # Panics + /// + /// This function will `panic!()` if it is used with more than one mutex + /// over time. Each condition variable is dynamically bound to exactly one + /// mutex to ensure defined behavior across platforms. If this functionality + /// is not desired, then unsafe primitives in `sys` are provided. + pub fn wait<T: AsMutexGuard>(&self, mutex_guard: &T) { + unsafe { + let me: &'static Condvar = &*(self as *const _); + me.inner.wait(mutex_guard) + } + } + + /// Wait on this condition variable for a notification, timing out after a + /// specified duration. + /// + /// The semantics of this function are equivalent to `wait()` except that + /// the thread will be blocked for roughly no longer than `dur`. This method + /// should not be used for precise timing due to anomalies such as + /// preemption or platform differences that may not cause the maximum amount + /// of time waited to be precisely `dur`. + /// + /// If the wait timed out, then `false` will be returned. Otherwise if a + /// notification was received then `true` will be returned. + /// + /// Like `wait`, the lock specified will be re-acquired when this function + /// returns, regardless of whether the timeout elapsed or not. + // Note that this method is *not* public, and this is quite intentional + // because we're not quite sure about the semantics of relative vs absolute + // durations or how the timing guarantees play into what the system APIs + // provide. There are also additional concerns about the unix-specific + // implementation which may need to be addressed. + #[allow(dead_code)] + fn wait_timeout<T: AsMutexGuard>(&self, mutex_guard: &T, + dur: Duration) -> bool { + unsafe { + let me: &'static Condvar = &*(self as *const _); + me.inner.wait_timeout(mutex_guard, dur) + } + } + + /// Wake up one blocked thread on this condvar. + /// + /// If there is a blocked thread on this condition variable, then it will + /// be woken up from its call to `wait` or `wait_timeout`. Calls to + /// `notify_one` are not buffered in any way. + /// + /// To wake up all threads, see `notify_one()`. + pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } + + /// Wake up all blocked threads on this condvar. + /// + /// This method will ensure that any current waiters on the condition + /// variable are awoken. Calls to `notify_all()` are not buffered in any + /// way. + /// + /// To wake up only one thread, see `notify_one()`. + pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } } +} + +impl Drop for Condvar { + fn drop(&mut self) { + unsafe { self.inner.inner.destroy() } + } +} + +impl StaticCondvar { + /// Block the current thread until this condition variable receives a + /// notification. + /// + /// See `Condvar::wait`. + pub fn wait<T: AsMutexGuard>(&'static self, mutex_guard: &T) { + unsafe { + let lock = mutex_guard.as_mutex_guard(); + let sys = mutex::guard_lock(lock); + self.verify(sys); + self.inner.wait(sys); + (*mutex::guard_poison(lock)).check("mutex"); + } + } + + /// Wait on this condition variable for a notification, timing out after a + /// specified duration. + /// + /// See `Condvar::wait_timeout`. + #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above + fn wait_timeout<T: AsMutexGuard>(&'static self, mutex_guard: &T, + dur: Duration) -> bool { + unsafe { + let lock = mutex_guard.as_mutex_guard(); + let sys = mutex::guard_lock(lock); + self.verify(sys); + let ret = self.inner.wait_timeout(sys, dur); + (*mutex::guard_poison(lock)).check("mutex"); + return ret; + } + } + + /// Wake up one blocked thread on this condvar. + /// + /// See `Condvar::notify_one`. + pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } + + /// Wake up all blocked threads on this condvar. + /// + /// See `Condvar::notify_all`. + pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } + + /// Deallocate all resources associated with this static condvar. + /// + /// This method is unsafe to call as there is no guarantee that there are no + /// active users of the condvar, and this also doesn't prevent any future + /// users of the condvar. This method is required to be called to not leak + /// memory on all platforms. + pub unsafe fn destroy(&'static self) { + self.inner.destroy() + } + + fn verify(&self, mutex: &sys_mutex::Mutex) { + let addr = mutex as *const _ as uint; + match self.mutex.compare_and_swap(0, addr, atomic::SeqCst) { + // If we got out 0, then we have successfully bound the mutex to + // this cvar. + 0 => {} + + // If we get out a value that's the same as `addr`, then someone + // already beat us to the punch. + n if n == addr => {} + + // Anything else and we're using more than one mutex on this cvar, + // which is currently disallowed. + _ => panic!("attempted to use a condition variable with two \ + mutexes"), + } + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + + use time::Duration; + use super::{StaticCondvar, CONDVAR_INIT}; + use sync::{StaticMutex, MUTEX_INIT, Condvar, Mutex, Arc}; + + #[test] + fn smoke() { + let c = Condvar::new(); + c.notify_one(); + c.notify_all(); + } + + #[test] + fn static_smoke() { + static C: StaticCondvar = CONDVAR_INIT; + C.notify_one(); + C.notify_all(); + unsafe { C.destroy(); } + } + + #[test] + fn notify_one() { + static C: StaticCondvar = CONDVAR_INIT; + static M: StaticMutex = MUTEX_INIT; + + let g = M.lock(); + spawn(proc() { + let _g = M.lock(); + C.notify_one(); + }); + C.wait(&g); + drop(g); + unsafe { C.destroy(); M.destroy(); } + } + + #[test] + fn notify_all() { + const N: uint = 10; + + let data = Arc::new((Mutex::new(0), Condvar::new())); + let (tx, rx) = channel(); + for _ in range(0, N) { + let data = data.clone(); + let tx = tx.clone(); + spawn(proc() { + let &(ref lock, ref cond) = &*data; + let mut cnt = lock.lock(); + *cnt += 1; + if *cnt == N { + tx.send(()); + } + while *cnt != 0 { + cond.wait(&cnt); + } + tx.send(()); + }); + } + drop(tx); + + let &(ref lock, ref cond) = &*data; + rx.recv(); + let mut cnt = lock.lock(); + *cnt = 0; + cond.notify_all(); + drop(cnt); + + for _ in range(0, N) { + rx.recv(); + } + } + + #[test] + fn wait_timeout() { + static C: StaticCondvar = CONDVAR_INIT; + static M: StaticMutex = MUTEX_INIT; + + let g = M.lock(); + assert!(!C.wait_timeout(&g, Duration::nanoseconds(1000))); + spawn(proc() { + let _g = M.lock(); + C.notify_one(); + }); + assert!(C.wait_timeout(&g, Duration::days(1))); + drop(g); + unsafe { C.destroy(); M.destroy(); } + } + + #[test] + #[should_fail] + fn two_mutexes() { + static M1: StaticMutex = MUTEX_INIT; + static M2: StaticMutex = MUTEX_INIT; + static C: StaticCondvar = CONDVAR_INIT; + + let g = M1.lock(); + spawn(proc() { + let _g = M1.lock(); + C.notify_one(); + }); + C.wait(&g); + drop(g); + + C.wait(&M2.lock()); + + } +} + diff --git a/src/libstd/sync/deque.rs b/src/libstd/sync/deque.rs deleted file mode 100644 index 33f6f77eb62..00000000000 --- a/src/libstd/sync/deque.rs +++ /dev/null @@ -1,663 +0,0 @@ -// 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A (mostly) lock-free concurrent work-stealing deque -//! -//! This module contains an implementation of the Chase-Lev work stealing deque -//! described in "Dynamic Circular Work-Stealing Deque". The implementation is -//! heavily based on the pseudocode found in the paper. -//! -//! This implementation does not want to have the restriction of a garbage -//! collector for reclamation of buffers, and instead it uses a shared pool of -//! buffers. This shared pool is required for correctness in this -//! implementation. -//! -//! The only lock-synchronized portions of this deque are the buffer allocation -//! and deallocation portions. Otherwise all operations are lock-free. -//! -//! # Example -//! -//! use std::sync::deque::BufferPool; -//! -//! let mut pool = BufferPool::new(); -//! let (mut worker, mut stealer) = pool.deque(); -//! -//! // Only the worker may push/pop -//! worker.push(1i); -//! worker.pop(); -//! -//! // Stealers take data from the other end of the deque -//! worker.push(1i); -//! stealer.steal(); -//! -//! // Stealers can be cloned to have many stealers stealing in parallel -//! worker.push(1i); -//! let mut stealer2 = stealer.clone(); -//! stealer2.steal(); - -#![experimental] - -// NB: the "buffer pool" strategy is not done for speed, but rather for -// correctness. For more info, see the comment on `swap_buffer` - -// FIXME: all atomic operations in this module use a SeqCst ordering. That is -// probably overkill - -pub use self::Stolen::*; - -use core::prelude::*; - -use alloc::arc::Arc; -use alloc::heap::{allocate, deallocate}; -use alloc::boxed::Box; -use vec::Vec; -use core::kinds::marker; -use core::mem::{forget, min_align_of, size_of, transmute}; -use core::ptr; -use rustrt::exclusive::Exclusive; - -use sync::atomic::{AtomicInt, AtomicPtr, SeqCst}; - -// Once the queue is less than 1/K full, then it will be downsized. Note that -// the deque requires that this number be less than 2. -static K: int = 4; - -// Minimum number of bits that a buffer size should be. No buffer will resize to -// under this value, and all deques will initially contain a buffer of this -// size. -// -// The size in question is 1 << MIN_BITS -static MIN_BITS: uint = 7; - -struct Deque<T> { - bottom: AtomicInt, - top: AtomicInt, - array: AtomicPtr<Buffer<T>>, - pool: BufferPool<T>, -} - -/// Worker half of the work-stealing deque. This worker has exclusive access to -/// one side of the deque, and uses `push` and `pop` method to manipulate it. -/// -/// There may only be one worker per deque. -pub struct Worker<T> { - deque: Arc<Deque<T>>, - _noshare: marker::NoSync, -} - -/// The stealing half of the work-stealing deque. Stealers have access to the -/// opposite end of the deque from the worker, and they only have access to the -/// `steal` method. -pub struct Stealer<T> { - deque: Arc<Deque<T>>, - _noshare: marker::NoSync, -} - -/// When stealing some data, this is an enumeration of the possible outcomes. -#[deriving(PartialEq, Show)] -pub enum Stolen<T> { - /// The deque was empty at the time of stealing - Empty, - /// The stealer lost the race for stealing data, and a retry may return more - /// data. - Abort, - /// The stealer has successfully stolen some data. - Data(T), -} - -/// The allocation pool for buffers used by work-stealing deques. Right now this -/// structure is used for reclamation of memory after it is no longer in use by -/// deques. -/// -/// This data structure is protected by a mutex, but it is rarely used. Deques -/// will only use this structure when allocating a new buffer or deallocating a -/// previous one. -pub struct BufferPool<T> { - pool: Arc<Exclusive<Vec<Box<Buffer<T>>>>>, -} - -/// An internal buffer used by the chase-lev deque. This structure is actually -/// implemented as a circular buffer, and is used as the intermediate storage of -/// the data in the deque. -/// -/// This type is implemented with *T instead of Vec<T> for two reasons: -/// -/// 1. There is nothing safe about using this buffer. This easily allows the -/// same value to be read twice in to rust, and there is nothing to -/// prevent this. The usage by the deque must ensure that one of the -/// values is forgotten. Furthermore, we only ever want to manually run -/// destructors for values in this buffer (on drop) because the bounds -/// are defined by the deque it's owned by. -/// -/// 2. We can certainly avoid bounds checks using *T instead of Vec<T>, although -/// LLVM is probably pretty good at doing this already. -struct Buffer<T> { - storage: *const T, - log_size: uint, -} - -impl<T: Send> BufferPool<T> { - /// Allocates a new buffer pool which in turn can be used to allocate new - /// deques. - pub fn new() -> BufferPool<T> { - BufferPool { pool: Arc::new(Exclusive::new(Vec::new())) } - } - - /// Allocates a new work-stealing deque which will send/receiving memory to - /// and from this buffer pool. - pub fn deque(&self) -> (Worker<T>, Stealer<T>) { - let a = Arc::new(Deque::new(self.clone())); - let b = a.clone(); - (Worker { deque: a, _noshare: marker::NoSync }, - Stealer { deque: b, _noshare: marker::NoSync }) - } - - fn alloc(&mut self, bits: uint) -> Box<Buffer<T>> { - unsafe { - let mut pool = self.pool.lock(); - match pool.iter().position(|x| x.size() >= (1 << bits)) { - Some(i) => pool.remove(i).unwrap(), - None => box Buffer::new(bits) - } - } - } - - fn free(&self, buf: Box<Buffer<T>>) { - unsafe { - let mut pool = self.pool.lock(); - match pool.iter().position(|v| v.size() > buf.size()) { - Some(i) => pool.insert(i, buf), - None => pool.push(buf), - } - } - } -} - -impl<T: Send> Clone for BufferPool<T> { - fn clone(&self) -> BufferPool<T> { BufferPool { pool: self.pool.clone() } } -} - -impl<T: Send> Worker<T> { - /// Pushes data onto the front of this work queue. - pub fn push(&self, t: T) { - unsafe { self.deque.push(t) } - } - /// Pops data off the front of the work queue, returning `None` on an empty - /// queue. - pub fn pop(&self) -> Option<T> { - unsafe { self.deque.pop() } - } - - /// Gets access to the buffer pool that this worker is attached to. This can - /// be used to create more deques which share the same buffer pool as this - /// deque. - pub fn pool<'a>(&'a self) -> &'a BufferPool<T> { - &self.deque.pool - } -} - -impl<T: Send> Stealer<T> { - /// Steals work off the end of the queue (opposite of the worker's end) - pub fn steal(&self) -> Stolen<T> { - unsafe { self.deque.steal() } - } - - /// Gets access to the buffer pool that this stealer is attached to. This - /// can be used to create more deques which share the same buffer pool as - /// this deque. - pub fn pool<'a>(&'a self) -> &'a BufferPool<T> { - &self.deque.pool - } -} - -impl<T: Send> Clone for Stealer<T> { - fn clone(&self) -> Stealer<T> { - Stealer { deque: self.deque.clone(), _noshare: marker::NoSync } - } -} - -// Almost all of this code can be found directly in the paper so I'm not -// personally going to heavily comment what's going on here. - -impl<T: Send> Deque<T> { - fn new(mut pool: BufferPool<T>) -> Deque<T> { - let buf = pool.alloc(MIN_BITS); - Deque { - bottom: AtomicInt::new(0), - top: AtomicInt::new(0), - array: AtomicPtr::new(unsafe { transmute(buf) }), - pool: pool, - } - } - - unsafe fn push(&self, data: T) { - let mut b = self.bottom.load(SeqCst); - let t = self.top.load(SeqCst); - let mut a = self.array.load(SeqCst); - let size = b - t; - if size >= (*a).size() - 1 { - // You won't find this code in the chase-lev deque paper. This is - // alluded to in a small footnote, however. We always free a buffer - // when growing in order to prevent leaks. - a = self.swap_buffer(b, a, (*a).resize(b, t, 1)); - b = self.bottom.load(SeqCst); - } - (*a).put(b, data); - self.bottom.store(b + 1, SeqCst); - } - - unsafe fn pop(&self) -> Option<T> { - let b = self.bottom.load(SeqCst); - let a = self.array.load(SeqCst); - let b = b - 1; - self.bottom.store(b, SeqCst); - let t = self.top.load(SeqCst); - let size = b - t; - if size < 0 { - self.bottom.store(t, SeqCst); - return None; - } - let data = (*a).get(b); - if size > 0 { - self.maybe_shrink(b, t); - return Some(data); - } - if self.top.compare_and_swap(t, t + 1, SeqCst) == t { - self.bottom.store(t + 1, SeqCst); - return Some(data); - } else { - self.bottom.store(t + 1, SeqCst); - forget(data); // someone else stole this value - return None; - } - } - - unsafe fn steal(&self) -> Stolen<T> { - let t = self.top.load(SeqCst); - let old = self.array.load(SeqCst); - let b = self.bottom.load(SeqCst); - let a = self.array.load(SeqCst); - let size = b - t; - if size <= 0 { return Empty } - if size % (*a).size() == 0 { - if a == old && t == self.top.load(SeqCst) { - return Empty - } - return Abort - } - let data = (*a).get(t); - if self.top.compare_and_swap(t, t + 1, SeqCst) == t { - Data(data) - } else { - forget(data); // someone else stole this value - Abort - } - } - - unsafe fn maybe_shrink(&self, b: int, t: int) { - let a = self.array.load(SeqCst); - if b - t < (*a).size() / K && b - t > (1 << MIN_BITS) { - self.swap_buffer(b, a, (*a).resize(b, t, -1)); - } - } - - // Helper routine not mentioned in the paper which is used in growing and - // shrinking buffers to swap in a new buffer into place. As a bit of a - // recap, the whole point that we need a buffer pool rather than just - // calling malloc/free directly is that stealers can continue using buffers - // after this method has called 'free' on it. The continued usage is simply - // a read followed by a forget, but we must make sure that the memory can - // continue to be read after we flag this buffer for reclamation. - unsafe fn swap_buffer(&self, b: int, old: *mut Buffer<T>, - buf: Buffer<T>) -> *mut Buffer<T> { - let newbuf: *mut Buffer<T> = transmute(box buf); - self.array.store(newbuf, SeqCst); - let ss = (*newbuf).size(); - self.bottom.store(b + ss, SeqCst); - let t = self.top.load(SeqCst); - if self.top.compare_and_swap(t, t + ss, SeqCst) != t { - self.bottom.store(b, SeqCst); - } - self.pool.free(transmute(old)); - return newbuf; - } -} - - -#[unsafe_destructor] -impl<T: Send> Drop for Deque<T> { - fn drop(&mut self) { - let t = self.top.load(SeqCst); - let b = self.bottom.load(SeqCst); - let a = self.array.load(SeqCst); - // Free whatever is leftover in the dequeue, and then move the buffer - // back into the pool. - for i in range(t, b) { - let _: T = unsafe { (*a).get(i) }; - } - self.pool.free(unsafe { transmute(a) }); - } -} - -#[inline] -fn buffer_alloc_size<T>(log_size: uint) -> uint { - (1 << log_size) * size_of::<T>() -} - -impl<T: Send> Buffer<T> { - unsafe fn new(log_size: uint) -> Buffer<T> { - let size = buffer_alloc_size::<T>(log_size); - let buffer = allocate(size, min_align_of::<T>()); - if buffer.is_null() { ::alloc::oom() } - Buffer { - storage: buffer as *const T, - log_size: log_size, - } - } - - fn size(&self) -> int { 1 << self.log_size } - - // Apparently LLVM cannot optimize (foo % (1 << bar)) into this implicitly - fn mask(&self) -> int { (1 << self.log_size) - 1 } - - unsafe fn elem(&self, i: int) -> *const T { - self.storage.offset(i & self.mask()) - } - - // This does not protect against loading duplicate values of the same cell, - // nor does this clear out the contents contained within. Hence, this is a - // very unsafe method which the caller needs to treat specially in case a - // race is lost. - unsafe fn get(&self, i: int) -> T { - ptr::read(self.elem(i)) - } - - // Unsafe because this unsafely overwrites possibly uninitialized or - // initialized data. - unsafe fn put(&self, i: int, t: T) { - ptr::write(self.elem(i) as *mut T, t); - } - - // Again, unsafe because this has incredibly dubious ownership violations. - // It is assumed that this buffer is immediately dropped. - unsafe fn resize(&self, b: int, t: int, delta: int) -> Buffer<T> { - // NB: not entirely obvious, but thanks to 2's complement, - // casting delta to uint and then adding gives the desired - // effect. - let buf = Buffer::new(self.log_size + delta as uint); - for i in range(t, b) { - buf.put(i, self.get(i)); - } - return buf; - } -} - -#[unsafe_destructor] -impl<T: Send> Drop for Buffer<T> { - fn drop(&mut self) { - // It is assumed that all buffers are empty on drop. - let size = buffer_alloc_size::<T>(self.log_size); - unsafe { deallocate(self.storage as *mut u8, size, min_align_of::<T>()) } - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use super::{Data, BufferPool, Abort, Empty, Worker, Stealer}; - - use mem; - use rustrt::thread::Thread; - use rand; - use rand::Rng; - use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, SeqCst, - AtomicUint, INIT_ATOMIC_UINT}; - use vec; - - #[test] - fn smoke() { - let pool = BufferPool::new(); - let (w, s) = pool.deque(); - assert_eq!(w.pop(), None); - assert_eq!(s.steal(), Empty); - w.push(1i); - assert_eq!(w.pop(), Some(1)); - w.push(1); - assert_eq!(s.steal(), Data(1)); - w.push(1); - assert_eq!(s.clone().steal(), Data(1)); - } - - #[test] - fn stealpush() { - static AMT: int = 100000; - let pool = BufferPool::<int>::new(); - let (w, s) = pool.deque(); - let t = Thread::start(proc() { - let mut left = AMT; - while left > 0 { - match s.steal() { - Data(i) => { - assert_eq!(i, 1); - left -= 1; - } - Abort | Empty => {} - } - } - }); - - for _ in range(0, AMT) { - w.push(1); - } - - t.join(); - } - - #[test] - fn stealpush_large() { - static AMT: int = 100000; - let pool = BufferPool::<(int, int)>::new(); - let (w, s) = pool.deque(); - let t = Thread::start(proc() { - let mut left = AMT; - while left > 0 { - match s.steal() { - Data((1, 10)) => { left -= 1; } - Data(..) => panic!(), - Abort | Empty => {} - } - } - }); - - for _ in range(0, AMT) { - w.push((1, 10)); - } - - t.join(); - } - - fn stampede(w: Worker<Box<int>>, s: Stealer<Box<int>>, - nthreads: int, amt: uint) { - for _ in range(0, amt) { - w.push(box 20); - } - let mut remaining = AtomicUint::new(amt); - let unsafe_remaining: *mut AtomicUint = &mut remaining; - - let threads = range(0, nthreads).map(|_| { - let s = s.clone(); - Thread::start(proc() { - unsafe { - while (*unsafe_remaining).load(SeqCst) > 0 { - match s.steal() { - Data(box 20) => { - (*unsafe_remaining).fetch_sub(1, SeqCst); - } - Data(..) => panic!(), - Abort | Empty => {} - } - } - } - }) - }).collect::<Vec<Thread<()>>>(); - - while remaining.load(SeqCst) > 0 { - match w.pop() { - Some(box 20) => { remaining.fetch_sub(1, SeqCst); } - Some(..) => panic!(), - None => {} - } - } - - for thread in threads.into_iter() { - thread.join(); - } - } - - #[test] - fn run_stampede() { - let pool = BufferPool::<Box<int>>::new(); - let (w, s) = pool.deque(); - stampede(w, s, 8, 10000); - } - - #[test] - fn many_stampede() { - static AMT: uint = 4; - let pool = BufferPool::<Box<int>>::new(); - let threads = range(0, AMT).map(|_| { - let (w, s) = pool.deque(); - Thread::start(proc() { - stampede(w, s, 4, 10000); - }) - }).collect::<Vec<Thread<()>>>(); - - for thread in threads.into_iter() { - thread.join(); - } - } - - #[test] - fn stress() { - static AMT: int = 100000; - static NTHREADS: int = 8; - static DONE: AtomicBool = INIT_ATOMIC_BOOL; - static HITS: AtomicUint = INIT_ATOMIC_UINT; - let pool = BufferPool::<int>::new(); - let (w, s) = pool.deque(); - - let threads = range(0, NTHREADS).map(|_| { - let s = s.clone(); - Thread::start(proc() { - loop { - match s.steal() { - Data(2) => { HITS.fetch_add(1, SeqCst); } - Data(..) => panic!(), - _ if DONE.load(SeqCst) => break, - _ => {} - } - } - }) - }).collect::<Vec<Thread<()>>>(); - - let mut rng = rand::task_rng(); - let mut expected = 0; - while expected < AMT { - if rng.gen_range(0i, 3) == 2 { - match w.pop() { - None => {} - Some(2) => { HITS.fetch_add(1, SeqCst); }, - Some(_) => panic!(), - } - } else { - expected += 1; - w.push(2); - } - } - - while HITS.load(SeqCst) < AMT as uint { - match w.pop() { - None => {} - Some(2) => { HITS.fetch_add(1, SeqCst); }, - Some(_) => panic!(), - } - } - DONE.store(true, SeqCst); - - for thread in threads.into_iter() { - thread.join(); - } - - assert_eq!(HITS.load(SeqCst), expected as uint); - } - - #[test] - #[cfg_attr(windows, ignore)] // apparently windows scheduling is weird? - fn no_starvation() { - static AMT: int = 10000; - static NTHREADS: int = 4; - static DONE: AtomicBool = INIT_ATOMIC_BOOL; - let pool = BufferPool::<(int, uint)>::new(); - let (w, s) = pool.deque(); - - let (threads, hits) = vec::unzip(range(0, NTHREADS).map(|_| { - let s = s.clone(); - let unique_box = box AtomicUint::new(0); - let thread_box = unsafe { - *mem::transmute::<&Box<AtomicUint>, - *const *mut AtomicUint>(&unique_box) - }; - (Thread::start(proc() { - unsafe { - loop { - match s.steal() { - Data((1, 2)) => { - (*thread_box).fetch_add(1, SeqCst); - } - Data(..) => panic!(), - _ if DONE.load(SeqCst) => break, - _ => {} - } - } - } - }), unique_box) - })); - - let mut rng = rand::task_rng(); - let mut myhit = false; - 'outer: loop { - for _ in range(0, rng.gen_range(0, AMT)) { - if !myhit && rng.gen_range(0i, 3) == 2 { - match w.pop() { - None => {} - Some((1, 2)) => myhit = true, - Some(_) => panic!(), - } - } else { - w.push((1, 2)); - } - } - - for slot in hits.iter() { - let amt = slot.load(SeqCst); - if amt == 0 { continue 'outer; } - } - if myhit { - break - } - } - - DONE.store(true, SeqCst); - - for thread in threads.into_iter() { - thread.join(); - } - } -} diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs index f2f9351fd0d..79e0d487cad 100644 --- a/src/libstd/sync/future.rs +++ b/src/libstd/sync/future.rs @@ -148,7 +148,7 @@ mod test { use prelude::*; use sync::Future; use task; - use comm::{channel, Sender}; + use comm::channel; #[test] fn test_from_value() { diff --git a/src/libstd/sync/lock.rs b/src/libstd/sync/lock.rs deleted file mode 100644 index 77f5b013519..00000000000 --- a/src/libstd/sync/lock.rs +++ /dev/null @@ -1,805 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Wrappers for safe, shared, mutable memory between tasks -//! -//! The wrappers in this module build on the primitives from `sync::raw` to -//! provide safe interfaces around using the primitive locks. These primitives -//! implement a technique called "poisoning" where when a task panicked with a -//! held lock, all future attempts to use the lock will panic. -//! -//! For example, if two tasks are contending on a mutex and one of them panics -//! after grabbing the lock, the second task will immediately panic because the -//! lock is now poisoned. - -use core::prelude::*; - -use self::Inner::*; - -use core::cell::UnsafeCell; -use rustrt::local::Local; -use rustrt::task::Task; - -use super::raw; - -// Poisoning helpers - -struct PoisonOnFail<'a> { - flag: &'a mut bool, - failed: bool, -} - -fn failing() -> bool { - Local::borrow(None::<Task>).unwinder.unwinding() -} - -impl<'a> PoisonOnFail<'a> { - fn check(flag: bool, name: &str) { - if flag { - panic!("Poisoned {} - another task failed inside!", name); - } - } - - fn new<'a>(flag: &'a mut bool, name: &str) -> PoisonOnFail<'a> { - PoisonOnFail::check(*flag, name); - PoisonOnFail { - flag: flag, - failed: failing() - } - } -} - -#[unsafe_destructor] -impl<'a> Drop for PoisonOnFail<'a> { - fn drop(&mut self) { - if !self.failed && failing() { - *self.flag = true; - } - } -} - -// Condvar - -enum Inner<'a> { - InnerMutex(raw::MutexGuard<'a>), - InnerRWLock(raw::RWLockWriteGuard<'a>), -} - -impl<'b> Inner<'b> { - fn cond<'a>(&'a self) -> &'a raw::Condvar<'b> { - match *self { - InnerMutex(ref m) => &m.cond, - InnerRWLock(ref m) => &m.cond, - } - } -} - -/// A condition variable, a mechanism for unlock-and-descheduling and -/// signaling, for use with the lock types. -pub struct Condvar<'a> { - name: &'static str, - // n.b. Inner must be after PoisonOnFail because we must set the poison flag - // *inside* the mutex, and struct fields are destroyed top-to-bottom - // (destroy the lock guard last). - poison: PoisonOnFail<'a>, - inner: Inner<'a>, -} - -impl<'a> Condvar<'a> { - /// Atomically exit the associated lock and block until a signal is sent. - /// - /// wait() is equivalent to wait_on(0). - /// - /// # Panics - /// - /// A task which is killed while waiting on a condition variable will wake - /// up, panic, and unlock the associated lock as it unwinds. - #[inline] - pub fn wait(&self) { self.wait_on(0) } - - /// Atomically exit the associated lock and block on a specified condvar - /// until a signal is sent on that same condvar. - /// - /// The associated lock must have been initialised with an appropriate - /// number of condvars. The condvar_id must be between 0 and num_condvars-1 - /// or else this call will fail. - #[inline] - pub fn wait_on(&self, condvar_id: uint) { - assert!(!*self.poison.flag); - self.inner.cond().wait_on(condvar_id); - // This is why we need to wrap sync::condvar. - PoisonOnFail::check(*self.poison.flag, self.name); - } - - /// Wake up a blocked task. Returns false if there was no blocked task. - #[inline] - pub fn signal(&self) -> bool { self.signal_on(0) } - - /// Wake up a blocked task on a specified condvar (as - /// sync::cond.signal_on). Returns false if there was no blocked task. - #[inline] - pub fn signal_on(&self, condvar_id: uint) -> bool { - assert!(!*self.poison.flag); - self.inner.cond().signal_on(condvar_id) - } - - /// Wake up all blocked tasks. Returns the number of tasks woken. - #[inline] - pub fn broadcast(&self) -> uint { self.broadcast_on(0) } - - /// Wake up all blocked tasks on a specified condvar (as - /// sync::cond.broadcast_on). Returns the number of tasks woken. - #[inline] - pub fn broadcast_on(&self, condvar_id: uint) -> uint { - assert!(!*self.poison.flag); - self.inner.cond().broadcast_on(condvar_id) - } -} - -/// A wrapper type which provides synchronized access to the underlying data, of -/// type `T`. A mutex always provides exclusive access, and concurrent requests -/// will block while the mutex is already locked. -/// -/// # Example -/// -/// ``` -/// use std::sync::{Mutex, Arc}; -/// -/// let mutex = Arc::new(Mutex::new(1i)); -/// let mutex2 = mutex.clone(); -/// -/// spawn(proc() { -/// let mut val = mutex2.lock(); -/// *val += 1; -/// val.cond.signal(); -/// }); -/// -/// let value = mutex.lock(); -/// while *value != 2 { -/// value.cond.wait(); -/// } -/// ``` -pub struct Mutex<T> { - lock: raw::Mutex, - failed: UnsafeCell<bool>, - data: UnsafeCell<T>, -} - -/// An guard which is created by locking a mutex. Through this guard the -/// underlying data can be accessed. -pub struct MutexGuard<'a, T:'a> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _data: &'a mut T, - /// Inner condition variable connected to the locked mutex that this guard - /// was created from. This can be used for atomic-unlock-and-deschedule. - pub cond: Condvar<'a>, -} - -impl<T: Send> Mutex<T> { - /// Creates a new mutex to protect the user-supplied data. - pub fn new(user_data: T) -> Mutex<T> { - Mutex::new_with_condvars(user_data, 1) - } - - /// Create a new mutex, with a specified number of associated condvars. - /// - /// This will allow calling wait_on/signal_on/broadcast_on with condvar IDs - /// between 0 and num_condvars-1. (If num_condvars is 0, lock_cond will be - /// allowed but any operations on the condvar will fail.) - pub fn new_with_condvars(user_data: T, num_condvars: uint) -> Mutex<T> { - Mutex { - lock: raw::Mutex::new_with_condvars(num_condvars), - failed: UnsafeCell::new(false), - data: UnsafeCell::new(user_data), - } - } - - /// Access the underlying mutable data with mutual exclusion from other - /// tasks. The returned value is an RAII guard which will unlock the mutex - /// when dropped. All concurrent tasks attempting to lock the mutex will - /// block while the returned value is still alive. - /// - /// # Panics - /// - /// Panicking while inside the Mutex will unlock the Mutex while unwinding, so - /// that other tasks won't block forever. It will also poison the Mutex: - /// any tasks that subsequently try to access it (including those already - /// blocked on the mutex) will also panic immediately. - #[inline] - pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> { - let guard = self.lock.lock(); - - // These two accesses are safe because we're guaranteed at this point - // that we have exclusive access to this mutex. We are indeed able to - // promote ourselves from &Mutex to `&mut T` - let poison = unsafe { &mut *self.failed.get() }; - let data = unsafe { &mut *self.data.get() }; - - MutexGuard { - _data: data, - cond: Condvar { - name: "Mutex", - poison: PoisonOnFail::new(poison, "Mutex"), - inner: InnerMutex(guard), - }, - } - } -} - -impl<'a, T: Send> Deref<T> for MutexGuard<'a, T> { - fn deref<'a>(&'a self) -> &'a T { &*self._data } -} -impl<'a, T: Send> DerefMut<T> for MutexGuard<'a, T> { - fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self._data } -} - -/// A dual-mode reader-writer lock. The data can be accessed mutably or -/// immutably, and immutably-accessing tasks may run concurrently. -/// -/// # Example -/// -/// ``` -/// use std::sync::{RWLock, Arc}; -/// -/// let lock1 = Arc::new(RWLock::new(1i)); -/// let lock2 = lock1.clone(); -/// -/// spawn(proc() { -/// let mut val = lock2.write(); -/// *val = 3; -/// let val = val.downgrade(); -/// println!("{}", *val); -/// }); -/// -/// let val = lock1.read(); -/// println!("{}", *val); -/// ``` -pub struct RWLock<T> { - lock: raw::RWLock, - failed: UnsafeCell<bool>, - data: UnsafeCell<T>, -} - -/// A guard which is created by locking an rwlock in write mode. Through this -/// guard the underlying data can be accessed. -pub struct RWLockWriteGuard<'a, T:'a> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _data: &'a mut T, - /// Inner condition variable that can be used to sleep on the write mode of - /// this rwlock. - pub cond: Condvar<'a>, -} - -/// A guard which is created by locking an rwlock in read mode. Through this -/// guard the underlying data can be accessed. -pub struct RWLockReadGuard<'a, T:'a> { - // FIXME #12808: strange names to try to avoid interfering with - // field accesses of the contained type via Deref - _data: &'a T, - _guard: raw::RWLockReadGuard<'a>, -} - -impl<T: Send + Sync> RWLock<T> { - /// Create a reader/writer lock with the supplied data. - pub fn new(user_data: T) -> RWLock<T> { - RWLock::new_with_condvars(user_data, 1) - } - - /// Create a reader/writer lock with the supplied data and a specified number - /// of condvars (as sync::RWLock::new_with_condvars). - pub fn new_with_condvars(user_data: T, num_condvars: uint) -> RWLock<T> { - RWLock { - lock: raw::RWLock::new_with_condvars(num_condvars), - failed: UnsafeCell::new(false), - data: UnsafeCell::new(user_data), - } - } - - /// Access the underlying data mutably. Locks the rwlock in write mode; - /// other readers and writers will block. - /// - /// # Panics - /// - /// Panicking while inside the lock will unlock the lock while unwinding, so - /// that other tasks won't block forever. As Mutex.lock, it will also poison - /// the lock, so subsequent readers and writers will both also panic. - #[inline] - pub fn write<'a>(&'a self) -> RWLockWriteGuard<'a, T> { - let guard = self.lock.write(); - - // These two accesses are safe because we're guaranteed at this point - // that we have exclusive access to this rwlock. We are indeed able to - // promote ourselves from &RWLock to `&mut T` - let poison = unsafe { &mut *self.failed.get() }; - let data = unsafe { &mut *self.data.get() }; - - RWLockWriteGuard { - _data: data, - cond: Condvar { - name: "RWLock", - poison: PoisonOnFail::new(poison, "RWLock"), - inner: InnerRWLock(guard), - }, - } - } - - /// Access the underlying data immutably. May run concurrently with other - /// reading tasks. - /// - /// # Panics - /// - /// Panicking will unlock the lock while unwinding. However, unlike all other - /// access modes, this will not poison the lock. - pub fn read<'a>(&'a self) -> RWLockReadGuard<'a, T> { - let guard = self.lock.read(); - PoisonOnFail::check(unsafe { *self.failed.get() }, "RWLock"); - RWLockReadGuard { - _guard: guard, - _data: unsafe { &*self.data.get() }, - } - } -} - -impl<'a, T: Send + Sync> RWLockWriteGuard<'a, T> { - /// Consumes this write lock token, returning a new read lock token. - /// - /// This will allow pending readers to come into the lock. - pub fn downgrade(self) -> RWLockReadGuard<'a, T> { - let RWLockWriteGuard { _data, cond } = self; - // convert the data to read-only explicitly - let data = &*_data; - let guard = match cond.inner { - InnerMutex(..) => unreachable!(), - InnerRWLock(guard) => guard.downgrade() - }; - RWLockReadGuard { _guard: guard, _data: data } - } -} - -impl<'a, T: Send + Sync> Deref<T> for RWLockReadGuard<'a, T> { - fn deref<'a>(&'a self) -> &'a T { self._data } -} -impl<'a, T: Send + Sync> Deref<T> for RWLockWriteGuard<'a, T> { - fn deref<'a>(&'a self) -> &'a T { &*self._data } -} -impl<'a, T: Send + Sync> DerefMut<T> for RWLockWriteGuard<'a, T> { - fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self._data } -} - -/// A barrier enables multiple tasks to synchronize the beginning -/// of some computation. -/// -/// ```rust -/// use std::sync::{Arc, Barrier}; -/// -/// let barrier = Arc::new(Barrier::new(10)); -/// for _ in range(0u, 10) { -/// let c = barrier.clone(); -/// // The same messages will be printed together. -/// // You will NOT see any interleaving. -/// spawn(proc() { -/// println!("before wait"); -/// c.wait(); -/// println!("after wait"); -/// }); -/// } -/// ``` -pub struct Barrier { - lock: Mutex<BarrierState>, - num_tasks: uint, -} - -// The inner state of a double barrier -struct BarrierState { - count: uint, - generation_id: uint, -} - -impl Barrier { - /// Create a new barrier that can block a given number of tasks. - pub fn new(num_tasks: uint) -> Barrier { - Barrier { - lock: Mutex::new(BarrierState { - count: 0, - generation_id: 0, - }), - num_tasks: num_tasks, - } - } - - /// Block the current task until a certain number of tasks is waiting. - pub fn wait(&self) { - let mut lock = self.lock.lock(); - let local_gen = lock.generation_id; - lock.count += 1; - if lock.count < self.num_tasks { - // We need a while loop to guard against spurious wakeups. - // http://en.wikipedia.org/wiki/Spurious_wakeup - while local_gen == lock.generation_id && - lock.count < self.num_tasks { - lock.cond.wait(); - } - } else { - lock.count = 0; - lock.generation_id += 1; - lock.cond.broadcast(); - } - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use comm::Empty; - use task; - use task::try_future; - use sync::Arc; - - use super::{Mutex, Barrier, RWLock}; - - #[test] - fn test_mutex_arc_condvar() { - let arc = Arc::new(Mutex::new(false)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - task::spawn(proc() { - // wait until parent gets in - rx.recv(); - let mut lock = arc2.lock(); - *lock = true; - lock.cond.signal(); - }); - - let lock = arc.lock(); - tx.send(()); - assert!(!*lock); - while !*lock { - lock.cond.wait(); - } - } - - #[test] #[should_fail] - fn test_arc_condvar_poison() { - let arc = Arc::new(Mutex::new(1i)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - spawn(proc() { - rx.recv(); - let lock = arc2.lock(); - lock.cond.signal(); - // Parent should fail when it wakes up. - panic!(); - }); - - let lock = arc.lock(); - tx.send(()); - while *lock == 1 { - lock.cond.wait(); - } - } - - #[test] #[should_fail] - fn test_mutex_arc_poison() { - let arc = Arc::new(Mutex::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.lock(); - assert_eq!(*lock, 2); - }); - let lock = arc.lock(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1i)); - let arc2 = Arc::new(Mutex::new(arc)); - task::spawn(proc() { - let lock = arc2.lock(); - let lock2 = lock.deref().lock(); - assert_eq!(*lock2, 1); - }); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1i)); - let arc2 = arc.clone(); - let _ = task::try::<()>(proc() { - struct Unwinder { - i: Arc<Mutex<int>>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.lock(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }); - let lock = arc.lock(); - assert_eq!(*lock, 2); - } - - #[test] #[should_fail] - fn test_rw_arc_poison_wr() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.write(); - assert_eq!(*lock, 2); - }); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - #[test] #[should_fail] - fn test_rw_arc_poison_ww() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.write(); - assert_eq!(*lock, 2); - }); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.read(); - assert_eq!(*lock, 2); - }); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.read(); - assert_eq!(*lock, 2); - }); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_dr() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try(proc() { - let lock = arc2.write().downgrade(); - assert_eq!(*lock, 2); - }); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RWLock::new(0i)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - task::spawn(proc() { - let mut lock = arc2.write(); - for _ in range(0u, 10) { - let tmp = *lock; - *lock = -1; - task::deschedule(); - *lock = tmp + 1; - } - tx.send(()); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in range(0u, 5) { - let arc3 = arc.clone(); - children.push(try_future(proc() { - let lock = arc3.read(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children.iter_mut() { - assert!(r.get_ref().is_ok()); - } - - // Wait for writer to finish - rx.recv(); - let lock = arc.read(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RWLock::new(1i)); - let arc2 = arc.clone(); - let _ = task::try::<()>(proc() { - struct Unwinder { - i: Arc<RWLock<int>>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }); - let lock = arc.read(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rw_downgrade() { - // (1) A downgrader gets in write mode and does cond.wait. - // (2) A writer gets in write mode, sets state to 42, and does signal. - // (3) Downgrader wakes, sets state to 31337. - // (4) tells writer and all other readers to contend as it downgrades. - // (5) Writer attempts to set state back to 42, while downgraded task - // and all reader tasks assert that it's 31337. - let arc = Arc::new(RWLock::new(0i)); - - // Reader tasks - let mut reader_convos = Vec::new(); - for _ in range(0u, 10) { - let ((tx1, rx1), (tx2, rx2)) = (channel(), channel()); - reader_convos.push((tx1, rx2)); - let arcn = arc.clone(); - task::spawn(proc() { - rx1.recv(); // wait for downgrader to give go-ahead - let lock = arcn.read(); - assert_eq!(*lock, 31337); - tx2.send(()); - }); - } - - // Writer task - let arc2 = arc.clone(); - let ((tx1, rx1), (tx2, rx2)) = (channel(), channel()); - task::spawn(proc() { - rx1.recv(); - { - let mut lock = arc2.write(); - assert_eq!(*lock, 0); - *lock = 42; - lock.cond.signal(); - } - rx1.recv(); - { - let mut lock = arc2.write(); - // This shouldn't happen until after the downgrade read - // section, and all other readers, finish. - assert_eq!(*lock, 31337); - *lock = 42; - } - tx2.send(()); - }); - - // Downgrader (us) - let mut lock = arc.write(); - tx1.send(()); // send to another writer who will wake us up - while *lock == 0 { - lock.cond.wait(); - } - assert_eq!(*lock, 42); - *lock = 31337; - // send to other readers - for &(ref mut rc, _) in reader_convos.iter_mut() { - rc.send(()) - } - let lock = lock.downgrade(); - // complete handshake with other readers - for &(_, ref mut rp) in reader_convos.iter_mut() { - rp.recv() - } - tx1.send(()); // tell writer to try again - assert_eq!(*lock, 31337); - drop(lock); - - rx2.recv(); // complete handshake with writer - } - - #[cfg(test)] - fn test_rw_write_cond_downgrade_read_race_helper() { - // Tests that when a downgrader hands off the "reader cloud" lock - // because of a contending reader, a writer can't race to get it - // instead, which would result in readers_and_writers. This tests - // the raw module rather than this one, but it's here because an - // rwarc gives us extra shared state to help check for the race. - let x = Arc::new(RWLock::new(true)); - let (tx, rx) = channel(); - - // writer task - let xw = x.clone(); - task::spawn(proc() { - let mut lock = xw.write(); - tx.send(()); // tell downgrader it's ok to go - lock.cond.wait(); - // The core of the test is here: the condvar reacquire path - // must involve order_lock, so that it cannot race with a reader - // trying to receive the "reader cloud lock hand-off". - *lock = false; - }); - - rx.recv(); // wait for writer to get in - - let lock = x.write(); - assert!(*lock); - // make writer contend in the cond-reacquire path - lock.cond.signal(); - // make a reader task to trigger the "reader cloud lock" handoff - let xr = x.clone(); - let (tx, rx) = channel(); - task::spawn(proc() { - tx.send(()); - drop(xr.read()); - }); - rx.recv(); // wait for reader task to exist - - let lock = lock.downgrade(); - // if writer mistakenly got in, make sure it mutates state - // before we assert on it - for _ in range(0u, 5) { task::deschedule(); } - // make sure writer didn't get in. - assert!(*lock); - } - #[test] - fn test_rw_write_cond_downgrade_read_race() { - // Ideally the above test case would have deschedule statements in it - // that helped to expose the race nearly 100% of the time... but adding - // deschedules in the intuitively-right locations made it even less - // likely, and I wasn't sure why :( . This is a mediocre "next best" - // option. - for _ in range(0u, 8) { - test_rw_write_cond_downgrade_read_race_helper(); - } - } - - #[test] - fn test_barrier() { - let barrier = Arc::new(Barrier::new(10)); - let (tx, rx) = channel(); - - for _ in range(0u, 9) { - let c = barrier.clone(); - let tx = tx.clone(); - spawn(proc() { - c.wait(); - tx.send(true); - }); - } - - // At this point, all spawned tasks should be blocked, - // so we shouldn't get anything from the port - assert!(match rx.try_recv() { - Err(Empty) => true, - _ => false, - }); - - barrier.wait(); - // Now, the barrier is cleared and we should get data. - for _ in range(0u, 9) { - rx.recv(); - } - } -} diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 944b852db35..7605a6a96a0 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -17,41 +17,27 @@ #![experimental] -pub use self::one::{Once, ONCE_INIT}; - pub use alloc::arc::{Arc, Weak}; -pub use self::lock::{Mutex, MutexGuard, Condvar, Barrier, - RWLock, RWLockReadGuard, RWLockWriteGuard}; -// The mutex/rwlock in this module are not meant for reexport -pub use self::raw::{Semaphore, SemaphoreGuard}; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard, MUTEX_INIT}; +pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT}; +pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard}; +pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard}; +pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsMutexGuard}; +pub use self::once::{Once, ONCE_INIT}; +pub use self::semaphore::{Semaphore, SemaphoreGuard}; +pub use self::barrier::Barrier; pub use self::future::Future; pub use self::task_pool::TaskPool; -// Core building blocks for all primitives in this crate - -#[stable] pub mod atomic; - -// Concurrent data structures - -pub mod spsc_queue; -pub mod mpsc_queue; -pub mod mpmc_bounded_queue; -pub mod deque; - -// Low-level concurrency primitives - -mod raw; -mod mutex; -mod one; - -// Higher level primitives based on those above - -mod lock; - -// Task management - +mod barrier; +mod condvar; mod future; +mod mutex; +mod once; +mod poison; +mod rwlock; +mod semaphore; mod task_pool; diff --git a/src/libstd/sync/mpmc_bounded_queue.rs b/src/libstd/sync/mpmc_bounded_queue.rs deleted file mode 100644 index dca2d4098c6..00000000000 --- a/src/libstd/sync/mpmc_bounded_queue.rs +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of Dmitry Vyukov. - */ - -#![experimental] -#![allow(missing_docs, dead_code)] - -// http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue - -use core::prelude::*; - -use alloc::arc::Arc; -use vec::Vec; -use core::num::UnsignedInt; -use core::cell::UnsafeCell; - -use sync::atomic::{AtomicUint,Relaxed,Release,Acquire}; - -struct Node<T> { - sequence: AtomicUint, - value: Option<T>, -} - -struct State<T> { - pad0: [u8, ..64], - buffer: Vec<UnsafeCell<Node<T>>>, - mask: uint, - pad1: [u8, ..64], - enqueue_pos: AtomicUint, - pad2: [u8, ..64], - dequeue_pos: AtomicUint, - pad3: [u8, ..64], -} - -pub struct Queue<T> { - state: Arc<State<T>>, -} - -impl<T: Send> State<T> { - fn with_capacity(capacity: uint) -> State<T> { - let capacity = if capacity < 2 || (capacity & (capacity - 1)) != 0 { - if capacity < 2 { - 2u - } else { - // use next power of 2 as capacity - capacity.next_power_of_two() - } - } else { - capacity - }; - let buffer = Vec::from_fn(capacity, |i| { - UnsafeCell::new(Node { sequence:AtomicUint::new(i), value: None }) - }); - State{ - pad0: [0, ..64], - buffer: buffer, - mask: capacity-1, - pad1: [0, ..64], - enqueue_pos: AtomicUint::new(0), - pad2: [0, ..64], - dequeue_pos: AtomicUint::new(0), - pad3: [0, ..64], - } - } - - fn push(&self, value: T) -> bool { - let mask = self.mask; - let mut pos = self.enqueue_pos.load(Relaxed); - loop { - let node = &self.buffer[pos & mask]; - let seq = unsafe { (*node.get()).sequence.load(Acquire) }; - let diff: int = seq as int - pos as int; - - if diff == 0 { - let enqueue_pos = self.enqueue_pos.compare_and_swap(pos, pos+1, Relaxed); - if enqueue_pos == pos { - unsafe { - (*node.get()).value = Some(value); - (*node.get()).sequence.store(pos+1, Release); - } - break - } else { - pos = enqueue_pos; - } - } else if diff < 0 { - return false - } else { - pos = self.enqueue_pos.load(Relaxed); - } - } - true - } - - fn pop(&self) -> Option<T> { - let mask = self.mask; - let mut pos = self.dequeue_pos.load(Relaxed); - loop { - let node = &self.buffer[pos & mask]; - let seq = unsafe { (*node.get()).sequence.load(Acquire) }; - let diff: int = seq as int - (pos + 1) as int; - if diff == 0 { - let dequeue_pos = self.dequeue_pos.compare_and_swap(pos, pos+1, Relaxed); - if dequeue_pos == pos { - unsafe { - let value = (*node.get()).value.take(); - (*node.get()).sequence.store(pos + mask + 1, Release); - return value - } - } else { - pos = dequeue_pos; - } - } else if diff < 0 { - return None - } else { - pos = self.dequeue_pos.load(Relaxed); - } - } - } -} - -impl<T: Send> Queue<T> { - pub fn with_capacity(capacity: uint) -> Queue<T> { - Queue{ - state: Arc::new(State::with_capacity(capacity)) - } - } - - pub fn push(&self, value: T) -> bool { - self.state.push(value) - } - - pub fn pop(&self) -> Option<T> { - self.state.pop() - } -} - -impl<T: Send> Clone for Queue<T> { - fn clone(&self) -> Queue<T> { - Queue { state: self.state.clone() } - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use super::Queue; - - #[test] - fn test() { - let nthreads = 8u; - let nmsgs = 1000u; - let q = Queue::with_capacity(nthreads*nmsgs); - assert_eq!(None, q.pop()); - let (tx, rx) = channel(); - - for _ in range(0, nthreads) { - let q = q.clone(); - let tx = tx.clone(); - spawn(proc() { - let q = q; - for i in range(0, nmsgs) { - assert!(q.push(i)); - } - tx.send(()); - }); - } - - let mut completion_rxs = vec![]; - for _ in range(0, nthreads) { - let (tx, rx) = channel(); - completion_rxs.push(rx); - let q = q.clone(); - spawn(proc() { - let q = q; - let mut i = 0u; - loop { - match q.pop() { - None => {}, - Some(_) => { - i += 1; - if i == nmsgs { break } - } - } - } - tx.send(i); - }); - } - - for rx in completion_rxs.iter_mut() { - assert_eq!(nmsgs, rx.recv()); - } - for _ in range(0, nthreads) { - rx.recv(); - } - } -} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index c9e90210c30..4e07d54c57e 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -8,43 +8,68 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A simple native mutex implementation. Warning: this API is likely -//! to change soon. +use prelude::*; -#![allow(dead_code)] - -use core::prelude::*; -use alloc::boxed::Box; -use rustrt::mutex; - -pub const LOCKED: uint = 1 << 0; -pub const BLOCKED: uint = 1 << 1; +use cell::UnsafeCell; +use kinds::marker; +use sync::{poison, AsMutexGuard}; +use sys_common::mutex as sys; /// A mutual exclusion primitive useful for protecting shared data /// -/// This mutex will properly block tasks waiting for the lock to become -/// available. The mutex can also be statically initialized or created via a -/// `new` constructor. +/// This mutex will block threads waiting for the lock to become available. The +/// mutex can also be statically initialized or created via a `new` +/// constructor. Each mutex has a type parameter which represents the data that +/// it is protecting. The data can only be accessed through the RAII guards +/// returned from `lock` and `try_lock`, which guarantees that the data is only +/// ever accessed when the mutex is locked. +/// +/// # Poisoning +/// +/// In order to prevent access to otherwise invalid data, each mutex will +/// propagate any panics which occur while the lock is held. Once a thread has +/// panicked while holding the lock, then all other threads will immediately +/// panic as well once they hold the lock. /// /// # Example /// -/// ```rust,ignore -/// use std::sync::mutex::Mutex; +/// ```rust +/// use std::sync::{Arc, Mutex}; +/// const N: uint = 10; /// -/// let m = Mutex::new(); -/// let guard = m.lock(); -/// // do some work -/// drop(guard); // unlock the lock +/// // Spawn a few threads to increment a shared variable (non-atomically), and +/// // let the main thread know once all increments are done. +/// // +/// // Here we're using an Arc to share memory among tasks, and the data inside +/// // the Arc is protected with a mutex. +/// let data = Arc::new(Mutex::new(0)); +/// +/// let (tx, rx) = channel(); +/// for _ in range(0u, 10) { +/// let (data, tx) = (data.clone(), tx.clone()); +/// spawn(proc() { +/// // The shared static can only be accessed once the lock is held. +/// // Our non-atomic increment is safe because we're the only thread +/// // which can access the shared state when the lock is held. +/// let mut data = data.lock(); +/// *data += 1; +/// if *data == N { +/// tx.send(()); +/// } +/// // the lock is unlocked here when `data` goes out of scope. +/// }); +/// } +/// +/// rx.recv(); /// ``` -pub struct Mutex { +pub struct Mutex<T> { // Note that this static mutex is in a *box*, not inlined into the struct - // itself. This is done for memory safety reasons with the usage of a - // StaticNativeMutex inside the static mutex above. Once a native mutex has - // been used once, its address can never change (it can't be moved). This - // mutex type can be safely moved at any time, so to ensure that the native - // mutex is used correctly we box the inner lock to give it a constant - // address. - lock: Box<StaticMutex>, + // itself. Once a native mutex has been used once, its address can never + // change (it can't be moved). This mutex type can be safely moved at any + // time, so to ensure that the native mutex is used correctly we box the + // inner lock to give it a constant address. + inner: Box<StaticMutex>, + data: UnsafeCell<T>, } /// The static mutex type is provided to allow for static allocation of mutexes. @@ -57,8 +82,8 @@ pub struct Mutex { /// /// # Example /// -/// ```rust,ignore -/// use std::sync::mutex::{StaticMutex, MUTEX_INIT}; +/// ```rust +/// use std::sync::{StaticMutex, MUTEX_INIT}; /// /// static LOCK: StaticMutex = MUTEX_INIT; /// @@ -69,35 +94,113 @@ pub struct Mutex { /// // lock is unlocked here. /// ``` pub struct StaticMutex { - lock: mutex::StaticNativeMutex, + lock: sys::Mutex, + poison: UnsafeCell<poison::Flag>, } /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be access through this guard via its +/// Deref and DerefMut implementations #[must_use] -pub struct Guard<'a> { - guard: mutex::LockGuard<'a>, +pub struct MutexGuard<'a, T: 'a> { + // funny underscores due to how Deref/DerefMut currently work (they + // disregard field privacy). + __lock: &'a Mutex<T>, + __guard: StaticMutexGuard, } -fn lift_guard(guard: mutex::LockGuard) -> Guard { - Guard { guard: guard } +/// An RAII implementation of a "scoped lock" of a static mutex. When this +/// structure is dropped (falls out of scope), the lock will be unlocked. +#[must_use] +pub struct StaticMutexGuard { + lock: &'static sys::Mutex, + marker: marker::NoSend, + poison: poison::Guard<'static>, } /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. pub const MUTEX_INIT: StaticMutex = StaticMutex { - lock: mutex::NATIVE_MUTEX_INIT + lock: sys::MUTEX_INIT, + poison: UnsafeCell { value: poison::Flag { failed: false } }, }; -impl StaticMutex { - /// Attempts to grab this lock, see `Mutex::try_lock` - pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> { - unsafe { self.lock.trylock().map(lift_guard) } +impl<T: Send> Mutex<T> { + /// Creates a new mutex in an unlocked state ready for use. + pub fn new(t: T) -> Mutex<T> { + Mutex { + inner: box MUTEX_INIT, + data: UnsafeCell::new(t), + } + } + + /// Acquires a mutex, blocking the current task until it is able to do so. + /// + /// This function will block the local task until it is available to acquire + /// the mutex. Upon returning, the task is the only task with the mutex + /// held. An RAII guard is returned to allow scoped unlock of the lock. When + /// the guard goes out of scope, the mutex will be unlocked. + /// + /// # Panics + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will immediately panic once the mutex is acquired. + pub fn lock(&self) -> MutexGuard<T> { + unsafe { + let lock: &'static StaticMutex = &*(&*self.inner as *const _); + MutexGuard::new(self, lock.lock()) + } + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `None` is returned. + /// Otherwise, an RAII guard is returned. The lock will be unlocked when the + /// guard is dropped. + /// + /// This function does not block. + /// + /// # Panics + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will immediately panic if the mutex would otherwise be + /// acquired. + pub fn try_lock(&self) -> Option<MutexGuard<T>> { + unsafe { + let lock: &'static StaticMutex = &*(&*self.inner as *const _); + lock.try_lock().map(|guard| { + MutexGuard::new(self, guard) + }) + } } +} +#[unsafe_destructor] +impl<T: Send> Drop for Mutex<T> { + fn drop(&mut self) { + // This is actually safe b/c we know that there is no further usage of + // this mutex (it's up to the user to arrange for a mutex to get + // dropped, that's not our job) + unsafe { self.inner.lock.destroy() } + } +} + +impl StaticMutex { /// Acquires this lock, see `Mutex::lock` - pub fn lock<'a>(&'a self) -> Guard<'a> { - lift_guard(unsafe { self.lock.lock() }) + pub fn lock(&'static self) -> StaticMutexGuard { + unsafe { self.lock.lock() } + StaticMutexGuard::new(self) + } + + /// Attempts to grab this lock, see `Mutex::try_lock` + pub fn try_lock(&'static self) -> Option<StaticMutexGuard> { + if unsafe { self.lock.try_lock() } { + Some(StaticMutexGuard::new(self)) + } else { + None + } } /// Deallocates resources associated with this static mutex. @@ -110,58 +213,73 @@ impl StaticMutex { /// *all* platforms. It may be the case that some platforms do not leak /// memory if this method is not called, but this is not guaranteed to be /// true on all platforms. - pub unsafe fn destroy(&self) { + pub unsafe fn destroy(&'static self) { self.lock.destroy() } } -impl Mutex { - /// Creates a new mutex in an unlocked state ready for use. - pub fn new() -> Mutex { - Mutex { - lock: box StaticMutex { - lock: unsafe { mutex::StaticNativeMutex::new() }, - } - } +impl<'mutex, T> MutexGuard<'mutex, T> { + fn new(lock: &Mutex<T>, guard: StaticMutexGuard) -> MutexGuard<T> { + MutexGuard { __lock: lock, __guard: guard } } +} - /// Attempts to acquire this lock. - /// - /// If the lock could not be acquired at this time, then `None` is returned. - /// Otherwise, an RAII guard is returned. The lock will be unlocked when the - /// guard is dropped. - /// - /// This function does not block. - pub fn try_lock<'a>(&'a self) -> Option<Guard<'a>> { - self.lock.try_lock() +impl<'mutex, T> AsMutexGuard for MutexGuard<'mutex, T> { + unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { &self.__guard } +} + +impl<'mutex, T> Deref<T> for MutexGuard<'mutex, T> { + fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.__lock.data.get() } } +} +impl<'mutex, T> DerefMut<T> for MutexGuard<'mutex, T> { + fn deref_mut<'a>(&'a mut self) -> &'a mut T { + unsafe { &mut *self.__lock.data.get() } } +} - /// Acquires a mutex, blocking the current task until it is able to do so. - /// - /// This function will block the local task until it is available to acquire - /// the mutex. Upon returning, the task is the only task with the mutex - /// held. An RAII guard is returned to allow scoped unlock of the lock. When - /// the guard goes out of scope, the mutex will be unlocked. - pub fn lock<'a>(&'a self) -> Guard<'a> { self.lock.lock() } +impl StaticMutexGuard { + fn new(lock: &'static StaticMutex) -> StaticMutexGuard { + unsafe { + let guard = StaticMutexGuard { + lock: &lock.lock, + marker: marker::NoSend, + poison: (*lock.poison.get()).borrow(), + }; + guard.poison.check("mutex"); + return guard; + } + } +} + +pub fn guard_lock(guard: &StaticMutexGuard) -> &sys::Mutex { guard.lock } +pub fn guard_poison(guard: &StaticMutexGuard) -> &poison::Guard { + &guard.poison +} + +impl AsMutexGuard for StaticMutexGuard { + unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { self } } -impl Drop for Mutex { +#[unsafe_destructor] +impl Drop for StaticMutexGuard { fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - unsafe { self.lock.destroy() } + unsafe { + self.poison.done(); + self.lock.unlock(); + } } } #[cfg(test)] mod test { use prelude::*; - use super::{Mutex, StaticMutex, MUTEX_INIT}; + + use task; + use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar}; #[test] fn smoke() { - let m = Mutex::new(); + let m = Mutex::new(()); drop(m.lock()); drop(m.lock()); } @@ -211,8 +329,104 @@ mod test { } #[test] - fn trylock() { - let m = Mutex::new(); + fn try_lock() { + let m = Mutex::new(()); assert!(m.try_lock().is_some()); } + + #[test] + fn test_mutex_arc_condvar() { + let arc = Arc::new((Mutex::new(false), Condvar::new())); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + spawn(proc() { + // wait until parent gets in + rx.recv(); + let &(ref lock, ref cvar) = &*arc2; + let mut lock = lock.lock(); + *lock = true; + cvar.notify_one(); + }); + + let &(ref lock, ref cvar) = &*arc; + let lock = lock.lock(); + tx.send(()); + assert!(!*lock); + while !*lock { + cvar.wait(&lock); + } + } + + #[test] + #[should_fail] + fn test_arc_condvar_poison() { + let arc = Arc::new((Mutex::new(1i), Condvar::new())); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + spawn(proc() { + rx.recv(); + let &(ref lock, ref cvar) = &*arc2; + let _g = lock.lock(); + cvar.notify_one(); + // Parent should fail when it wakes up. + panic!(); + }); + + let &(ref lock, ref cvar) = &*arc; + let lock = lock.lock(); + tx.send(()); + while *lock == 1 { + cvar.wait(&lock); + } + } + + #[test] + #[should_fail] + fn test_mutex_arc_poison() { + let arc = Arc::new(Mutex::new(1i)); + let arc2 = arc.clone(); + let _ = task::try(proc() { + let lock = arc2.lock(); + assert_eq!(*lock, 2); + }); + let lock = arc.lock(); + assert_eq!(*lock, 1); + } + + #[test] + fn test_mutex_arc_nested() { + // Tests nested mutexes and access + // to underlying data. + let arc = Arc::new(Mutex::new(1i)); + let arc2 = Arc::new(Mutex::new(arc)); + let (tx, rx) = channel(); + spawn(proc() { + let lock = arc2.lock(); + let lock2 = lock.deref().lock(); + assert_eq!(*lock2, 1); + tx.send(()); + }); + rx.recv(); + } + + #[test] + fn test_mutex_arc_access_in_unwind() { + let arc = Arc::new(Mutex::new(1i)); + let arc2 = arc.clone(); + let _ = task::try::<()>(proc() { + struct Unwinder { + i: Arc<Mutex<int>>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + *self.i.lock() += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }); + let lock = arc.lock(); + assert_eq!(*lock, 2); + } } diff --git a/src/libstd/sync/one.rs b/src/libstd/sync/once.rs index f710a6da59b..a75088120f8 100644 --- a/src/libstd/sync/one.rs +++ b/src/libstd/sync/once.rs @@ -13,12 +13,10 @@ //! This primitive is meant to be used to run one-time initialization. An //! example use case would be for initializing an FFI library. -use core::prelude::*; - -use core::int; -use core::atomic; - -use super::mutex::{StaticMutex, MUTEX_INIT}; +use int; +use mem::drop; +use sync::atomic; +use sync::{StaticMutex, MUTEX_INIT}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related @@ -27,8 +25,8 @@ use super::mutex::{StaticMutex, MUTEX_INIT}; /// /// # Example /// -/// ```rust,ignore -/// use std::sync::one::{Once, ONCE_INIT}; +/// ```rust +/// use std::sync::{Once, ONCE_INIT}; /// /// static START: Once = ONCE_INIT; /// @@ -59,7 +57,7 @@ impl Once { /// /// When this function returns, it is guaranteed that some initialization /// has run and completed (it may not be the closure specified). - pub fn doit(&self, f: ||) { + pub fn doit(&'static self, f: ||) { // Optimize common path: load is much cheaper than fetch_add. if self.cnt.load(atomic::SeqCst) < 0 { return @@ -121,6 +119,7 @@ impl Once { #[cfg(test)] mod test { use prelude::*; + use task; use super::{ONCE_INIT, Once}; diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs new file mode 100644 index 00000000000..eb46fd77147 --- /dev/null +++ b/src/libstd/sync/poison.rs @@ -0,0 +1,48 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use option::None; +use rustrt::task::Task; +use rustrt::local::Local; + +pub struct Flag { pub failed: bool } + +impl Flag { + pub fn borrow(&mut self) -> Guard { + Guard { flag: &mut self.failed, failing: failing() } + } +} + +pub struct Guard<'a> { + flag: &'a mut bool, + failing: bool, +} + +impl<'a> Guard<'a> { + pub fn check(&self, name: &str) { + if *self.flag { + panic!("poisoned {} - another task failed inside", name); + } + } + + pub fn done(&mut self) { + if !self.failing && failing() { + *self.flag = true; + } + } +} + +fn failing() -> bool { + if Local::exists(None::<Task>) { + Local::borrow(None::<Task>).unwinder.unwinding() + } else { + false + } +} diff --git a/src/libstd/sync/raw.rs b/src/libstd/sync/raw.rs deleted file mode 100644 index 47580a11513..00000000000 --- a/src/libstd/sync/raw.rs +++ /dev/null @@ -1,1132 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Raw concurrency primitives you know and love. -//! -//! These primitives are not recommended for general use, but are provided for -//! flavorful use-cases. It is recommended to use the types at the top of the -//! `sync` crate which wrap values directly and provide safer abstractions for -//! containing data. - -// A side-effect of merging libsync into libstd; will go away once -// libsync rewrite lands -#![allow(dead_code)] - -use core::prelude::*; -use self::ReacquireOrderLock::*; - -use core::atomic; -use core::finally::Finally; -use core::kinds::marker; -use core::mem; -use core::cell::UnsafeCell; -use vec::Vec; - -use super::mutex; -use comm::{Receiver, Sender, channel}; - -// Each waiting task receives on one of these. -type WaitEnd = Receiver<()>; -type SignalEnd = Sender<()>; -// A doubly-ended queue of waiting tasks. -struct WaitQueue { - head: Receiver<SignalEnd>, - tail: Sender<SignalEnd>, -} - -impl WaitQueue { - fn new() -> WaitQueue { - let (block_tail, block_head) = channel(); - WaitQueue { head: block_head, tail: block_tail } - } - - // Signals one live task from the queue. - fn signal(&self) -> bool { - match self.head.try_recv() { - Ok(ch) => { - // Send a wakeup signal. If the waiter was killed, its port will - // have closed. Keep trying until we get a live task. - if ch.send_opt(()).is_ok() { - true - } else { - self.signal() - } - } - _ => false - } - } - - fn broadcast(&self) -> uint { - let mut count = 0; - loop { - match self.head.try_recv() { - Ok(ch) => { - if ch.send_opt(()).is_ok() { - count += 1; - } - } - _ => break - } - } - count - } - - fn wait_end(&self) -> WaitEnd { - let (signal_end, wait_end) = channel(); - self.tail.send(signal_end); - wait_end - } -} - -// The building-block used to make semaphores, mutexes, and rwlocks. -struct Sem<Q> { - lock: mutex::Mutex, - // n.b, we need Sem to be `Sync`, but the WaitQueue type is not send/share - // (for good reason). We have an internal invariant on this semaphore, - // however, that the queue is never accessed outside of a locked - // context. - inner: UnsafeCell<SemInner<Q>> -} - -struct SemInner<Q> { - count: int, - waiters: WaitQueue, - // Can be either unit or another waitqueue. Some sems shouldn't come with - // a condition variable attached, others should. - blocked: Q, -} - -#[must_use] -struct SemGuard<'a, Q:'a> { - sem: &'a Sem<Q>, -} - -impl<Q: Send> Sem<Q> { - fn new(count: int, q: Q) -> Sem<Q> { - assert!(count >= 0, - "semaphores cannot be initialized with negative values"); - Sem { - lock: mutex::Mutex::new(), - inner: UnsafeCell::new(SemInner { - waiters: WaitQueue::new(), - count: count, - blocked: q, - }) - } - } - - unsafe fn with(&self, f: |&mut SemInner<Q>|) { - let _g = self.lock.lock(); - // This &mut is safe because, due to the lock, we are the only one who can touch the data - f(&mut *self.inner.get()) - } - - pub fn acquire(&self) { - unsafe { - let mut waiter_nobe = None; - self.with(|state| { - state.count -= 1; - if state.count < 0 { - // Create waiter nobe, enqueue ourself, and tell - // outer scope we need to block. - waiter_nobe = Some(state.waiters.wait_end()); - } - }); - // Uncomment if you wish to test for sem races. Not - // valgrind-friendly. - /* for _ in range(0u, 1000) { task::deschedule(); } */ - // Need to wait outside the exclusive. - if waiter_nobe.is_some() { - let _ = waiter_nobe.unwrap().recv(); - } - } - } - - pub fn release(&self) { - unsafe { - self.with(|state| { - state.count += 1; - if state.count <= 0 { - state.waiters.signal(); - } - }) - } - } - - pub fn access<'a>(&'a self) -> SemGuard<'a, Q> { - self.acquire(); - SemGuard { sem: self } - } -} - -#[unsafe_destructor] -impl<'a, Q: Send> Drop for SemGuard<'a, Q> { - fn drop(&mut self) { - self.sem.release(); - } -} - -impl Sem<Vec<WaitQueue>> { - fn new_and_signal(count: int, num_condvars: uint) -> Sem<Vec<WaitQueue>> { - let mut queues = Vec::new(); - for _ in range(0, num_condvars) { queues.push(WaitQueue::new()); } - Sem::new(count, queues) - } - - // The only other places that condvars get built are rwlock.write_cond() - // and rwlock_write_mode. - pub fn access_cond<'a>(&'a self) -> SemCondGuard<'a> { - SemCondGuard { - guard: self.access(), - cvar: Condvar { sem: self, order: Nothing, nocopy: marker::NoCopy }, - } - } -} - -// FIXME(#3598): Want to use an Option down below, but we need a custom enum -// that's not polymorphic to get around the fact that lifetimes are invariant -// inside of type parameters. -enum ReacquireOrderLock<'a> { - Nothing, // c.c - Just(&'a Semaphore), -} - -/// A mechanism for atomic-unlock-and-deschedule blocking and signalling. -pub struct Condvar<'a> { - // The 'Sem' object associated with this condvar. This is the one that's - // atomically-unlocked-and-descheduled upon and reacquired during wakeup. - sem: &'a Sem<Vec<WaitQueue> >, - // This is (can be) an extra semaphore which is held around the reacquire - // operation on the first one. This is only used in cvars associated with - // rwlocks, and is needed to ensure that, when a downgrader is trying to - // hand off the access lock (which would be the first field, here), a 2nd - // writer waking up from a cvar wait can't race with a reader to steal it, - // See the comment in write_cond for more detail. - order: ReacquireOrderLock<'a>, - // Make sure condvars are non-copyable. - nocopy: marker::NoCopy, -} - -impl<'a> Condvar<'a> { - /// Atomically drop the associated lock, and block until a signal is sent. - /// - /// # Panics - /// - /// A task which is killed while waiting on a condition variable will wake - /// up, panic, and unlock the associated lock as it unwinds. - pub fn wait(&self) { self.wait_on(0) } - - /// As wait(), but can specify which of multiple condition variables to - /// wait on. Only a signal_on() or broadcast_on() with the same condvar_id - /// will wake this thread. - /// - /// The associated lock must have been initialised with an appropriate - /// number of condvars. The condvar_id must be between 0 and num_condvars-1 - /// or else this call will panic. - /// - /// wait() is equivalent to wait_on(0). - pub fn wait_on(&self, condvar_id: uint) { - let mut wait_end = None; - let mut out_of_bounds = None; - // Release lock, 'atomically' enqueuing ourselves in so doing. - unsafe { - self.sem.with(|state| { - if condvar_id < state.blocked.len() { - // Drop the lock. - state.count += 1; - if state.count <= 0 { - state.waiters.signal(); - } - // Create waiter nobe, and enqueue ourself to - // be woken up by a signaller. - wait_end = Some(state.blocked[condvar_id].wait_end()); - } else { - out_of_bounds = Some(state.blocked.len()); - } - }) - } - - // If deschedule checks start getting inserted anywhere, we can be - // killed before or after enqueueing. - check_cvar_bounds(out_of_bounds, condvar_id, "cond.wait_on()", || { - // Unconditionally "block". (Might not actually block if a - // signaller already sent -- I mean 'unconditionally' in contrast - // with acquire().) - (|| { - let _ = wait_end.take().unwrap().recv(); - }).finally(|| { - // Reacquire the condvar. - match self.order { - Just(lock) => { - let _g = lock.access(); - self.sem.acquire(); - } - Nothing => self.sem.acquire(), - } - }) - }) - } - - /// Wake up a blocked task. Returns false if there was no blocked task. - pub fn signal(&self) -> bool { self.signal_on(0) } - - /// As signal, but with a specified condvar_id. See wait_on. - pub fn signal_on(&self, condvar_id: uint) -> bool { - unsafe { - let mut out_of_bounds = None; - let mut result = false; - self.sem.with(|state| { - if condvar_id < state.blocked.len() { - result = state.blocked[condvar_id].signal(); - } else { - out_of_bounds = Some(state.blocked.len()); - } - }); - check_cvar_bounds(out_of_bounds, - condvar_id, - "cond.signal_on()", - || result) - } - } - - /// Wake up all blocked tasks. Returns the number of tasks woken. - pub fn broadcast(&self) -> uint { self.broadcast_on(0) } - - /// As broadcast, but with a specified condvar_id. See wait_on. - pub fn broadcast_on(&self, condvar_id: uint) -> uint { - let mut out_of_bounds = None; - let mut queue = None; - unsafe { - self.sem.with(|state| { - if condvar_id < state.blocked.len() { - // To avoid :broadcast_heavy, we make a new waitqueue, - // swap it out with the old one, and broadcast on the - // old one outside of the little-lock. - queue = Some(mem::replace(&mut state.blocked[condvar_id], - WaitQueue::new())); - } else { - out_of_bounds = Some(state.blocked.len()); - } - }); - check_cvar_bounds(out_of_bounds, - condvar_id, - "cond.signal_on()", - || { - queue.take().unwrap().broadcast() - }) - } - } -} - -// Checks whether a condvar ID was out of bounds, and panics if so, or does -// something else next on success. -#[inline] -fn check_cvar_bounds<U>( - out_of_bounds: Option<uint>, - id: uint, - act: &str, - blk: || -> U) - -> U { - match out_of_bounds { - Some(0) => - panic!("{} with illegal ID {} - this lock has no condvars!", act, id), - Some(length) => - panic!("{} with illegal ID {} - ID must be less than {}", act, id, length), - None => blk() - } -} - -#[must_use] -struct SemCondGuard<'a> { - guard: SemGuard<'a, Vec<WaitQueue>>, - cvar: Condvar<'a>, -} - -/// A counting, blocking, bounded-waiting semaphore. -pub struct Semaphore { - sem: Sem<()>, -} - -/// An RAII guard used to represent an acquired resource to a semaphore. When -/// dropped, this value will release the resource back to the semaphore. -#[must_use] -pub struct SemaphoreGuard<'a> { - _guard: SemGuard<'a, ()>, -} - -impl Semaphore { - /// Create a new semaphore with the specified count. - /// - /// # Panics - /// - /// This function will panic if `count` is negative. - pub fn new(count: int) -> Semaphore { - Semaphore { sem: Sem::new(count, ()) } - } - - /// Acquire a resource represented by the semaphore. Blocks if necessary - /// until resource(s) become available. - pub fn acquire(&self) { self.sem.acquire() } - - /// Release a held resource represented by the semaphore. Wakes a blocked - /// contending task, if any exist. Won't block the caller. - pub fn release(&self) { self.sem.release() } - - /// Acquire a resource of this semaphore, returning an RAII guard which will - /// release the resource when dropped. - pub fn access<'a>(&'a self) -> SemaphoreGuard<'a> { - SemaphoreGuard { _guard: self.sem.access() } - } -} - -/// A blocking, bounded-waiting, mutual exclusion lock with an associated -/// FIFO condition variable. -/// -/// # Panics -/// -/// A task which panicks while holding a mutex will unlock the mutex as it -/// unwinds. -pub struct Mutex { - sem: Sem<Vec<WaitQueue>>, -} - -/// An RAII structure which is used to gain access to a mutex's condition -/// variable. Additionally, when a value of this type is dropped, the -/// corresponding mutex is also unlocked. -#[must_use] -pub struct MutexGuard<'a> { - _guard: SemGuard<'a, Vec<WaitQueue>>, - /// Inner condition variable which is connected to the outer mutex, and can - /// be used for atomic-unlock-and-deschedule. - pub cond: Condvar<'a>, -} - -impl Mutex { - /// Create a new mutex, with one associated condvar. - pub fn new() -> Mutex { Mutex::new_with_condvars(1) } - - /// Create a new mutex, with a specified number of associated condvars. This - /// will allow calling wait_on/signal_on/broadcast_on with condvar IDs - /// between 0 and num_condvars-1. (If num_condvars is 0, lock_cond will be - /// allowed but any operations on the condvar will panic.) - pub fn new_with_condvars(num_condvars: uint) -> Mutex { - Mutex { sem: Sem::new_and_signal(1, num_condvars) } - } - - /// Acquires ownership of this mutex, returning an RAII guard which will - /// unlock the mutex when dropped. The associated condition variable can - /// also be accessed through the returned guard. - pub fn lock<'a>(&'a self) -> MutexGuard<'a> { - let SemCondGuard { guard, cvar } = self.sem.access_cond(); - MutexGuard { _guard: guard, cond: cvar } - } -} - -// NB: Wikipedia - Readers-writers_problem#The_third_readers-writers_problem - -/// A blocking, no-starvation, reader-writer lock with an associated condvar. -/// -/// # Panics -/// -/// A task which panics while holding an rwlock will unlock the rwlock as it -/// unwinds. -pub struct RWLock { - order_lock: Semaphore, - access_lock: Sem<Vec<WaitQueue>>, - - // The only way the count flag is ever accessed is with xadd. Since it is - // a read-modify-write operation, multiple xadds on different cores will - // always be consistent with respect to each other, so a monotonic/relaxed - // consistency ordering suffices (i.e., no extra barriers are needed). - // - // FIXME(#6598): The atomics module has no relaxed ordering flag, so I use - // acquire/release orderings superfluously. Change these someday. - read_count: atomic::AtomicUint, -} - -/// An RAII helper which is created by acquiring a read lock on an RWLock. When -/// dropped, this will unlock the RWLock. -#[must_use] -pub struct RWLockReadGuard<'a> { - lock: &'a RWLock, -} - -/// An RAII helper which is created by acquiring a write lock on an RWLock. When -/// dropped, this will unlock the RWLock. -/// -/// A value of this type can also be consumed to downgrade to a read-only lock. -#[must_use] -pub struct RWLockWriteGuard<'a> { - lock: &'a RWLock, - /// Inner condition variable that is connected to the write-mode of the - /// outer rwlock. - pub cond: Condvar<'a>, -} - -impl RWLock { - /// Create a new rwlock, with one associated condvar. - pub fn new() -> RWLock { RWLock::new_with_condvars(1) } - - /// Create a new rwlock, with a specified number of associated condvars. - /// Similar to mutex_with_condvars. - pub fn new_with_condvars(num_condvars: uint) -> RWLock { - RWLock { - order_lock: Semaphore::new(1), - access_lock: Sem::new_and_signal(1, num_condvars), - read_count: atomic::AtomicUint::new(0), - } - } - - /// Acquires a read-lock, returning an RAII guard that will unlock the lock - /// when dropped. Calls to 'read' from other tasks may run concurrently with - /// this one. - pub fn read<'a>(&'a self) -> RWLockReadGuard<'a> { - let _guard = self.order_lock.access(); - let old_count = self.read_count.fetch_add(1, atomic::Acquire); - if old_count == 0 { - self.access_lock.acquire(); - } - RWLockReadGuard { lock: self } - } - - /// Acquire a write-lock, returning an RAII guard that will unlock the lock - /// when dropped. No calls to 'read' or 'write' from other tasks will run - /// concurrently with this one. - /// - /// You can also downgrade a write to a read by calling the `downgrade` - /// method on the returned guard. Additionally, the guard will contain a - /// `Condvar` attached to this lock. - /// - /// # Example - /// - /// ```{rust,ignore} - /// use std::sync::raw::RWLock; - /// - /// let lock = RWLock::new(); - /// let write = lock.write(); - /// // ... exclusive access ... - /// let read = write.downgrade(); - /// // ... shared access ... - /// drop(read); - /// ``` - pub fn write<'a>(&'a self) -> RWLockWriteGuard<'a> { - let _g = self.order_lock.access(); - self.access_lock.acquire(); - - // It's important to thread our order lock into the condvar, so that - // when a cond.wait() wakes up, it uses it while reacquiring the - // access lock. If we permitted a waking-up writer to "cut in line", - // there could arise a subtle race when a downgrader attempts to hand - // off the reader cloud lock to a waiting reader. This race is tested - // in arc.rs (test_rw_write_cond_downgrade_read_race) and looks like: - // T1 (writer) T2 (downgrader) T3 (reader) - // [in cond.wait()] - // [locks for writing] - // [holds access_lock] - // [is signalled, perhaps by - // downgrader or a 4th thread] - // tries to lock access(!) - // lock order_lock - // xadd read_count[0->1] - // tries to lock access - // [downgrade] - // xadd read_count[1->2] - // unlock access - // Since T1 contended on the access lock before T3 did, it will steal - // the lock handoff. Adding order_lock in the condvar reacquire path - // solves this because T1 will hold order_lock while waiting on access, - // which will cause T3 to have to wait until T1 finishes its write, - // which can't happen until T2 finishes the downgrade-read entirely. - // The astute reader will also note that making waking writers use the - // order_lock is better for not starving readers. - RWLockWriteGuard { - lock: self, - cond: Condvar { - sem: &self.access_lock, - order: Just(&self.order_lock), - nocopy: marker::NoCopy, - } - } - } -} - -impl<'a> RWLockWriteGuard<'a> { - /// Consumes this write lock and converts it into a read lock. - pub fn downgrade(self) -> RWLockReadGuard<'a> { - let lock = self.lock; - // Don't run the destructor of the write guard, we're in charge of - // things from now on - unsafe { mem::forget(self) } - - let old_count = lock.read_count.fetch_add(1, atomic::Release); - // If another reader was already blocking, we need to hand-off - // the "reader cloud" access lock to them. - if old_count != 0 { - // Guaranteed not to let another writer in, because - // another reader was holding the order_lock. Hence they - // must be the one to get the access_lock (because all - // access_locks are acquired with order_lock held). See - // the comment in write_cond for more justification. - lock.access_lock.release(); - } - RWLockReadGuard { lock: lock } - } -} - -#[unsafe_destructor] -impl<'a> Drop for RWLockWriteGuard<'a> { - fn drop(&mut self) { - self.lock.access_lock.release(); - } -} - -#[unsafe_destructor] -impl<'a> Drop for RWLockReadGuard<'a> { - fn drop(&mut self) { - let old_count = self.lock.read_count.fetch_sub(1, atomic::Release); - assert!(old_count > 0); - if old_count == 1 { - // Note: this release used to be outside of a locked access - // to exclusive-protected state. If this code is ever - // converted back to such (instead of using atomic ops), - // this access MUST NOT go inside the exclusive access. - self.lock.access_lock.release(); - } - } -} - -#[cfg(test)] -mod tests { - pub use self::RWLockMode::*; - - use sync::Arc; - use prelude::*; - use super::{Semaphore, Mutex, RWLock, Condvar}; - - use mem; - use result; - use task; - - #[test] - fn test_sem_acquire_release() { - let s = Semaphore::new(1); - s.acquire(); - s.release(); - s.acquire(); - } - - #[test] - fn test_sem_basic() { - let s = Semaphore::new(1); - let _g = s.access(); - } - - #[test] - #[should_fail] - fn test_sem_basic2() { - Semaphore::new(-1); - } - - #[test] - fn test_sem_as_mutex() { - let s = Arc::new(Semaphore::new(1)); - let s2 = s.clone(); - task::spawn(proc() { - let _g = s2.access(); - for _ in range(0u, 5) { task::deschedule(); } - }); - let _g = s.access(); - for _ in range(0u, 5) { task::deschedule(); } - } - - #[test] - fn test_sem_as_cvar() { - /* Child waits and parent signals */ - let (tx, rx) = channel(); - let s = Arc::new(Semaphore::new(0)); - let s2 = s.clone(); - task::spawn(proc() { - s2.acquire(); - tx.send(()); - }); - for _ in range(0u, 5) { task::deschedule(); } - s.release(); - let _ = rx.recv(); - - /* Parent waits and child signals */ - let (tx, rx) = channel(); - let s = Arc::new(Semaphore::new(0)); - let s2 = s.clone(); - task::spawn(proc() { - for _ in range(0u, 5) { task::deschedule(); } - s2.release(); - let _ = rx.recv(); - }); - s.acquire(); - tx.send(()); - } - - #[test] - fn test_sem_multi_resource() { - // Parent and child both get in the critical section at the same - // time, and shake hands. - let s = Arc::new(Semaphore::new(2)); - let s2 = s.clone(); - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - task::spawn(proc() { - let _g = s2.access(); - let _ = rx2.recv(); - tx1.send(()); - }); - let _g = s.access(); - tx2.send(()); - let _ = rx1.recv(); - } - - #[test] - fn test_sem_runtime_friendly_blocking() { - // Force the runtime to schedule two threads on the same sched_loop. - // When one blocks, it should schedule the other one. - let s = Arc::new(Semaphore::new(1)); - let s2 = s.clone(); - let (tx, rx) = channel(); - { - let _g = s.access(); - task::spawn(proc() { - tx.send(()); - drop(s2.access()); - tx.send(()); - }); - rx.recv(); // wait for child to come alive - for _ in range(0u, 5) { task::deschedule(); } // let the child contend - } - rx.recv(); // wait for child to be done - } - - #[test] - fn test_mutex_lock() { - // Unsafely achieve shared state, and do the textbook - // "load tmp = move ptr; inc tmp; store ptr <- tmp" dance. - let (tx, rx) = channel(); - let m = Arc::new(Mutex::new()); - let m2 = m.clone(); - let mut sharedstate = box 0; - { - let ptr: *mut int = &mut *sharedstate; - task::spawn(proc() { - access_shared(ptr, &m2, 10); - tx.send(()); - }); - } - { - access_shared(&mut *sharedstate, &m, 10); - let _ = rx.recv(); - - assert_eq!(*sharedstate, 20); - } - - fn access_shared(sharedstate: *mut int, m: &Arc<Mutex>, n: uint) { - for _ in range(0u, n) { - let _g = m.lock(); - let oldval = unsafe { *sharedstate }; - task::deschedule(); - unsafe { *sharedstate = oldval + 1; } - } - } - } - - #[test] - fn test_mutex_cond_wait() { - let m = Arc::new(Mutex::new()); - - // Child wakes up parent - { - let lock = m.lock(); - let m2 = m.clone(); - task::spawn(proc() { - let lock = m2.lock(); - let woken = lock.cond.signal(); - assert!(woken); - }); - lock.cond.wait(); - } - // Parent wakes up child - let (tx, rx) = channel(); - let m3 = m.clone(); - task::spawn(proc() { - let lock = m3.lock(); - tx.send(()); - lock.cond.wait(); - tx.send(()); - }); - rx.recv(); // Wait until child gets in the mutex - { - let lock = m.lock(); - let woken = lock.cond.signal(); - assert!(woken); - } - rx.recv(); // Wait until child wakes up - } - - fn test_mutex_cond_broadcast_helper(num_waiters: uint) { - let m = Arc::new(Mutex::new()); - let mut rxs = Vec::new(); - - for _ in range(0u, num_waiters) { - let mi = m.clone(); - let (tx, rx) = channel(); - rxs.push(rx); - task::spawn(proc() { - let lock = mi.lock(); - tx.send(()); - lock.cond.wait(); - tx.send(()); - }); - } - - // wait until all children get in the mutex - for rx in rxs.iter_mut() { rx.recv(); } - { - let lock = m.lock(); - let num_woken = lock.cond.broadcast(); - assert_eq!(num_woken, num_waiters); - } - // wait until all children wake up - for rx in rxs.iter_mut() { rx.recv(); } - } - - #[test] - fn test_mutex_cond_broadcast() { - test_mutex_cond_broadcast_helper(12); - } - - #[test] - fn test_mutex_cond_broadcast_none() { - test_mutex_cond_broadcast_helper(0); - } - - #[test] - fn test_mutex_cond_no_waiter() { - let m = Arc::new(Mutex::new()); - let m2 = m.clone(); - let _ = task::try(proc() { - drop(m.lock()); - }); - let lock = m2.lock(); - assert!(!lock.cond.signal()); - } - - #[test] - fn test_mutex_killed_simple() { - use any::Any; - - // Mutex must get automatically unlocked if panicked/killed within. - let m = Arc::new(Mutex::new()); - let m2 = m.clone(); - - let result: result::Result<(), Box<Any + Send>> = task::try(proc() { - let _lock = m2.lock(); - panic!(); - }); - assert!(result.is_err()); - // child task must have finished by the time try returns - drop(m.lock()); - } - - #[test] - fn test_mutex_cond_signal_on_0() { - // Tests that signal_on(0) is equivalent to signal(). - let m = Arc::new(Mutex::new()); - let lock = m.lock(); - let m2 = m.clone(); - task::spawn(proc() { - let lock = m2.lock(); - lock.cond.signal_on(0); - }); - lock.cond.wait(); - } - - #[test] - fn test_mutex_no_condvars() { - let result = task::try(proc() { - let m = Mutex::new_with_condvars(0); - m.lock().cond.wait(); - }); - assert!(result.is_err()); - let result = task::try(proc() { - let m = Mutex::new_with_condvars(0); - m.lock().cond.signal(); - }); - assert!(result.is_err()); - let result = task::try(proc() { - let m = Mutex::new_with_condvars(0); - m.lock().cond.broadcast(); - }); - assert!(result.is_err()); - } - - #[cfg(test)] - pub enum RWLockMode { Read, Write, Downgrade, DowngradeRead } - - #[cfg(test)] - fn lock_rwlock_in_mode(x: &Arc<RWLock>, mode: RWLockMode, blk: ||) { - match mode { - Read => { let _g = x.read(); blk() } - Write => { let _g = x.write(); blk() } - Downgrade => { let _g = x.write(); blk() } - DowngradeRead => { let _g = x.write().downgrade(); blk() } - } - } - - #[cfg(test)] - fn test_rwlock_exclusion(x: Arc<RWLock>, - mode1: RWLockMode, - mode2: RWLockMode) { - // Test mutual exclusion between readers and writers. Just like the - // mutex mutual exclusion test, a ways above. - let (tx, rx) = channel(); - let x2 = x.clone(); - let mut sharedstate = box 0; - { - let ptr: *const int = &*sharedstate; - task::spawn(proc() { - let sharedstate: &mut int = - unsafe { mem::transmute(ptr) }; - access_shared(sharedstate, &x2, mode1, 10); - tx.send(()); - }); - } - { - access_shared(&mut *sharedstate, &x, mode2, 10); - let _ = rx.recv(); - - assert_eq!(*sharedstate, 20); - } - - fn access_shared(sharedstate: &mut int, x: &Arc<RWLock>, - mode: RWLockMode, n: uint) { - for _ in range(0u, n) { - lock_rwlock_in_mode(x, mode, || { - let oldval = *sharedstate; - task::deschedule(); - *sharedstate = oldval + 1; - }) - } - } - } - - #[test] - fn test_rwlock_readers_wont_modify_the_data() { - test_rwlock_exclusion(Arc::new(RWLock::new()), Read, Write); - test_rwlock_exclusion(Arc::new(RWLock::new()), Write, Read); - test_rwlock_exclusion(Arc::new(RWLock::new()), Read, Downgrade); - test_rwlock_exclusion(Arc::new(RWLock::new()), Downgrade, Read); - test_rwlock_exclusion(Arc::new(RWLock::new()), Write, DowngradeRead); - test_rwlock_exclusion(Arc::new(RWLock::new()), DowngradeRead, Write); - } - - #[test] - fn test_rwlock_writers_and_writers() { - test_rwlock_exclusion(Arc::new(RWLock::new()), Write, Write); - test_rwlock_exclusion(Arc::new(RWLock::new()), Write, Downgrade); - test_rwlock_exclusion(Arc::new(RWLock::new()), Downgrade, Write); - test_rwlock_exclusion(Arc::new(RWLock::new()), Downgrade, Downgrade); - } - - #[cfg(test)] - fn test_rwlock_handshake(x: Arc<RWLock>, - mode1: RWLockMode, - mode2: RWLockMode, - make_mode2_go_first: bool) { - // Much like sem_multi_resource. - let x2 = x.clone(); - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - task::spawn(proc() { - if !make_mode2_go_first { - rx2.recv(); // parent sends to us once it locks, or ... - } - lock_rwlock_in_mode(&x2, mode2, || { - if make_mode2_go_first { - tx1.send(()); // ... we send to it once we lock - } - rx2.recv(); - tx1.send(()); - }) - }); - if make_mode2_go_first { - rx1.recv(); // child sends to us once it locks, or ... - } - lock_rwlock_in_mode(&x, mode1, || { - if !make_mode2_go_first { - tx2.send(()); // ... we send to it once we lock - } - tx2.send(()); - rx1.recv(); - }) - } - - #[test] - fn test_rwlock_readers_and_readers() { - test_rwlock_handshake(Arc::new(RWLock::new()), Read, Read, false); - // The downgrader needs to get in before the reader gets in, otherwise - // they cannot end up reading at the same time. - test_rwlock_handshake(Arc::new(RWLock::new()), DowngradeRead, Read, false); - test_rwlock_handshake(Arc::new(RWLock::new()), Read, DowngradeRead, true); - // Two downgrade_reads can never both end up reading at the same time. - } - - #[test] - fn test_rwlock_downgrade_unlock() { - // Tests that downgrade can unlock the lock in both modes - let x = Arc::new(RWLock::new()); - lock_rwlock_in_mode(&x, Downgrade, || { }); - test_rwlock_handshake(x, Read, Read, false); - let y = Arc::new(RWLock::new()); - lock_rwlock_in_mode(&y, DowngradeRead, || { }); - test_rwlock_exclusion(y, Write, Write); - } - - #[test] - fn test_rwlock_read_recursive() { - let x = RWLock::new(); - let _g1 = x.read(); - let _g2 = x.read(); - } - - #[test] - fn test_rwlock_cond_wait() { - // As test_mutex_cond_wait above. - let x = Arc::new(RWLock::new()); - - // Child wakes up parent - { - let lock = x.write(); - let x2 = x.clone(); - task::spawn(proc() { - let lock = x2.write(); - assert!(lock.cond.signal()); - }); - lock.cond.wait(); - } - // Parent wakes up child - let (tx, rx) = channel(); - let x3 = x.clone(); - task::spawn(proc() { - let lock = x3.write(); - tx.send(()); - lock.cond.wait(); - tx.send(()); - }); - rx.recv(); // Wait until child gets in the rwlock - drop(x.read()); // Must be able to get in as a reader - { - let x = x.write(); - assert!(x.cond.signal()); - } - rx.recv(); // Wait until child wakes up - drop(x.read()); // Just for good measure - } - - #[cfg(test)] - fn test_rwlock_cond_broadcast_helper(num_waiters: uint) { - // Much like the mutex broadcast test. Downgrade-enabled. - fn lock_cond(x: &Arc<RWLock>, blk: |c: &Condvar|) { - let lock = x.write(); - blk(&lock.cond); - } - - let x = Arc::new(RWLock::new()); - let mut rxs = Vec::new(); - - for _ in range(0u, num_waiters) { - let xi = x.clone(); - let (tx, rx) = channel(); - rxs.push(rx); - task::spawn(proc() { - lock_cond(&xi, |cond| { - tx.send(()); - cond.wait(); - tx.send(()); - }) - }); - } - - // wait until all children get in the mutex - for rx in rxs.iter_mut() { let _ = rx.recv(); } - lock_cond(&x, |cond| { - let num_woken = cond.broadcast(); - assert_eq!(num_woken, num_waiters); - }); - // wait until all children wake up - for rx in rxs.iter_mut() { let _ = rx.recv(); } - } - - #[test] - fn test_rwlock_cond_broadcast() { - test_rwlock_cond_broadcast_helper(0); - test_rwlock_cond_broadcast_helper(12); - } - - #[cfg(test)] - fn rwlock_kill_helper(mode1: RWLockMode, mode2: RWLockMode) { - use any::Any; - - // Mutex must get automatically unlocked if panicked/killed within. - let x = Arc::new(RWLock::new()); - let x2 = x.clone(); - - let result: result::Result<(), Box<Any + Send>> = task::try(proc() { - lock_rwlock_in_mode(&x2, mode1, || { - panic!(); - }) - }); - assert!(result.is_err()); - // child task must have finished by the time try returns - lock_rwlock_in_mode(&x, mode2, || { }) - } - - #[test] - fn test_rwlock_reader_killed_writer() { - rwlock_kill_helper(Read, Write); - } - - #[test] - fn test_rwlock_writer_killed_reader() { - rwlock_kill_helper(Write, Read); - } - - #[test] - fn test_rwlock_reader_killed_reader() { - rwlock_kill_helper(Read, Read); - } - - #[test] - fn test_rwlock_writer_killed_writer() { - rwlock_kill_helper(Write, Write); - } - - #[test] - fn test_rwlock_kill_downgrader() { - rwlock_kill_helper(Downgrade, Read); - rwlock_kill_helper(Read, Downgrade); - rwlock_kill_helper(Downgrade, Write); - rwlock_kill_helper(Write, Downgrade); - rwlock_kill_helper(DowngradeRead, Read); - rwlock_kill_helper(Read, DowngradeRead); - rwlock_kill_helper(DowngradeRead, Write); - rwlock_kill_helper(Write, DowngradeRead); - rwlock_kill_helper(DowngradeRead, Downgrade); - rwlock_kill_helper(DowngradeRead, Downgrade); - rwlock_kill_helper(Downgrade, DowngradeRead); - rwlock_kill_helper(Downgrade, DowngradeRead); - } -} diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs new file mode 100644 index 00000000000..a4f8b1df6af --- /dev/null +++ b/src/libstd/sync/rwlock.rs @@ -0,0 +1,514 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; + +use kinds::marker; +use cell::UnsafeCell; +use sys_common::rwlock as sys; +use sync::poison; + +/// A reader-writer lock +/// +/// This type of lock allows a number of readers or at most one writer at any +/// point in time. The write portion of this lock typically allows modification +/// of the underlying data (exclusive access) and the read portion of this lock +/// typically allows for read-only access (shared access). +/// +/// The type parameter `T` represents the data that this lock protects. It is +/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to +/// allow concurrent access through readers. The RAII guards returned from the +/// locking methods implement `Deref` (and `DerefMut` for the `write` methods) +/// to allow access to the contained of the lock. +/// +/// RWLocks, like Mutexes, will become poisoned on panics. Note, however, that +/// an RWLock may only be poisoned if a panic occurs while it is locked +/// exclusively (write mode). If a panic occurs in any reader, then the lock +/// will not be poisoned. +/// +/// # Example +/// +/// ``` +/// use std::sync::RWLock; +/// +/// let lock = RWLock::new(5i); +/// +/// // many reader locks can be held at once +/// { +/// let r1 = lock.read(); +/// let r2 = lock.read(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // read locks are dropped at this point +/// +/// // only one write lock may be held, however +/// { +/// let mut w = lock.write(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // write lock is dropped here +/// ``` +pub struct RWLock<T> { + inner: Box<StaticRWLock>, + data: UnsafeCell<T>, +} + +/// Structure representing a staticaly allocated RWLock. +/// +/// This structure is intended to be used inside of a `static` and will provide +/// automatic global access as well as lazy initialization. The internal +/// resources of this RWLock, however, must be manually deallocated. +/// +/// # Example +/// +/// ``` +/// use std::sync::{StaticRWLock, RWLOCK_INIT}; +/// +/// static LOCK: StaticRWLock = RWLOCK_INIT; +/// +/// { +/// let _g = LOCK.read(); +/// // ... shared read access +/// } +/// { +/// let _g = LOCK.write(); +/// // ... exclusive write access +/// } +/// unsafe { LOCK.destroy() } // free all resources +/// ``` +pub struct StaticRWLock { + inner: sys::RWLock, + poison: UnsafeCell<poison::Flag>, +} + +/// Constant initialization for a statically-initialized rwlock. +pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { + inner: sys::RWLOCK_INIT, + poison: UnsafeCell { value: poison::Flag { failed: false } }, +}; + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +#[must_use] +pub struct RWLockReadGuard<'a, T: 'a> { + __lock: &'a RWLock<T>, + __guard: StaticRWLockReadGuard, +} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped. +#[must_use] +pub struct RWLockWriteGuard<'a, T: 'a> { + __lock: &'a RWLock<T>, + __guard: StaticRWLockWriteGuard, +} + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +#[must_use] +pub struct StaticRWLockReadGuard { + lock: &'static sys::RWLock, + marker: marker::NoSend, +} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped. +#[must_use] +pub struct StaticRWLockWriteGuard { + lock: &'static sys::RWLock, + marker: marker::NoSend, + poison: poison::Guard<'static>, +} + +impl<T: Send + Sync> RWLock<T> { + /// Creates a new instance of an RWLock which is unlocked and read to go. + pub fn new(t: T) -> RWLock<T> { + RWLock { inner: box RWLOCK_INIT, data: UnsafeCell::new(t) } + } + + /// Locks this rwlock with shared read access, blocking the current thread + /// until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which + /// hold the lock. There may be other readers currently inside the lock when + /// this method returns. This method does not provide any guarantees with + /// respect to the ordering of whether contentious readers or writers will + /// acquire the lock first. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// # Panics + /// + /// This function will panic if the RWLock is poisoned. An RWLock is + /// poisoned whenever a writer panics while holding an exclusive lock. The + /// panic will occur immediately after the lock has been acquired. + #[inline] + pub fn read(&self) -> RWLockReadGuard<T> { + unsafe { + let lock: &'static StaticRWLock = &*(&*self.inner as *const _); + RWLockReadGuard::new(self, lock.read()) + } + } + + /// Attempt to acquire this lock with shared read access. + /// + /// This function will never block and will return immediately if `read` + /// would otherwise succeed. Returns `Some` of an RAII guard which will + /// release the shared access of this thread when dropped, or `None` if the + /// access could not be granted. This method does not provide any + /// guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// # Panics + /// + /// This function will panic if the RWLock is poisoned. An RWLock is + /// poisoned whenever a writer panics while holding an exclusive lock. A + /// panic will only occur if the lock is acquired. + #[inline] + pub fn try_read(&self) -> Option<RWLockReadGuard<T>> { + unsafe { + let lock: &'static StaticRWLock = &*(&*self.inner as *const _); + lock.try_read().map(|guard| { + RWLockReadGuard::new(self, guard) + }) + } + } + + /// Lock this rwlock with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// This function will not return while other writers or other readers + /// currently have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this rwlock + /// when dropped. + /// + /// # Panics + /// + /// This function will panic if the RWLock is poisoned. An RWLock is + /// poisoned whenever a writer panics while holding an exclusive lock. The + /// panic will occur when the lock is acquired. + #[inline] + pub fn write(&self) -> RWLockWriteGuard<T> { + unsafe { + let lock: &'static StaticRWLock = &*(&*self.inner as *const _); + RWLockWriteGuard::new(self, lock.write()) + } + } + + /// Attempt to lock this rwlock with exclusive write access. + /// + /// This function does not ever block, and it will return `None` if a call + /// to `write` would otherwise block. If successful, an RAII guard is + /// returned. + /// + /// # Panics + /// + /// This function will panic if the RWLock is poisoned. An RWLock is + /// poisoned whenever a writer panics while holding an exclusive lock. A + /// panic will only occur if the lock is acquired. + #[inline] + pub fn try_write(&self) -> Option<RWLockWriteGuard<T>> { + unsafe { + let lock: &'static StaticRWLock = &*(&*self.inner as *const _); + lock.try_write().map(|guard| { + RWLockWriteGuard::new(self, guard) + }) + } + } +} + +#[unsafe_destructor] +impl<T> Drop for RWLock<T> { + fn drop(&mut self) { + unsafe { self.inner.inner.destroy() } + } +} + +impl StaticRWLock { + /// Locks this rwlock with shared read access, blocking the current thread + /// until it can be acquired. + /// + /// See `RWLock::read`. + #[inline] + pub fn read(&'static self) -> StaticRWLockReadGuard { + unsafe { self.inner.read() } + StaticRWLockReadGuard::new(self) + } + + /// Attempt to acquire this lock with shared read access. + /// + /// See `RWLock::try_read`. + #[inline] + pub fn try_read(&'static self) -> Option<StaticRWLockReadGuard> { + if unsafe { self.inner.try_read() } { + Some(StaticRWLockReadGuard::new(self)) + } else { + None + } + } + + /// Lock this rwlock with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// See `RWLock::write`. + #[inline] + pub fn write(&'static self) -> StaticRWLockWriteGuard { + unsafe { self.inner.write() } + StaticRWLockWriteGuard::new(self) + } + + /// Attempt to lock this rwlock with exclusive write access. + /// + /// See `RWLock::try_write`. + #[inline] + pub fn try_write(&'static self) -> Option<StaticRWLockWriteGuard> { + if unsafe { self.inner.try_write() } { + Some(StaticRWLockWriteGuard::new(self)) + } else { + None + } + } + + /// Deallocate all resources associated with this static lock. + /// + /// This method is unsafe to call as there is no guarantee that there are no + /// active users of the lock, and this also doesn't prevent any future users + /// of this lock. This method is required to be called to not leak memory on + /// all platforms. + pub unsafe fn destroy(&'static self) { + self.inner.destroy() + } +} + +impl<'rwlock, T> RWLockReadGuard<'rwlock, T> { + fn new(lock: &RWLock<T>, guard: StaticRWLockReadGuard) + -> RWLockReadGuard<T> { + RWLockReadGuard { __lock: lock, __guard: guard } + } +} +impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> { + fn new(lock: &RWLock<T>, guard: StaticRWLockWriteGuard) + -> RWLockWriteGuard<T> { + RWLockWriteGuard { __lock: lock, __guard: guard } + } +} + +impl<'rwlock, T> Deref<T> for RWLockReadGuard<'rwlock, T> { + fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } +} +impl<'rwlock, T> Deref<T> for RWLockWriteGuard<'rwlock, T> { + fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } +} +impl<'rwlock, T> DerefMut<T> for RWLockWriteGuard<'rwlock, T> { + fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.__lock.data.get() } } +} + +impl StaticRWLockReadGuard { + fn new(lock: &'static StaticRWLock) -> StaticRWLockReadGuard { + let guard = StaticRWLockReadGuard { + lock: &lock.inner, + marker: marker::NoSend, + }; + unsafe { (*lock.poison.get()).borrow().check("rwlock"); } + return guard; + } +} +impl StaticRWLockWriteGuard { + fn new(lock: &'static StaticRWLock) -> StaticRWLockWriteGuard { + unsafe { + let guard = StaticRWLockWriteGuard { + lock: &lock.inner, + marker: marker::NoSend, + poison: (*lock.poison.get()).borrow(), + }; + guard.poison.check("rwlock"); + return guard; + } + } +} + +#[unsafe_destructor] +impl Drop for StaticRWLockReadGuard { + fn drop(&mut self) { + unsafe { self.lock.read_unlock(); } + } +} + +#[unsafe_destructor] +impl Drop for StaticRWLockWriteGuard { + fn drop(&mut self) { + self.poison.done(); + unsafe { self.lock.write_unlock(); } + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + + use rand::{mod, Rng}; + use task; + use sync::{Arc, RWLock, StaticRWLock, RWLOCK_INIT}; + + #[test] + fn smoke() { + let l = RWLock::new(()); + drop(l.read()); + drop(l.write()); + drop((l.read(), l.read())); + drop(l.write()); + } + + #[test] + fn static_smoke() { + static R: StaticRWLock = RWLOCK_INIT; + drop(R.read()); + drop(R.write()); + drop((R.read(), R.read())); + drop(R.write()); + unsafe { R.destroy(); } + } + + #[test] + fn frob() { + static R: StaticRWLock = RWLOCK_INIT; + static N: uint = 10; + static M: uint = 1000; + + let (tx, rx) = channel::<()>(); + for _ in range(0, N) { + let tx = tx.clone(); + spawn(proc() { + let mut rng = rand::task_rng(); + for _ in range(0, M) { + if rng.gen_weighted_bool(N) { + drop(R.write()); + } else { + drop(R.read()); + } + } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv_opt(); + unsafe { R.destroy(); } + } + + #[test] + #[should_fail] + fn test_rw_arc_poison_wr() { + let arc = Arc::new(RWLock::new(1i)); + let arc2 = arc.clone(); + let _ = task::try(proc() { + let lock = arc2.write(); + assert_eq!(*lock, 2); + }); + let lock = arc.read(); + assert_eq!(*lock, 1); + } + + #[test] + #[should_fail] + fn test_rw_arc_poison_ww() { + let arc = Arc::new(RWLock::new(1i)); + let arc2 = arc.clone(); + let _ = task::try(proc() { + let lock = arc2.write(); + assert_eq!(*lock, 2); + }); + let lock = arc.write(); + assert_eq!(*lock, 1); + } + + #[test] + fn test_rw_arc_no_poison_rr() { + let arc = Arc::new(RWLock::new(1i)); + let arc2 = arc.clone(); + let _ = task::try(proc() { + let lock = arc2.read(); + assert_eq!(*lock, 2); + }); + let lock = arc.read(); + assert_eq!(*lock, 1); + } + #[test] + fn test_rw_arc_no_poison_rw() { + let arc = Arc::new(RWLock::new(1i)); + let arc2 = arc.clone(); + let _ = task::try(proc() { + let lock = arc2.read(); + assert_eq!(*lock, 2); + }); + let lock = arc.write(); + assert_eq!(*lock, 1); + } + + #[test] + fn test_rw_arc() { + let arc = Arc::new(RWLock::new(0i)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + task::spawn(proc() { + let mut lock = arc2.write(); + for _ in range(0u, 10) { + let tmp = *lock; + *lock = -1; + task::deschedule(); + *lock = tmp + 1; + } + tx.send(()); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in range(0u, 5) { + let arc3 = arc.clone(); + children.push(task::try_future(proc() { + let lock = arc3.read(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children.iter_mut() { + assert!(r.get_ref().is_ok()); + } + + // Wait for writer to finish + rx.recv(); + let lock = arc.read(); + assert_eq!(*lock, 10); + } + + #[test] + fn test_rw_arc_access_in_unwind() { + let arc = Arc::new(RWLock::new(1i)); + let arc2 = arc.clone(); + let _ = task::try::<()>(proc() { + struct Unwinder { + i: Arc<RWLock<int>>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }); + let lock = arc.read(); + assert_eq!(*lock, 2); + } +} diff --git a/src/libstd/sync/semaphore.rs b/src/libstd/sync/semaphore.rs new file mode 100644 index 00000000000..03fb84c38d4 --- /dev/null +++ b/src/libstd/sync/semaphore.rs @@ -0,0 +1,195 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ops::Drop; +use sync::{Mutex, Condvar}; + +/// A counting, blocking, semaphore. +/// +/// Semaphores are a form of atomic counter where access is only granted if the +/// counter is a positive value. Each acquisition will block the calling thread +/// until the counter is positive, and each release will increment the counter +/// and unblock any threads if necessary. +/// +/// # Example +/// +/// ``` +/// use std::sync::Semaphore; +/// +/// // Create a semaphore that represents 5 resources +/// let sem = Semaphore::new(5); +/// +/// // Acquire one of the resources +/// sem.acquire(); +/// +/// // Acquire one of the resources for a limited period of time +/// { +/// let _guard = sem.access(); +/// // ... +/// } // resources is released here +/// +/// // Release our initially acquired resource +/// sem.release(); +/// ``` +pub struct Semaphore { + lock: Mutex<int>, + cvar: Condvar, +} + +/// An RAII guard which will release a resource acquired from a semaphore when +/// dropped. +pub struct SemaphoreGuard<'a> { + sem: &'a Semaphore, +} + +impl Semaphore { + /// Creates a new semaphore with the initial count specified. + /// + /// The count specified can be thought of as a number of resources, and a + /// call to `acquire` or `access` will block until at least one resource is + /// available. It is valid to initialize a semaphore with a negative count. + pub fn new(count: int) -> Semaphore { + Semaphore { + lock: Mutex::new(count), + cvar: Condvar::new(), + } + } + + /// Acquires a resource of this semaphore, blocking the current thread until + /// it can do so. + /// + /// This method will block until the internal count of the semaphore is at + /// least 1. + pub fn acquire(&self) { + let mut count = self.lock.lock(); + while *count <= 0 { + self.cvar.wait(&count); + } + *count -= 1; + } + + /// Release a resource from this semaphore. + /// + /// This will increment the number of resources in this semaphore by 1 and + /// will notify any pending waiters in `acquire` or `access` if necessary. + pub fn release(&self) { + *self.lock.lock() += 1; + self.cvar.notify_one(); + } + + /// Acquires a resource of this semaphore, returning an RAII guard to + /// release the semaphore when dropped. + /// + /// This function is semantically equivalent to an `acquire` followed by a + /// `release` when the guard returned is dropped. + pub fn access(&self) -> SemaphoreGuard { + self.acquire(); + SemaphoreGuard { sem: self } + } +} + +#[unsafe_destructor] +impl<'a> Drop for SemaphoreGuard<'a> { + fn drop(&mut self) { + self.sem.release(); + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + + use sync::Arc; + use super::Semaphore; + + #[test] + fn test_sem_acquire_release() { + let s = Semaphore::new(1); + s.acquire(); + s.release(); + s.acquire(); + } + + #[test] + fn test_sem_basic() { + let s = Semaphore::new(1); + let _g = s.access(); + } + + #[test] + fn test_sem_as_mutex() { + let s = Arc::new(Semaphore::new(1)); + let s2 = s.clone(); + spawn(proc() { + let _g = s2.access(); + }); + let _g = s.access(); + } + + #[test] + fn test_sem_as_cvar() { + /* Child waits and parent signals */ + let (tx, rx) = channel(); + let s = Arc::new(Semaphore::new(0)); + let s2 = s.clone(); + spawn(proc() { + s2.acquire(); + tx.send(()); + }); + s.release(); + let _ = rx.recv(); + + /* Parent waits and child signals */ + let (tx, rx) = channel(); + let s = Arc::new(Semaphore::new(0)); + let s2 = s.clone(); + spawn(proc() { + s2.release(); + let _ = rx.recv(); + }); + s.acquire(); + tx.send(()); + } + + #[test] + fn test_sem_multi_resource() { + // Parent and child both get in the critical section at the same + // time, and shake hands. + let s = Arc::new(Semaphore::new(2)); + let s2 = s.clone(); + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + spawn(proc() { + let _g = s2.access(); + let _ = rx2.recv(); + tx1.send(()); + }); + let _g = s.access(); + tx2.send(()); + let _ = rx1.recv(); + } + + #[test] + fn test_sem_runtime_friendly_blocking() { + let s = Arc::new(Semaphore::new(1)); + let s2 = s.clone(); + let (tx, rx) = channel(); + { + let _g = s.access(); + spawn(proc() { + tx.send(()); + drop(s2.access()); + tx.send(()); + }); + rx.recv(); // wait for child to come alive + } + rx.recv(); // wait for child to be done + } +} diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys/common/condvar.rs new file mode 100644 index 00000000000..e09d9704029 --- /dev/null +++ b/src/libstd/sys/common/condvar.rs @@ -0,0 +1,67 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use time::Duration; +use sys_common::mutex::{mod, Mutex}; +use sys::condvar as imp; + +/// An OS-based condition variable. +/// +/// This structure is the lowest layer possible on top of the OS-provided +/// condition variables. It is consequently entirely unsafe to use. It is +/// recommended to use the safer types at the top level of this crate instead of +/// this type. +pub struct Condvar(imp::Condvar); + +/// Static initializer for condition variables. +pub const CONDVAR_INIT: Condvar = Condvar(imp::CONDVAR_INIT); + +impl Condvar { + /// Creates a new condition variable for use. + /// + /// Behavior is undefined if the condition variable is moved after it is + /// first used with any of the functions below. + #[inline] + pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) } + + /// Signal one waiter on this condition variable to wake up. + #[inline] + pub unsafe fn notify_one(&self) { self.0.notify_one() } + + /// Awaken all current waiters on this condition variable. + #[inline] + pub unsafe fn notify_all(&self) { self.0.notify_all() } + + /// Wait for a signal on the specified mutex. + /// + /// Behavior is undefined if the mutex is not locked by the current thread. + /// Behavior is also undefined if more than one mutex is used concurrently + /// on this condition variable. + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) } + + /// Wait for a signal on the specified mutex with a timeout duration + /// specified by `dur` (a relative time into the future). + /// + /// Behavior is undefined if the mutex is not locked by the current thread. + /// Behavior is also undefined if more than one mutex is used concurrently + /// on this condition variable. + #[inline] + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + self.0.wait_timeout(mutex::raw(mutex), dur) + } + + /// Deallocate all resources associated with this condition variable. + /// + /// Behavior is undefined if there are current or will be future users of + /// this condition variable. + #[inline] + pub unsafe fn destroy(&self) { self.0.destroy() } +} diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 9508d8d9232..c0018c5d970 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -20,13 +20,14 @@ //! can be created in the future and there must be no active timers at that //! time. +use prelude::*; + +use cell::UnsafeCell; use mem; use rustrt::bookkeeping; -use rustrt::mutex::StaticNativeMutex; use rustrt; -use cell::UnsafeCell; +use sync::{StaticMutex, StaticCondvar}; use sys::helper_signal; -use prelude::*; use task; @@ -39,7 +40,8 @@ use task; /// is for static initialization. pub struct Helper<M> { /// Internal lock which protects the remaining fields - pub lock: StaticNativeMutex, + pub lock: StaticMutex, + pub cond: StaticCondvar, // You'll notice that the remaining fields are UnsafeCell<T>, and this is // because all helper thread operations are done through &self, but we need @@ -53,6 +55,9 @@ pub struct Helper<M> { /// Flag if this helper thread has booted and been initialized yet. pub initialized: UnsafeCell<bool>, + + /// Flag if this helper thread has shut down + pub shutdown: UnsafeCell<bool>, } impl<M: Send> Helper<M> { @@ -80,7 +85,9 @@ impl<M: Send> Helper<M> { task::spawn(proc() { bookkeeping::decrement(); helper(receive, rx, t); - self.lock.lock().signal() + let _g = self.lock.lock(); + *self.shutdown.get() = true; + self.cond.notify_one() }); rustrt::at_exit(proc() { self.shutdown() }); @@ -119,7 +126,9 @@ impl<M: Send> Helper<M> { helper_signal::signal(*self.signal.get() as helper_signal::signal); // Wait for the child to exit - guard.wait(); + while !*self.shutdown.get() { + self.cond.wait(&guard); + } drop(guard); // Clean up after ourselves diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index e382ec261a0..f8861c20464 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -19,8 +19,11 @@ use num::Int; use path::BytesContainer; use collections; -pub mod net; +pub mod condvar; pub mod helper_thread; +pub mod mutex; +pub mod net; +pub mod rwlock; pub mod thread_local; // common error constructors diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs new file mode 100644 index 00000000000..117d33db328 --- /dev/null +++ b/src/libstd/sys/common/mutex.rs @@ -0,0 +1,64 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use sys::mutex::raw; + +use sys::mutex as imp; + +/// An OS-based mutual exclusion lock. +/// +/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of +/// this mutex is unsafe and it is recommended to instead use the safe wrapper +/// at the top level of the crate instead of this type. +pub struct Mutex(imp::Mutex); + +/// Constant initializer for statically allocated mutexes. +pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT); + +impl Mutex { + /// Creates a newly initialized mutex. + /// + /// Behavior is undefined if the mutex is moved after the first method is + /// called on the mutex. + #[inline] + pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) } + + /// Lock the mutex blocking the current thread until it is available. + /// + /// Behavior is undefined if the mutex has been moved between this and any + /// previous function call. + #[inline] + pub unsafe fn lock(&self) { self.0.lock() } + + /// Attempt to lock the mutex without blocking, returning whether it was + /// successfully acquired or not. + /// + /// Behavior is undefined if the mutex has been moved between this and any + /// previous function call. + #[inline] + pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } + + /// Unlock the mutex. + /// + /// Behavior is undefined if the current thread does not actually hold the + /// mutex. + #[inline] + pub unsafe fn unlock(&self) { self.0.unlock() } + + /// Deallocate all resources associated with this mutex. + /// + /// Behavior is undefined if there are current or will be future users of + /// this mutex. + #[inline] + pub unsafe fn destroy(&self) { self.0.destroy() } +} + +// not meant to be exported to the outside world, just the containing module +pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 029fc852742..ddc6dd021c3 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -16,13 +16,13 @@ use libc::{mod, c_char, c_int}; use mem; use num::Int; use ptr::{mod, null, null_mut}; -use rustrt::mutex; use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use io::net::addrinfo; use io::{IoResult, IoError}; use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; +use sync::{Mutex, MutexGuard}; use sys_common::{mod, keep_going, short_write, timeout}; use prelude::*; use cmp; @@ -557,12 +557,12 @@ struct Inner { // Unused on Linux, where this lock is not necessary. #[allow(dead_code)] - lock: mutex::NativeMutex + lock: Mutex<()>, } impl Inner { fn new(fd: sock_t) -> Inner { - Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } } + Inner { fd: fd, lock: Mutex::new(()) } } } @@ -572,7 +572,7 @@ impl Drop for Inner { pub struct Guard<'a> { pub fd: sock_t, - pub guard: mutex::LockGuard<'a>, + pub guard: MutexGuard<'a, ()>, } #[unsafe_destructor] @@ -666,7 +666,7 @@ impl TcpStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock() }, + guard: self.inner.lock.lock(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret @@ -805,7 +805,7 @@ impl UdpSocket { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock() }, + guard: self.inner.lock.lock(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs new file mode 100644 index 00000000000..df016b9e293 --- /dev/null +++ b/src/libstd/sys/common/rwlock.rs @@ -0,0 +1,86 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::rwlock as imp; + +/// An OS-based reader-writer lock. +/// +/// This structure is entirely unsafe and serves as the lowest layer of a +/// cross-platform binding of system rwlocks. It is recommended to use the +/// safer types at the top level of this crate instead of this type. +pub struct RWLock(imp::RWLock); + +/// Constant initializer for static RWLocks. +pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT); + +impl RWLock { + /// Creates a new instance of an RWLock. + /// + /// Usage of an RWLock is undefined if it is moved after its first use (any + /// function calls below). + #[inline] + pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) } + + /// Acquire shared access to the underlying lock, blocking the current + /// thread to do so. + /// + /// Behavior is undefined if the rwlock has been moved between this and any + /// previous methodo call. + #[inline] + pub unsafe fn read(&self) { self.0.read() } + + /// Attempt to acquire shared access to this lock, returning whether it + /// succeeded or not. + /// + /// This function does not block the current thread. + /// + /// Behavior is undefined if the rwlock has been moved between this and any + /// previous methodo call. + #[inline] + pub unsafe fn try_read(&self) -> bool { self.0.try_read() } + + /// Acquire write access to the underlying lock, blocking the current thread + /// to do so. + /// + /// Behavior is undefined if the rwlock has been moved between this and any + /// previous methodo call. + #[inline] + pub unsafe fn write(&self) { self.0.write() } + + /// Attempt to acquire exclusive access to this lock, returning whether it + /// succeeded or not. + /// + /// This function does not block the current thread. + /// + /// Behavior is undefined if the rwlock has been moved between this and any + /// previous methodo call. + #[inline] + pub unsafe fn try_write(&self) -> bool { self.0.try_write() } + + /// Unlock previously acquired shared access to this lock. + /// + /// Behavior is undefined if the current thread does not have shared access. + #[inline] + pub unsafe fn read_unlock(&self) { self.0.read_unlock() } + + /// Unlock previously acquired exclusive access to this lock. + /// + /// Behavior is undefined if the current thread does not currently have + /// exclusive access. + #[inline] + pub unsafe fn write_unlock(&self) { self.0.write_unlock() } + + /// Destroy OS-related resources with this RWLock. + /// + /// Behavior is undefined if there are any currently active users of this + /// lock. + #[inline] + pub unsafe fn destroy(&self) { self.0.destroy() } +} diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs new file mode 100644 index 00000000000..f64718539ef --- /dev/null +++ b/src/libstd/sys/unix/condvar.rs @@ -0,0 +1,83 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; +use libc; +use sys::mutex::{mod, Mutex}; +use sys::sync as ffi; +use time::Duration; + +pub struct Condvar { inner: UnsafeCell<ffi::pthread_cond_t> } + +pub const CONDVAR_INIT: Condvar = Condvar { + inner: UnsafeCell { value: ffi::PTHREAD_COND_INITIALIZER }, +}; + +impl Condvar { + #[inline] + pub unsafe fn new() -> Condvar { + // Might be moved and address is changing it is better to avoid + // initialization of potentially opaque OS data before it landed + Condvar { inner: UnsafeCell::new(ffi::PTHREAD_COND_INITIALIZER) } + } + + #[inline] + pub unsafe fn notify_one(&self) { + let r = ffi::pthread_cond_signal(self.inner.get()); + debug_assert_eq!(r, 0); + } + + #[inline] + pub unsafe fn notify_all(&self) { + let r = ffi::pthread_cond_broadcast(self.inner.get()); + debug_assert_eq!(r, 0); + } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + let r = ffi::pthread_cond_wait(self.inner.get(), mutex::raw(mutex)); + debug_assert_eq!(r, 0); + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + assert!(dur >= Duration::nanoseconds(0)); + + // First, figure out what time it currently is + let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 }; + let r = ffi::gettimeofday(&mut tv, 0 as *mut _); + debug_assert_eq!(r, 0); + + // Offset that time with the specified duration + let abs = Duration::seconds(tv.tv_sec as i64) + + Duration::microseconds(tv.tv_usec as i64) + + dur; + let ns = abs.num_nanoseconds().unwrap() as u64; + let timeout = libc::timespec { + tv_sec: (ns / 1000000000) as libc::time_t, + tv_nsec: (ns % 1000000000) as libc::c_long, + }; + + // And wait! + let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), + &timeout); + if r != 0 { + debug_assert_eq!(r as int, libc::ETIMEDOUT as int); + false + } else { + true + } + } + + #[inline] + pub unsafe fn destroy(&self) { + let r = ffi::pthread_cond_destroy(self.inner.get()); + debug_assert_eq!(r, 0); + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 4b47b768d60..a773ef7e317 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -20,7 +20,7 @@ use prelude::*; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, FileStat, SeekStyle, Reader}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; -use result::{Ok, Err}; +use result::Result::{Ok, Err}; use sys::retry; use sys_common::{keep_going, eof, mkerr_libc}; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index af238905119..4effedbe3ab 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -25,23 +25,29 @@ use sys_common::mkerr_libc; macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( static $name: Helper<$m> = Helper { - lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, + lock: ::sync::MUTEX_INIT, + cond: ::sync::CONDVAR_INIT, chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, signal: ::cell::UnsafeCell { value: 0 }, initialized: ::cell::UnsafeCell { value: false }, + shutdown: ::cell::UnsafeCell { value: false }, }; ) ) pub mod c; pub mod ext; +pub mod condvar; pub mod fs; pub mod helper_signal; +pub mod mutex; pub mod os; pub mod pipe; pub mod process; +pub mod rwlock; +pub mod sync; pub mod tcp; -pub mod timer; pub mod thread_local; +pub mod timer; pub mod tty; pub mod udp; diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs new file mode 100644 index 00000000000..2f01c53cb2c --- /dev/null +++ b/src/libstd/sys/unix/mutex.rs @@ -0,0 +1,52 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; +use sys::sync as ffi; +use sys_common::mutex; + +pub struct Mutex { inner: UnsafeCell<ffi::pthread_mutex_t> } + +#[inline] +pub unsafe fn raw(m: &Mutex) -> *mut ffi::pthread_mutex_t { + m.inner.get() +} + +pub const MUTEX_INIT: Mutex = Mutex { + inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER }, +}; + +impl Mutex { + #[inline] + pub unsafe fn new() -> Mutex { + // Might be moved and address is changing it is better to avoid + // initialization of potentially opaque OS data before it landed + MUTEX_INIT + } + #[inline] + pub unsafe fn lock(&self) { + let r = ffi::pthread_mutex_lock(self.inner.get()); + debug_assert_eq!(r, 0); + } + #[inline] + pub unsafe fn unlock(&self) { + let r = ffi::pthread_mutex_unlock(self.inner.get()); + debug_assert_eq!(r, 0); + } + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::pthread_mutex_trylock(self.inner.get()) == 0 + } + #[inline] + pub unsafe fn destroy(&self) { + let r = ffi::pthread_mutex_destroy(self.inner.get()); + debug_assert_eq!(r, 0); + } +} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 3f70fb5c1a5..08e6f7059d8 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -12,8 +12,7 @@ use alloc::arc::Arc; use libc; use c_str::CString; use mem; -use rustrt::mutex; -use sync::atomic; +use sync::{atomic, Mutex}; use io::{mod, IoResult, IoError}; use prelude::*; @@ -60,12 +59,12 @@ struct Inner { // Unused on Linux, where this lock is not necessary. #[allow(dead_code)] - lock: mutex::NativeMutex + lock: Mutex<()>, } impl Inner { fn new(fd: fd_t) -> Inner { - Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } } + Inner { fd: fd, lock: Mutex::new(()) } } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 76c316076f9..7dde19a6476 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,7 +11,7 @@ use self::Req::*; use libc::{mod, pid_t, c_void, c_int}; use c_str::CString; -use io::{mod, IoResult, IoError}; +use io::{mod, IoResult, IoError, EndOfFile}; use mem; use os; use ptr; @@ -39,6 +39,8 @@ enum Req { NewChild(libc::pid_t, Sender<ProcessExit>, u64), } +const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; + impl Process { pub fn id(&self) -> pid_t { self.pid @@ -106,18 +108,36 @@ impl Process { if pid < 0 { return Err(super::last_error()) } else if pid > 0 { + #[inline] + fn combine(arr: &[u8]) -> i32 { + let a = arr[0] as u32; + let b = arr[1] as u32; + let c = arr[2] as u32; + let d = arr[3] as u32; + + ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 + } + + let p = Process{ pid: pid }; drop(output); - let mut bytes = [0, ..4]; + let mut bytes = [0, ..8]; return match input.read(&mut bytes) { - Ok(4) => { - let errno = (bytes[0] as i32 << 24) | - (bytes[1] as i32 << 16) | - (bytes[2] as i32 << 8) | - (bytes[3] as i32 << 0); + Ok(8) => { + assert!(combine(CLOEXEC_MSG_FOOTER) == combine(bytes.slice(4, 8)), + "Validation on the CLOEXEC pipe failed: {}", bytes); + let errno = combine(bytes.slice(0, 4)); + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); Err(super::decode_error(errno)) } - Err(..) => Ok(Process { pid: pid }), - Ok(..) => panic!("short read on the cloexec pipe"), + Err(ref e) if e.kind == EndOfFile => Ok(p), + Err(e) => { + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); + panic!("the CLOEXEC pipe failed: {}", e) + }, + Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } }; } @@ -154,13 +174,16 @@ impl Process { let _ = libc::close(input.fd()); fn fail(output: &mut FileDesc) -> ! { - let errno = sys::os::errno(); + let errno = sys::os::errno() as u32; let bytes = [ (errno >> 24) as u8, (errno >> 16) as u8, (errno >> 8) as u8, (errno >> 0) as u8, + CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], + CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] ]; + // pipe I/O up to PIPE_BUF bytes should be atomic assert!(output.write(&bytes).is_ok()); unsafe { libc::_exit(1) } } diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs new file mode 100644 index 00000000000..0d63ff14ff2 --- /dev/null +++ b/src/libstd/sys/unix/rwlock.rs @@ -0,0 +1,57 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; +use sys::sync as ffi; + +pub struct RWLock { inner: UnsafeCell<ffi::pthread_rwlock_t> } + +pub const RWLOCK_INIT: RWLock = RWLock { + inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER }, +}; + +impl RWLock { + #[inline] + pub unsafe fn new() -> RWLock { + // Might be moved and address is changing it is better to avoid + // initialization of potentially opaque OS data before it landed + RWLOCK_INIT + } + #[inline] + pub unsafe fn read(&self) { + let r = ffi::pthread_rwlock_rdlock(self.inner.get()); + debug_assert_eq!(r, 0); + } + #[inline] + pub unsafe fn try_read(&self) -> bool { + ffi::pthread_rwlock_tryrdlock(self.inner.get()) == 0 + } + #[inline] + pub unsafe fn write(&self) { + let r = ffi::pthread_rwlock_wrlock(self.inner.get()); + debug_assert_eq!(r, 0); + } + #[inline] + pub unsafe fn try_write(&self) -> bool { + ffi::pthread_rwlock_trywrlock(self.inner.get()) == 0 + } + #[inline] + pub unsafe fn read_unlock(&self) { + let r = ffi::pthread_rwlock_unlock(self.inner.get()); + debug_assert_eq!(r, 0); + } + #[inline] + pub unsafe fn write_unlock(&self) { self.read_unlock() } + #[inline] + pub unsafe fn destroy(&self) { + let r = ffi::pthread_rwlock_destroy(self.inner.get()); + debug_assert_eq!(r, 0); + } +} diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs new file mode 100644 index 00000000000..007826b4b9d --- /dev/null +++ b/src/libstd/sys/unix/sync.rs @@ -0,0 +1,208 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use libc; + +pub use self::os::{PTHREAD_MUTEX_INITIALIZER, pthread_mutex_t}; +pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t}; +pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t}; + +extern { + // mutexes + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int; + + // cvars + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const libc::timespec) -> libc::c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int; + pub fn gettimeofday(tp: *mut libc::timeval, + tz: *mut libc::c_void) -> libc::c_int; + + // rwlocks + pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> libc::c_int; + pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> libc::c_int; + pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> libc::c_int; + pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> libc::c_int; + pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> libc::c_int; + pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> libc::c_int; +} + +#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] +mod os { + use libc; + + pub type pthread_mutex_t = *mut libc::c_void; + pub type pthread_cond_t = *mut libc::c_void; + pub type pthread_rwlock_t = *mut libc::c_void; + + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _; +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod os { + use libc; + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_MUTEX_SIZE__: uint = 56; + #[cfg(any(target_arch = "x86", + target_arch = "arm"))] + const __PTHREAD_MUTEX_SIZE__: uint = 40; + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_COND_SIZE__: uint = 40; + #[cfg(any(target_arch = "x86", + target_arch = "arm"))] + const __PTHREAD_COND_SIZE__: uint = 24; + + #[cfg(target_arch = "x86_64")] + const __PTHREAD_RWLOCK_SIZE__: uint = 192; + #[cfg(any(target_arch = "x86", + target_arch = "arm"))] + const __PTHREAD_RWLOCK_SIZE__: uint = 124; + + const _PTHREAD_MUTEX_SIG_INIT: libc::c_long = 0x32AAABA7; + const _PTHREAD_COND_SIG_INIT: libc::c_long = 0x3CB0B1BB; + const _PTHREAD_RWLOCK_SIG_INIT: libc::c_long = 0x2DA8B3B4; + + #[repr(C)] + pub struct pthread_mutex_t { + __sig: libc::c_long, + __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__], + } + #[repr(C)] + pub struct pthread_cond_t { + __sig: libc::c_long, + __opaque: [u8, ..__PTHREAD_COND_SIZE__], + } + #[repr(C)] + pub struct pthread_rwlock_t { + __sig: libc::c_long, + __opaque: [u8, ..__PTHREAD_RWLOCK_SIZE__], + } + + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __sig: _PTHREAD_MUTEX_SIG_INIT, + __opaque: [0, ..__PTHREAD_MUTEX_SIZE__], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __sig: _PTHREAD_COND_SIG_INIT, + __opaque: [0, ..__PTHREAD_COND_SIZE__], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __sig: _PTHREAD_RWLOCK_SIG_INIT, + __opaque: [0, ..__PTHREAD_RWLOCK_SIZE__], + }; +} + +#[cfg(target_os = "linux")] +mod os { + use libc; + + // minus 8 because we have an 'align' field + #[cfg(target_arch = "x86_64")] + const __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8; + #[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "mips", + target_arch = "mipsel"))] + const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8; + + #[cfg(any(target_arch = "x86_64", + target_arch = "x86", + target_arch = "arm", + target_arch = "mips", + target_arch = "mipsel"))] + const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8; + + #[cfg(target_arch = "x86_64")] + const __SIZEOF_PTHREAD_RWLOCK_T: uint = 56 - 8; + + #[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "mips", + target_arch = "mipsel"))] + const __SIZEOF_PTHREAD_RWLOCK_T: uint = 32 - 8; + + #[repr(C)] + pub struct pthread_mutex_t { + __align: libc::c_longlong, + size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T], + } + #[repr(C)] + pub struct pthread_cond_t { + __align: libc::c_longlong, + size: [u8, ..__SIZEOF_PTHREAD_COND_T], + } + #[repr(C)] + pub struct pthread_rwlock_t { + __align: libc::c_longlong, + size: [u8, ..__SIZEOF_PTHREAD_RWLOCK_T], + } + + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __align: 0, + size: [0, ..__SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __align: 0, + size: [0, ..__SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __align: 0, + size: [0, ..__SIZEOF_PTHREAD_RWLOCK_T], + }; +} +#[cfg(target_os = "android")] +mod os { + use libc; + + #[repr(C)] + pub struct pthread_mutex_t { value: libc::c_int } + #[repr(C)] + pub struct pthread_cond_t { value: libc::c_int } + #[repr(C)] + pub struct pthread_rwlock_t { + lock: pthread_mutex_t, + cond: pthread_cond_t, + numLocks: libc::c_int, + writerThreadId: libc::c_int, + pendingReaders: libc::c_int, + pendingWriters: libc::c_int, + reserved: [*mut libc::c_void, ..4], + } + + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + value: 0, + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + value: 0, + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + lock: PTHREAD_MUTEX_INITIALIZER, + cond: PTHREAD_COND_INITIALIZER, + numLocks: 0, + writerThreadId: 0, + pendingReaders: 0, + pendingWriters: 0, + reserved: [0 as *mut _, ..4], + }; +} diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs new file mode 100644 index 00000000000..3cabf3a6319 --- /dev/null +++ b/src/libstd/sys/windows/condvar.rs @@ -0,0 +1,63 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; +use libc::{mod, DWORD}; +use libc; +use os; +use sys::mutex::{mod, Mutex}; +use sys::sync as ffi; +use time::Duration; + +pub struct Condvar { inner: UnsafeCell<ffi::CONDITION_VARIABLE> } + +pub const CONDVAR_INIT: Condvar = Condvar { + inner: UnsafeCell { value: ffi::CONDITION_VARIABLE_INIT } +}; + +impl Condvar { + #[inline] + pub unsafe fn new() -> Condvar { CONDVAR_INIT } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + let r = ffi::SleepConditionVariableCS(self.inner.get(), + mutex::raw(mutex), + libc::INFINITE); + debug_assert!(r != 0); + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + let r = ffi::SleepConditionVariableCS(self.inner.get(), + mutex::raw(mutex), + dur.num_milliseconds() as DWORD); + if r == 0 { + const ERROR_TIMEOUT: DWORD = 0x5B4; + debug_assert_eq!(os::errno() as uint, ERROR_TIMEOUT as uint); + false + } else { + true + } + } + + #[inline] + pub unsafe fn notify_one(&self) { + ffi::WakeConditionVariable(self.inner.get()) + } + + #[inline] + pub unsafe fn notify_all(&self) { + ffi::WakeAllConditionVariable(self.inner.get()) + } + + pub unsafe fn destroy(&self) { + // ... + } +} diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs index 2c58ee69e8b..049aca3f590 100644 --- a/src/libstd/sys/windows/ext.rs +++ b/src/libstd/sys/windows/ext.rs @@ -76,13 +76,13 @@ impl AsRawSocket for io::net::tcp::TcpStream { impl AsRawSocket for io::net::tcp::TcpListener { fn as_raw_socket(&self) -> Socket { - self.as_inner().fd() + self.as_inner().socket() } } impl AsRawSocket for io::net::tcp::TcpAcceptor { fn as_raw_socket(&self) -> Socket { - self.as_inner().fd() + self.as_inner().socket() } } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 9c4ffb926b5..9402c63dcf5 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -131,7 +131,7 @@ impl FileDesc { return ret; } - pub fn fstat(&mut self) -> IoResult<io::FileStat> { + pub fn fstat(&self) -> IoResult<io::FileStat> { let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::fstat(self.fd(), &mut stat) } { 0 => Ok(mkstat(&stat)), diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 6b9555c52ce..9fce308cb94 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -26,20 +26,26 @@ use sync::{Once, ONCE_INIT}; macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( static $name: Helper<$m> = Helper { - lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, + lock: ::sync::MUTEX_INIT, + cond: ::sync::CONDVAR_INIT, chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, signal: ::cell::UnsafeCell { value: 0 }, initialized: ::cell::UnsafeCell { value: false }, + shutdown: ::cell::UnsafeCell { value: false }, }; ) ) pub mod c; pub mod ext; +pub mod condvar; pub mod fs; pub mod helper_signal; +pub mod mutex; pub mod os; pub mod pipe; pub mod process; +pub mod rwlock; +pub mod sync; pub mod tcp; pub mod thread_local; pub mod timer; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs new file mode 100644 index 00000000000..ddd89070ed5 --- /dev/null +++ b/src/libstd/sys/windows/mutex.rs @@ -0,0 +1,78 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; + +use sync::atomic; +use alloc::{mod, heap}; + +use libc::DWORD; +use sys::sync as ffi; + +const SPIN_COUNT: DWORD = 4000; + +pub struct Mutex { inner: atomic::AtomicUint } + +pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT }; + +#[inline] +pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION { + m.get() +} + +impl Mutex { + #[inline] + pub unsafe fn new() -> Mutex { + Mutex { inner: atomic::AtomicUint::new(init_lock() as uint) } + } + #[inline] + pub unsafe fn lock(&self) { + ffi::EnterCriticalSection(self.get()) + } + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::TryEnterCriticalSection(self.get()) != 0 + } + #[inline] + pub unsafe fn unlock(&self) { + ffi::LeaveCriticalSection(self.get()) + } + pub unsafe fn destroy(&self) { + let lock = self.inner.swap(0, atomic::SeqCst); + if lock != 0 { free_lock(lock as ffi::LPCRITICAL_SECTION) } + } + + unsafe fn get(&self) -> ffi::LPCRITICAL_SECTION { + match self.inner.load(atomic::SeqCst) { + 0 => {} + n => return n as ffi::LPCRITICAL_SECTION + } + let lock = init_lock(); + match self.inner.compare_and_swap(0, lock as uint, atomic::SeqCst) { + 0 => return lock as ffi::LPCRITICAL_SECTION, + _ => {} + } + free_lock(lock); + return self.inner.load(atomic::SeqCst) as ffi::LPCRITICAL_SECTION; + } +} + +unsafe fn init_lock() -> ffi::LPCRITICAL_SECTION { + let block = heap::allocate(ffi::CRITICAL_SECTION_SIZE, 8) + as ffi::LPCRITICAL_SECTION; + if block.is_null() { alloc::oom() } + ffi::InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT); + return block; +} + +unsafe fn free_lock(h: ffi::LPCRITICAL_SECTION) { + ffi::DeleteCriticalSection(h); + heap::deallocate(h as *mut _, ffi::CRITICAL_SECTION_SIZE, 8); +} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index ca7985aa35b..bf658d0efd0 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -89,8 +89,7 @@ use libc; use c_str::CString; use mem; use ptr; -use sync::atomic; -use rustrt::mutex; +use sync::{atomic, Mutex}; use io::{mod, IoError, IoResult}; use prelude::*; @@ -126,7 +125,7 @@ impl Drop for Event { struct Inner { handle: libc::HANDLE, - lock: mutex::NativeMutex, + lock: Mutex<()>, read_closed: atomic::AtomicBool, write_closed: atomic::AtomicBool, } @@ -135,7 +134,7 @@ impl Inner { fn new(handle: libc::HANDLE) -> Inner { Inner { handle: handle, - lock: unsafe { mutex::NativeMutex::new() }, + lock: Mutex::new(()), read_closed: atomic::AtomicBool::new(false), write_closed: atomic::AtomicBool::new(false), } diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs new file mode 100644 index 00000000000..88ce85c39f6 --- /dev/null +++ b/src/libstd/sys/windows/rwlock.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; +use sys::sync as ffi; + +pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> } + +pub const RWLOCK_INIT: RWLock = RWLock { + inner: UnsafeCell { value: ffi::SRWLOCK_INIT } +}; + +impl RWLock { + #[inline] + pub unsafe fn new() -> RWLock { RWLOCK_INIT } + + #[inline] + pub unsafe fn read(&self) { + ffi::AcquireSRWLockShared(self.inner.get()) + } + #[inline] + pub unsafe fn try_read(&self) -> bool { + ffi::TryAcquireSRWLockShared(self.inner.get()) != 0 + } + #[inline] + pub unsafe fn write(&self) { + ffi::AcquireSRWLockExclusive(self.inner.get()) + } + #[inline] + pub unsafe fn try_write(&self) -> bool { + ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + } + #[inline] + pub unsafe fn read_unlock(&self) { + ffi::ReleaseSRWLockShared(self.inner.get()) + } + #[inline] + pub unsafe fn write_unlock(&self) { + ffi::ReleaseSRWLockExclusive(self.inner.get()) + } + + #[inline] + pub unsafe fn destroy(&self) { + // ... + } +} diff --git a/src/libstd/sys/windows/sync.rs b/src/libstd/sys/windows/sync.rs new file mode 100644 index 00000000000..cbca47912b5 --- /dev/null +++ b/src/libstd/sys/windows/sync.rs @@ -0,0 +1,58 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::{BOOL, DWORD, c_void, LPVOID}; +use libc::types::os::arch::extra::BOOLEAN; + +pub type LPCRITICAL_SECTION = *mut c_void; +pub type LPCONDITION_VARIABLE = *mut CONDITION_VARIABLE; +pub type LPSRWLOCK = *mut SRWLOCK; + +#[cfg(target_arch = "x86")] +pub const CRITICAL_SECTION_SIZE: uint = 24; +#[cfg(target_arch = "x86_64")] +pub const CRITICAL_SECTION_SIZE: uint = 40; + +#[repr(C)] +pub struct CONDITION_VARIABLE { pub ptr: LPVOID } +#[repr(C)] +pub struct SRWLOCK { pub ptr: LPVOID } + +pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { + ptr: 0 as *mut _, +}; +pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ }; + +extern "system" { + // critical sections + pub fn InitializeCriticalSectionAndSpinCount( + lpCriticalSection: LPCRITICAL_SECTION, + dwSpinCount: DWORD) -> BOOL; + pub fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION); + pub fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION); + pub fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION); + pub fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL; + + // condition variables + pub fn SleepConditionVariableCS(ConditionVariable: LPCONDITION_VARIABLE, + CriticalSection: LPCRITICAL_SECTION, + dwMilliseconds: DWORD) -> BOOL; + pub fn WakeConditionVariable(ConditionVariable: LPCONDITION_VARIABLE); + pub fn WakeAllConditionVariable(ConditionVariable: LPCONDITION_VARIABLE); + + // slim rwlocks + pub fn AcquireSRWLockExclusive(SRWLock: LPSRWLOCK); + pub fn AcquireSRWLockShared(SRWLock: LPSRWLOCK); + pub fn ReleaseSRWLockExclusive(SRWLock: LPSRWLOCK); + pub fn ReleaseSRWLockShared(SRWLock: LPSRWLOCK); + pub fn TryAcquireSRWLockExclusive(SRWLock: LPSRWLOCK) -> BOOLEAN; + pub fn TryAcquireSRWLockShared(SRWLock: LPSRWLOCK) -> BOOLEAN; +} + diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 3baf2be08d2..b577372d2fc 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -48,37 +48,35 @@ impl Drop for Event { // TCP listeners //////////////////////////////////////////////////////////////////////////////// -pub struct TcpListener { - inner: FileDesc, -} +pub struct TcpListener { sock: sock_t } impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> { sys::init_net(); - let fd = try!(socket(addr, libc::SOCK_STREAM)); - let ret = TcpListener { inner: FileDesc::new(fd as libc::c_int, true) }; + let sock = try!(socket(addr, libc::SOCK_STREAM)); + let ret = TcpListener { sock: sock }; let mut storage = unsafe { mem::zeroed() }; let len = addr_to_sockaddr(addr, &mut storage); let addrp = &storage as *const _ as *const libc::sockaddr; - match unsafe { libc::bind(fd, addrp, len) } { + match unsafe { libc::bind(sock, addrp, len) } { -1 => Err(last_net_error()), _ => Ok(ret), } } - pub fn fd(&self) -> sock_t { self.inner.fd as sock_t } + pub fn socket(&self) -> sock_t { self.sock } pub fn listen(self, backlog: int) -> IoResult<TcpAcceptor> { - match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { + match unsafe { libc::listen(self.socket(), backlog as libc::c_int) } { -1 => Err(last_net_error()), _ => { let accept = try!(Event::new()); let ret = unsafe { - c::WSAEventSelect(self.fd(), accept.handle(), c::FD_ACCEPT) + c::WSAEventSelect(self.socket(), accept.handle(), c::FD_ACCEPT) }; if ret != 0 { return Err(last_net_error()) @@ -97,7 +95,13 @@ impl TcpListener { } pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> { - sockname(self.fd(), libc::getsockname) + sockname(self.socket(), libc::getsockname) + } +} + +impl Drop for TcpListener { + fn drop(&mut self) { + unsafe { super::close_sock(self.sock); } } } @@ -114,7 +118,7 @@ struct AcceptorInner { } impl TcpAcceptor { - pub fn fd(&self) -> sock_t { self.inner.listener.fd() } + pub fn socket(&self) -> sock_t { self.inner.listener.socket() } pub fn accept(&mut self) -> IoResult<TcpStream> { // Unlink unix, windows cannot invoke `select` on arbitrary file @@ -161,13 +165,13 @@ impl TcpAcceptor { let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() }; let ret = unsafe { - c::WSAEnumNetworkEvents(self.fd(), events[1], &mut wsaevents) + c::WSAEnumNetworkEvents(self.socket(), events[1], &mut wsaevents) }; if ret != 0 { return Err(last_net_error()) } if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue } match unsafe { - libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut()) + libc::accept(self.socket(), ptr::null_mut(), ptr::null_mut()) } { -1 if wouldblock() => {} -1 => return Err(last_net_error()), @@ -175,13 +179,13 @@ impl TcpAcceptor { // Accepted sockets inherit the same properties as the caller, // so we need to deregister our event and switch the socket back // to blocking mode - fd => { - let stream = TcpStream::new(fd); + socket => { + let stream = TcpStream::new(socket); let ret = unsafe { - c::WSAEventSelect(fd, events[1], 0) + c::WSAEventSelect(socket, events[1], 0) }; if ret != 0 { return Err(last_net_error()) } - try!(set_nonblocking(fd, false)); + try!(set_nonblocking(socket, false)); return Ok(stream) } } @@ -191,7 +195,7 @@ impl TcpAcceptor { } pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> { - sockname(self.fd(), libc::getsockname) + sockname(self.socket(), libc::getsockname) } pub fn set_timeout(&mut self, timeout: Option<u64>) { diff --git a/src/libstd/task.rs b/src/libstd/task.rs index a0ee08570d9..8b4dbf61c18 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -49,7 +49,8 @@ use boxed::Box; use comm::channel; use io::{Writer, stdio}; use kinds::{Send, marker}; -use option::{None, Some, Option}; +use option::Option; +use option::Option::{None, Some}; use result::Result; use rustrt::local::Local; use rustrt::task::Task; @@ -172,9 +173,10 @@ impl TaskBuilder { /// # Return value /// /// If the child task executes successfully (without panicking) then the - /// future returns `result::Ok` containing the value returned by the - /// function. If the child task panics then the future returns `result::Err` - /// containing the argument to `panic!(...)` as an `Any` trait object. + /// future returns `result::Result::Ok` containing the value returned by the + /// function. If the child task panics then the future returns + /// `result::Result::Err` containing the argument to `panic!(...)` as an + /// `Any` trait object. #[experimental = "Futures are experimental."] pub fn try_future<T:Send>(self, f: proc():Send -> T) -> Future<Result<T, Box<Any + Send>>> { @@ -268,7 +270,7 @@ mod test { use borrow::IntoCow; use boxed::BoxAny; use prelude::*; - use result::{Ok, Err}; + use result::Result::{Ok, Err}; use result; use std::io::{ChanReader, ChanWriter}; use string::String; @@ -330,7 +332,7 @@ mod test { match try(proc() { "Success!".to_string() }).as_ref().map(|s| s.as_slice()) { - result::Ok("Success!") => (), + result::Result::Ok("Success!") => (), _ => panic!() } } @@ -340,8 +342,8 @@ mod test { match try(proc() { panic!() }) { - result::Err(_) => (), - result::Ok(()) => panic!() + result::Result::Err(_) => (), + result::Result::Ok(()) => panic!() } } diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index e2e8461ea54..029b8bf1138 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -115,7 +115,7 @@ macro_rules! thread_local( use std::cell::UnsafeCell as __UnsafeCell; use std::thread_local::KeyInner as __KeyInner; use std::option::Option as __Option; - use std::option::None as __None; + use std::option::Option::None as __None; __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { __UnsafeCell { value: __None } @@ -132,7 +132,7 @@ macro_rules! thread_local( use std::cell::UnsafeCell as __UnsafeCell; use std::thread_local::KeyInner as __KeyInner; use std::option::Option as __Option; - use std::option::None as __None; + use std::option::Option::None as __None; __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { __UnsafeCell { value: __None } @@ -198,7 +198,7 @@ macro_rules! __thread_local_inner( inner: ::std::cell::UnsafeCell { value: $init }, os: ::std::thread_local::OsStaticKey { inner: ::std::thread_local::OS_INIT_INNER, - dtor: ::std::option::Some(__destroy), + dtor: ::std::option::Option::Some(__destroy), }, } }; diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index ec2d62ff85c..63eb9a98736 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -14,9 +14,11 @@ use {fmt, i64}; use ops::{Add, Sub, Mul, Div, Neg}; -use option::{Option, Some, None}; +use option::Option; +use option::Option::{Some, None}; use num::Int; -use result::{Result, Ok, Err}; +use result::Result; +use result::Result::{Ok, Err}; /// The number of nanoseconds in a microsecond. const NANOS_PER_MICRO: i32 = 1000; @@ -387,7 +389,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { mod tests { use super::{Duration, MIN, MAX}; use {i32, i64}; - use option::{Some, None}; + use option::Option::{Some, None}; use string::ToString; #[test] diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 5f4e675aad5..2be11a236d3 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -45,15 +45,6 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt, [ast::TtToken(_, token::Ident(code, _))] => code, _ => unreachable!() }; - with_registered_diagnostics(|diagnostics| { - if !diagnostics.contains_key(&code.name) { - ecx.span_err(span, format!( - "unknown diagnostic code {}; add to librustc/diagnostics.rs", - token::get_ident(code).get() - ).as_slice()); - } - () - }); with_used_diagnostics(|diagnostics| { match diagnostics.insert(code.name, span) { Some(previous_span) => { @@ -106,25 +97,19 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, _ => unreachable!() }; - let (count, expr) = with_used_diagnostics(|diagnostics_in_use| { + let (count, expr) = with_registered_diagnostics(|diagnostics| { - let descriptions: Vec<P<ast::Expr>> = diagnostics - .iter().filter_map(|(code, description)| { - if !diagnostics_in_use.contains_key(code) { - ecx.span_warn(span, format!( - "diagnostic code {} never used", token::get_name(*code).get() - ).as_slice()); - } - description.map(|description| { - ecx.expr_tuple(span, vec![ - ecx.expr_str(span, token::get_name(*code)), - ecx.expr_str(span, token::get_name(description)) - ]) - }) - }).collect(); + let descriptions: Vec<P<ast::Expr>> = + diagnostics.iter().filter_map(|(code, description)| { + description.map(|description| { + ecx.expr_tuple(span, vec![ + ecx.expr_str(span, token::get_name(*code)), + ecx.expr_str(span, token::get_name(description))]) + }) + }).collect(); (descriptions.len(), ecx.expr_vec(span, descriptions)) - }) - }); + }); + MacItems::new(vec![quote_item!(ecx, pub static $name: [(&'static str, &'static str), ..$count] = $expr; ).unwrap()].into_iter()) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index bd01e5e6430..b4bb1a1a529 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -680,6 +680,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let some = vec!( self.ident_of("std"), self.ident_of("option"), + self.ident_of("Option"), self.ident_of("Some")); self.expr_call_global(sp, some, vec!(expr)) } @@ -688,6 +689,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let none = self.path_global(sp, vec!( self.ident_of("std"), self.ident_of("option"), + self.ident_of("Option"), self.ident_of("None"))); self.expr_path(none) } @@ -732,6 +734,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let ok = vec!( self.ident_of("std"), self.ident_of("result"), + self.ident_of("Result"), self.ident_of("Ok")); self.expr_call_global(sp, ok, vec!(expr)) } @@ -740,6 +743,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let err = vec!( self.ident_of("std"), self.ident_of("result"), + self.ident_of("Result"), self.ident_of("Err")); self.expr_call_global(sp, err, vec!(expr)) } @@ -810,6 +814,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let some = vec!( self.ident_of("std"), self.ident_of("option"), + self.ident_of("Option"), self.ident_of("Some")); let path = self.path_global(span, some); self.pat_enum(span, path, vec!(pat)) @@ -819,6 +824,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let some = vec!( self.ident_of("std"), self.ident_of("option"), + self.ident_of("Option"), self.ident_of("None")); let path = self.path_global(span, some); self.pat_enum(span, path, vec!()) @@ -828,6 +834,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let some = vec!( self.ident_of("std"), self.ident_of("result"), + self.ident_of("Result"), self.ident_of("Ok")); let path = self.path_global(span, some); self.pat_enum(span, path, vec!(pat)) @@ -837,6 +844,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let some = vec!( self.ident_of("std"), self.ident_of("result"), + self.ident_of("Result"), self.ident_of("Err")); let path = self.path_global(span, some); self.pat_enum(span, path, vec!(pat)) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 98345e1dd67..787c6e844d5 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -105,6 +105,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, let ordering = cx.path_global(span, vec!(cx.ident_of("std"), cx.ident_of("cmp"), + cx.ident_of("Ordering"), cx.ident_of("Equal"))); let ordering = cx.expr_path(ordering); let equals_expr = cx.expr_some(span, ordering); @@ -120,9 +121,9 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, Builds: let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); - if __test == ::std::option::Some(::std::cmp::Equal) { + if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); - if __test == ::std::option::Some(::std::cmp::Equal) { + if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { ... } else { __test @@ -139,7 +140,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, false, |cx, span, old, self_f, other_fs| { // let __test = new; - // if __test == Some(::std::cmp::Equal) { + // if __test == Some(::std::cmp::Ordering::Equal) { // old // } else { // __test diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index d84ad677e5d..83af45462ec 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -70,9 +70,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, Builds: let __test = self_field1.cmp(&other_field2); - if other == ::std::cmp::Equal { + if other == ::std::cmp::Ordering::Equal { let __test = self_field2.cmp(&other_field2); - if __test == ::std::cmp::Equal { + if __test == ::std::cmp::Ordering::Equal { ... } else { __test @@ -89,7 +89,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, false, |cx, span, old, new| { // let __test = new; - // if __test == ::std::cmp::Equal { + // if __test == ::std::cmp::Ordering::Equal { // old // } else { // __test diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 87e257c52cd..e6a44c57f1b 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -36,6 +36,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT true, vec!(cx.ident_of("std"), cx.ident_of("option"), + cx.ident_of("Option"), cx.ident_of("None")), Vec::new(), vec!(cx.ty_rptr(sp, @@ -50,6 +51,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT cx.expr_call_global(sp, vec!(cx.ident_of("std"), cx.ident_of("option"), + cx.ident_of("Option"), cx.ident_of("Some")), vec!(cx.expr_str(sp, token::intern_and_get_ident( diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 3fca110a881..45752499ad5 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -450,9 +450,8 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'static> { - let e_param_colons = cx.expr_lit(sp, ast::LitBool(false)); let expanded = expand_parse_call(cx, sp, "parse_ty", - vec!(e_param_colons), tts); + vec![], tts); base::MacExpr::new(expanded) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c7aef0020b2..11c65d531f6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -32,9 +32,7 @@ use parse::token; use std::slice; -/// This is a list of all known features since the beginning of time. This list -/// can never shrink, it may only be expanded (in order to prevent old programs -/// from failing to compile). The status of each feature may change, however. +// if you change this list without updating src/doc/reference.md, @cmr will be sad static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("globs", Active), ("macro_rules", Active), @@ -65,15 +63,13 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("unboxed_closures", Active), ("import_shadowing", Active), ("advanced_slice_patterns", Active), - ("tuple_indexing", Active), + ("tuple_indexing", Accepted), ("associated_types", Active), ("visible_private_types", Active), ("slicing_syntax", Active), - ("if_let", Active), - ("while_let", Active), - - // if you change this list without updating src/doc/reference.md, cmr will be sad + ("if_let", Accepted), + ("while_let", Accepted), // A temporary feature gate used to enable parser extensions needed // to bootstrap fix for #5723. @@ -309,24 +305,11 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { "unboxed closures are a work-in-progress \ feature with known bugs"); } - ast::ExprTupField(..) => { - self.gate_feature("tuple_indexing", - e.span, - "tuple indexing is experimental"); - } - ast::ExprIfLet(..) => { - self.gate_feature("if_let", e.span, - "`if let` syntax is experimental"); - } ast::ExprSlice(..) => { self.gate_feature("slicing_syntax", e.span, "slicing syntax is experimental"); } - ast::ExprWhileLet(..) => { - self.gate_feature("while_let", e.span, - "`while let` syntax is experimental"); - } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index db7bc6c323f..41fee1556ab 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -212,7 +212,7 @@ impl<'a> ParserAttr for Parser<'a> { fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>> { self.parse_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), - seq_sep_trailing_disallowed(token::Comma), + seq_sep_trailing_allowed(token::Comma), |p| p.parse_meta_item()).node } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 3842170d677..a96bf1ce10b 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -19,18 +19,13 @@ pub struct SeqSep { pub trailing_sep_allowed: bool } -pub fn seq_sep_trailing_disallowed(t: token::Token) -> SeqSep { - SeqSep { - sep: Some(t), - trailing_sep_allowed: false, - } -} pub fn seq_sep_trailing_allowed(t: token::Token) -> SeqSep { SeqSep { sep: Some(t), trailing_sep_allowed: true, } } + pub fn seq_sep_none() -> SeqSep { SeqSep { sep: None, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 57983a6dee6..b282db5ba2b 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -764,6 +764,15 @@ impl<'a> StringReader<'a> { } } + // SNAP 361baab + #[allow(unused)] + fn old_escape_warning(&mut self, sp: Span) { + self.span_diagnostic + .span_warn(sp, "\\U00ABCD12 and \\uABCD escapes are deprecated"); + self.span_diagnostic + .span_help(sp, "use \\u{ABCD12} escapes instead"); + } + /// Scan for a single (possibly escaped) byte or char /// in a byte, (non-raw) byte string, char, or (non-raw) string literal. /// `start` is the position of `first_source_char`, which is already consumed. @@ -782,12 +791,24 @@ impl<'a> StringReader<'a> { Some(e) => { return match e { 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, - 'x' => self.scan_hex_digits(2u, delim, !ascii_only), + 'x' => self.scan_byte_escape(delim, !ascii_only), 'u' if !ascii_only => { - self.scan_hex_digits(4u, delim, false) + if self.curr == Some('{') { + self.scan_unicode_escape(delim) + } else { + let res = self.scan_hex_digits(4u, delim, false); + // SNAP 361baab + //let sp = codemap::mk_sp(escaped_pos, self.last_pos); + //self.old_escape_warning(sp); + res + } } 'U' if !ascii_only => { - self.scan_hex_digits(8u, delim, false) + let res = self.scan_hex_digits(8u, delim, false); + // SNAP 361baab + //let sp = codemap::mk_sp(escaped_pos, self.last_pos); + //self.old_escape_warning(sp); + res } '\n' if delim == '"' => { self.consume_whitespace(); @@ -848,6 +869,56 @@ impl<'a> StringReader<'a> { true } + /// Scan over a \u{...} escape + /// + /// At this point, we have already seen the \ and the u, the { is the current character. We + /// will read at least one digit, and up to 6, and pass over the }. + fn scan_unicode_escape(&mut self, delim: char) -> bool { + self.bump(); // past the { + let start_bpos = self.last_pos; + let mut count: uint = 0; + let mut accum_int = 0; + + while !self.curr_is('}') && count <= 6 { + let c = match self.curr { + Some(c) => c, + None => { + self.fatal_span_(start_bpos, self.last_pos, + "unterminated unicode escape (found EOF)"); + } + }; + accum_int *= 16; + accum_int += c.to_digit(16).unwrap_or_else(|| { + if c == delim { + self.fatal_span_(self.last_pos, self.pos, + "unterminated unicode escape (needed a `}`)"); + } else { + self.fatal_span_char(self.last_pos, self.pos, + "illegal character in unicode escape", c); + } + }) as u32; + self.bump(); + count += 1; + } + + if count > 6 { + self.fatal_span_(start_bpos, self.last_pos, + "overlong unicode escape (can have at most 6 hex digits)"); + } + + self.bump(); // past the ending } + + let mut valid = count >= 1 && count <= 6; + if char::from_u32(accum_int).is_none() { + valid = false; + } + + if !valid { + self.fatal_span_(start_bpos, self.last_pos, "illegal unicode character escape"); + } + valid + } + /// Scan over a float exponent. fn scan_float_exponent(&mut self) { if self.curr_is('e') || self.curr_is('E') { @@ -1273,6 +1344,10 @@ impl<'a> StringReader<'a> { return token::Byte(id); } + fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool { + self.scan_hex_digits(2, delim, below_0x7f_only) + } + fn scan_byte_string(&mut self) -> token::Lit { self.bump(); let start = self.last_pos; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b46f7cdfe22..8d0c2de048a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -393,16 +393,28 @@ pub fn char_lit(lit: &str) -> (char, int) { let msg = format!("lexer should have rejected a bad character escape {}", lit); let msg2 = msg.as_slice(); - let esc: |uint| -> Option<(char, int)> = |len| + fn esc(len: uint, lit: &str) -> Option<(char, int)> { num::from_str_radix(lit.slice(2, len), 16) .and_then(char::from_u32) - .map(|x| (x, len as int)); + .map(|x| (x, len as int)) + } + + let unicode_escape: || -> Option<(char, int)> = || + if lit.as_bytes()[2] == b'{' { + let idx = lit.find('}').expect(msg2); + let subslice = lit.slice(3, idx); + num::from_str_radix(subslice, 16) + .and_then(char::from_u32) + .map(|x| (x, subslice.char_len() as int + 4)) + } else { + esc(6, lit) + }; // Unicode escapes return match lit.as_bytes()[1] as char { - 'x' | 'X' => esc(4), - 'u' => esc(6), - 'U' => esc(10), + 'x' | 'X' => esc(4, lit), + 'u' => unicode_escape(), + 'U' => esc(10, lit), _ => None, }.expect(msg2); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 920bcc3a951..bb3d28ce2bb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -87,6 +87,7 @@ use std::mem; use std::num::Float; use std::rc::Rc; use std::iter; +use std::slice; bitflags! { flags Restrictions: u8 { @@ -303,6 +304,22 @@ pub struct Parser<'a> { /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option<String>, + pub expected_tokens: Vec<TokenType>, +} + +#[deriving(PartialEq, Eq, Clone)] +pub enum TokenType { + Token(token::Token), + Operator, +} + +impl TokenType { + fn to_string(&self) -> String { + match *self { + TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)), + TokenType::Operator => "an operator".into_string(), + } + } } fn is_plain_ident_or_underscore(t: &token::Token) -> bool { @@ -347,6 +364,7 @@ impl<'a> Parser<'a> { open_braces: Vec::new(), owns_directory: true, root_module_name: None, + expected_tokens: Vec::new(), } } @@ -375,14 +393,18 @@ impl<'a> Parser<'a> { /// Expect and consume the token t. Signal an error if /// the next token is not t. pub fn expect(&mut self, t: &token::Token) { - if self.token == *t { - self.bump(); + if self.expected_tokens.is_empty() { + if self.token == *t { + self.bump(); + } else { + let token_str = Parser::token_to_string(t); + let this_token_str = self.this_token_to_string(); + self.fatal(format!("expected `{}`, found `{}`", + token_str, + this_token_str).as_slice()) + } } else { - let token_str = Parser::token_to_string(t); - let this_token_str = self.this_token_to_string(); - self.fatal(format!("expected `{}`, found `{}`", - token_str, - this_token_str).as_slice()) + self.expect_one_of(slice::ref_slice(t), &[]); } } @@ -392,15 +414,20 @@ impl<'a> Parser<'a> { pub fn expect_one_of(&mut self, edible: &[token::Token], inedible: &[token::Token]) { - fn tokens_to_string(tokens: &[token::Token]) -> String { + fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); // This might be a sign we need a connect method on Iterator. let b = i.next() - .map_or("".to_string(), |t| Parser::token_to_string(t)); - i.fold(b, |b,a| { - let mut b = b; - b.push_str("`, `"); - b.push_str(Parser::token_to_string(a).as_slice()); + .map_or("".into_string(), |t| t.to_string()); + i.enumerate().fold(b, |mut b, (i, ref a)| { + if tokens.len() > 2 && i == tokens.len() - 2 { + b.push_str(", or "); + } else if tokens.len() == 2 && i == tokens.len() - 2 { + b.push_str(" or "); + } else { + b.push_str(", "); + } + b.push_str(&*a.to_string()); b }) } @@ -409,17 +436,21 @@ impl<'a> Parser<'a> { } else if inedible.contains(&self.token) { // leave it in the input } else { - let mut expected = edible.iter().map(|x| x.clone()).collect::<Vec<_>>(); - expected.push_all(inedible); + let mut expected = edible.iter().map(|x| TokenType::Token(x.clone())) + .collect::<Vec<_>>(); + expected.extend(inedible.iter().map(|x| TokenType::Token(x.clone()))); + expected.push_all(&*self.expected_tokens); + expected.sort_by(|a, b| a.to_string().cmp(&b.to_string())); + expected.dedup(); let expect = tokens_to_string(expected.as_slice()); let actual = self.this_token_to_string(); self.fatal( (if expected.len() != 1 { - (format!("expected one of `{}`, found `{}`", + (format!("expected one of {}, found `{}`", expect, actual)) } else { - (format!("expected `{}`, found `{}`", + (format!("expected {}, found `{}`", expect, actual)) }).as_slice() @@ -514,10 +545,20 @@ impl<'a> Parser<'a> { spanned(lo, hi, node) } + /// Check if the next token is `tok`, and return `true` if so. + /// + /// This method is will automatically add `tok` to `expected_tokens` if `tok` is not + /// encountered. + pub fn check(&mut self, tok: &token::Token) -> bool { + let is_present = self.token == *tok; + if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } + is_present + } + /// Consume token 'tok' if it exists. Returns true if the given /// token was present, false otherwise. pub fn eat(&mut self, tok: &token::Token) -> bool { - let is_present = self.token == *tok; + let is_present = self.check(tok); if is_present { self.bump() } is_present } @@ -739,7 +780,7 @@ impl<'a> Parser<'a> { // commas in generic parameters, because it can stop either after // parsing a type or after parsing a comma. for i in iter::count(0u, 1) { - if self.token == token::Gt + if self.check(&token::Gt) || self.token == token::BinOp(token::Shr) || self.token == token::Ge || self.token == token::BinOpEq(token::Shr) { @@ -798,7 +839,7 @@ impl<'a> Parser<'a> { } _ => () } - if sep.trailing_sep_allowed && self.token == *ket { break; } + if sep.trailing_sep_allowed && self.check(ket) { break; } v.push(f(self)); } return v; @@ -881,6 +922,7 @@ impl<'a> Parser<'a> { self.span = next.sp; self.token = next.tok; self.tokens_consumed += 1u; + self.expected_tokens.clear(); } /// Advance the parser by one token and return the bumped token. @@ -999,7 +1041,7 @@ impl<'a> Parser<'a> { self.parse_proc_type(lifetime_defs) } else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() { self.parse_ty_bare_fn_or_ty_closure(lifetime_defs) - } else if self.token == token::ModSep || + } else if self.check(&token::ModSep) || self.token.is_ident() || self.token.is_path() { @@ -1101,7 +1143,7 @@ impl<'a> Parser<'a> { /// Parses an optional unboxed closure kind (`&:`, `&mut:`, or `:`). pub fn parse_optional_unboxed_closure_kind(&mut self) -> Option<UnboxedClosureKind> { - if self.token == token::BinOp(token::And) && + if self.check(&token::BinOp(token::And)) && self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(2, |t| *t == token::Colon) { self.bump(); @@ -1211,7 +1253,8 @@ impl<'a> Parser<'a> { lifetime_defs: Vec<ast::LifetimeDef>) -> Vec<ast::LifetimeDef> { - if self.eat(&token::Lt) { + if self.token == token::Lt { + self.bump(); if lifetime_defs.is_empty() { self.warn("deprecated syntax; use the `for` keyword now \ (e.g. change `fn<'a>` to `for<'a> fn`)"); @@ -1430,7 +1473,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let t = if self.token == token::OpenDelim(token::Paren) { + let t = if self.check(&token::OpenDelim(token::Paren)) { self.bump(); // (t) is a parenthesized ty @@ -1440,7 +1483,7 @@ impl<'a> Parser<'a> { let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { ts.push(self.parse_ty_sum()); - if self.token == token::Comma { + if self.check(&token::Comma) { last_comma = true; self.bump(); } else { @@ -1464,11 +1507,11 @@ impl<'a> Parser<'a> { _ => self.obsolete(last_span, ObsoleteOwnedType) } TyTup(vec![self.parse_ty()]) - } else if self.token == token::BinOp(token::Star) { + } else if self.check(&token::BinOp(token::Star)) { // STAR POINTER (bare pointer?) self.bump(); TyPtr(self.parse_ptr()) - } else if self.token == token::OpenDelim(token::Bracket) { + } else if self.check(&token::OpenDelim(token::Bracket)) { // VECTOR self.expect(&token::OpenDelim(token::Bracket)); let t = self.parse_ty_sum(); @@ -1481,7 +1524,7 @@ impl<'a> Parser<'a> { }; self.expect(&token::CloseDelim(token::Bracket)); t - } else if self.token == token::BinOp(token::And) || + } else if self.check(&token::BinOp(token::And)) || self.token == token::AndAnd { // BORROWED POINTER self.expect_and(); @@ -1492,7 +1535,7 @@ impl<'a> Parser<'a> { self.token_is_closure_keyword() { // BARE FUNCTION OR CLOSURE self.parse_ty_bare_fn_or_ty_closure(Vec::new()) - } else if self.token == token::BinOp(token::Or) || + } else if self.check(&token::BinOp(token::Or)) || self.token == token::OrOr || (self.token == token::Lt && self.look_ahead(1, |t| { @@ -1509,7 +1552,7 @@ impl<'a> Parser<'a> { TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type(Vec::new()) - } else if self.token == token::Lt { + } else if self.check(&token::Lt) { // QUALIFIED PATH `<TYPE as TRAIT_REF>::item` self.bump(); let self_type = self.parse_ty_sum(); @@ -1523,7 +1566,7 @@ impl<'a> Parser<'a> { trait_ref: P(trait_ref), item_name: item_name, })) - } else if self.token == token::ModSep || + } else if self.check(&token::ModSep) || self.token.is_ident() || self.token.is_path() { // NAMED TYPE @@ -1532,7 +1575,8 @@ impl<'a> Parser<'a> { // TYPE TO BE INFERRED TyInfer } else { - let msg = format!("expected type, found token {}", self.token); + let this_token_str = self.this_token_to_string(); + let msg = format!("expected type, found `{}`", this_token_str); self.fatal(msg.as_slice()); }; @@ -1635,7 +1679,7 @@ impl<'a> Parser<'a> { } pub fn maybe_parse_fixed_vstore(&mut self) -> Option<P<ast::Expr>> { - if self.token == token::Comma && + if self.check(&token::Comma) && self.look_ahead(1, |t| *t == token::DotDot) { self.bump(); self.bump(); @@ -1959,9 +2003,10 @@ impl<'a> Parser<'a> { token::Gt => { return res; } token::BinOp(token::Shr) => { return res; } _ => { + let this_token_str = self.this_token_to_string(); let msg = format!("expected `,` or `>` after lifetime \ - name, got: {}", - self.token); + name, found `{}`", + this_token_str); self.fatal(msg.as_slice()); } } @@ -2126,7 +2171,7 @@ impl<'a> Parser<'a> { es.push(self.parse_expr()); self.commit_expr(&**es.last().unwrap(), &[], &[token::Comma, token::CloseDelim(token::Paren)]); - if self.token == token::Comma { + if self.check(&token::Comma) { trailing_comma = true; self.bump(); @@ -2167,14 +2212,14 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); - if self.token == token::CloseDelim(token::Bracket) { + if self.check(&token::CloseDelim(token::Bracket)) { // Empty vector. self.bump(); ex = ExprVec(Vec::new()); } else { // Nonempty vector. let first_expr = self.parse_expr(); - if self.token == token::Comma && + if self.check(&token::Comma) && self.look_ahead(1, |t| *t == token::DotDot) { // Repeating vector syntax: [ 0, ..512 ] self.bump(); @@ -2182,7 +2227,7 @@ impl<'a> Parser<'a> { let count = self.parse_expr(); self.expect(&token::CloseDelim(token::Bracket)); ex = ExprRepeat(first_expr, count); - } else if self.token == token::Comma { + } else if self.check(&token::Comma) { // Vector with two or more elements. self.bump(); let remaining_exprs = self.parse_seq_to_end( @@ -2284,7 +2329,7 @@ impl<'a> Parser<'a> { ex = ExprBreak(None); } hi = self.span.hi; - } else if self.token == token::ModSep || + } else if self.check(&token::ModSep) || self.token.is_ident() && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False) { @@ -2292,7 +2337,7 @@ impl<'a> Parser<'a> { self.parse_path(LifetimeAndTypesWithColons); // `!`, as an operator, is prefix, so we know this isn't that - if self.token == token::Not { + if self.check(&token::Not) { // MACRO INVOCATION expression self.bump(); @@ -2309,7 +2354,7 @@ impl<'a> Parser<'a> { tts, EMPTY_CTXT)); } - if self.token == token::OpenDelim(token::Brace) { + if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited // from parsing struct literals here. if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) { @@ -2840,6 +2885,7 @@ impl<'a> Parser<'a> { self.restrictions.contains(RESTRICTION_NO_BAR_OP) { return lhs; } + self.expected_tokens.push(TokenType::Operator); let cur_opt = self.token.to_binop(); match cur_opt { @@ -3079,7 +3125,7 @@ impl<'a> Parser<'a> { /// Parse the RHS of a local variable declaration (e.g. '= 14;') fn parse_initializer(&mut self) -> Option<P<Expr>> { - if self.token == token::Eq { + if self.check(&token::Eq) { self.bump(); Some(self.parse_expr()) } else { @@ -3092,7 +3138,7 @@ impl<'a> Parser<'a> { let mut pats = Vec::new(); loop { pats.push(self.parse_pat()); - if self.token == token::BinOp(token::Or) { self.bump(); } + if self.check(&token::BinOp(token::Or)) { self.bump(); } else { return pats; } }; } @@ -3111,14 +3157,19 @@ impl<'a> Parser<'a> { first = false; } else { self.expect(&token::Comma); + + if self.token == token::CloseDelim(token::Bracket) + && (before_slice || after.len() != 0) { + break + } } if before_slice { - if self.token == token::DotDot { + if self.check(&token::DotDot) { self.bump(); - if self.token == token::Comma || - self.token == token::CloseDelim(token::Bracket) { + if self.check(&token::Comma) || + self.check(&token::CloseDelim(token::Bracket)) { slice = Some(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: PatWild(PatWildMulti), @@ -3135,7 +3186,7 @@ impl<'a> Parser<'a> { } let subpat = self.parse_pat(); - if before_slice && self.token == token::DotDot { + if before_slice && self.check(&token::DotDot) { self.bump(); slice = Some(subpat); before_slice = false; @@ -3160,13 +3211,13 @@ impl<'a> Parser<'a> { } else { self.expect(&token::Comma); // accept trailing commas - if self.token == token::CloseDelim(token::Brace) { break } + if self.check(&token::CloseDelim(token::Brace)) { break } } let lo = self.span.lo; let hi; - if self.token == token::DotDot { + if self.check(&token::DotDot) { self.bump(); if self.token != token::CloseDelim(token::Brace) { let token_str = self.this_token_to_string(); @@ -3187,7 +3238,7 @@ impl<'a> Parser<'a> { let fieldname = self.parse_ident(); - let (subpat, is_shorthand) = if self.token == token::Colon { + let (subpat, is_shorthand) = if self.check(&token::Colon) { match bind_type { BindByRef(..) | BindByValue(MutMutable) => { let token_str = self.this_token_to_string(); @@ -3267,15 +3318,15 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => { // parse (pat,pat,pat,...) as tuple self.bump(); - if self.token == token::CloseDelim(token::Paren) { + if self.check(&token::CloseDelim(token::Paren)) { self.bump(); pat = PatTup(vec![]); } else { let mut fields = vec!(self.parse_pat()); if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { - while self.token == token::Comma { + while self.check(&token::Comma) { self.bump(); - if self.token == token::CloseDelim(token::Paren) { break; } + if self.check(&token::CloseDelim(token::Paren)) { break; } fields.push(self.parse_pat()); } } @@ -3318,7 +3369,7 @@ impl<'a> Parser<'a> { // These expressions are limited to literals (possibly // preceded by unary-minus) or identifiers. let val = self.parse_literal_maybe_minus(); - if (self.token == token::DotDotDot) && + if (self.check(&token::DotDotDot)) && self.look_ahead(1, |t| { *t != token::Comma && *t != token::CloseDelim(token::Bracket) }) { @@ -3621,7 +3672,7 @@ impl<'a> Parser<'a> { let hi = self.span.hi; if id.name == token::special_idents::invalid.name { - if self.token == token::Dot { + if self.check(&token::Dot) { let span = self.span; let token_string = self.this_token_to_string(); self.span_err(span, @@ -3934,7 +3985,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_colon_then_ty_param_bounds(); - let default = if self.token == token::Eq { + let default = if self.check(&token::Eq) { self.bump(); Some(self.parse_ty_sum()) } @@ -4334,7 +4385,7 @@ impl<'a> Parser<'a> { (optional_unboxed_closure_kind, args) } }; - let output = if self.token == token::RArrow { + let output = if self.check(&token::RArrow) { self.parse_ret_ty() } else { Return(P(Ty { @@ -4359,7 +4410,7 @@ impl<'a> Parser<'a> { seq_sep_trailing_allowed(token::Comma), |p| p.parse_fn_block_arg()); - let output = if self.token == token::RArrow { + let output = if self.check(&token::RArrow) { self.parse_ret_ty() } else { Return(P(Ty { @@ -4616,7 +4667,7 @@ impl<'a> Parser<'a> { token::get_ident(class_name)).as_slice()); } self.bump(); - } else if self.token == token::OpenDelim(token::Paren) { + } else if self.check(&token::OpenDelim(token::Paren)) { // It's a tuple-like struct. is_tuple_like = true; fields = self.parse_unspanned_seq( @@ -4801,7 +4852,7 @@ impl<'a> Parser<'a> { fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> ItemInfo { let id_span = self.span; let id = self.parse_ident(); - if self.token == token::Semi { + if self.check(&token::Semi) { self.bump(); // This mod is in an external file. Let's go get it! let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span); @@ -5044,7 +5095,8 @@ impl<'a> Parser<'a> { let (maybe_path, ident) = match self.token { token::Ident(..) => { let the_ident = self.parse_ident(); - let path = if self.eat(&token::Eq) { + let path = if self.token == token::Eq { + self.bump(); let path = self.parse_str(); let span = self.span; self.obsolete(span, ObsoleteExternCrateRenaming); @@ -5184,7 +5236,7 @@ impl<'a> Parser<'a> { token::get_ident(ident)).as_slice()); } kind = StructVariantKind(struct_def); - } else if self.token == token::OpenDelim(token::Paren) { + } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; let arg_tys = self.parse_enum_variant_seq( &token::OpenDelim(token::Paren), @@ -5348,7 +5400,7 @@ impl<'a> Parser<'a> { visibility, maybe_append(attrs, extra_attrs)); return IoviItem(item); - } else if self.token == token::OpenDelim(token::Brace) { + } else if self.check(&token::OpenDelim(token::Brace)) { return self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs); } @@ -5629,7 +5681,7 @@ impl<'a> Parser<'a> { fn parse_view_path(&mut self) -> P<ViewPath> { let lo = self.span.lo; - if self.token == token::OpenDelim(token::Brace) { + if self.check(&token::OpenDelim(token::Brace)) { // use {foo,bar} let idents = self.parse_unspanned_seq( &token::OpenDelim(token::Brace), @@ -5653,7 +5705,7 @@ impl<'a> Parser<'a> { self.bump(); let path_lo = self.span.lo; path = vec!(self.parse_ident()); - while self.token == token::ModSep { + while self.check(&token::ModSep) { self.bump(); let id = self.parse_ident(); path.push(id); @@ -5677,7 +5729,7 @@ impl<'a> Parser<'a> { token::ModSep => { // foo::bar or foo::{a,b,c} or foo::* - while self.token == token::ModSep { + while self.check(&token::ModSep) { self.bump(); match self.token { @@ -5846,7 +5898,7 @@ impl<'a> Parser<'a> { loop { match self.parse_foreign_item(attrs, macros_allowed) { IoviNone(returned_attrs) => { - if self.token == token::CloseDelim(token::Brace) { + if self.check(&token::CloseDelim(token::Brace)) { attrs = returned_attrs; break } diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index d644542db07..3c909a3c708 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -576,7 +576,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> { #[cfg(test)] mod test { use super::{expand,Param,Words,Variables,Number}; - use std::result::Ok; + use std::result::Result::Ok; #[test] fn test_basic_setabf() { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index fbc60c9b342..c943d8706e5 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -51,8 +51,7 @@ use std::collections::TreeMap; use stats::Stats; use getopts::{OptGroup, optflag, optopt}; use regex::Regex; -use serialize::{json, Decodable}; -use serialize::json::{Json, ToJson}; +use serialize::{json, Decodable, Encodable}; use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; @@ -286,6 +285,9 @@ pub struct TestOpts { pub logfile: Option<Path>, pub nocapture: bool, pub color: ColorConfig, + pub show_boxplot: bool, + pub boxplot_width: uint, + pub show_all_stats: bool, } impl TestOpts { @@ -303,6 +305,9 @@ impl TestOpts { logfile: None, nocapture: false, color: AutoColor, + show_boxplot: false, + boxplot_width: 50, + show_all_stats: false, } } } @@ -333,7 +338,10 @@ fn optgroups() -> Vec<getopts::OptGroup> { getopts::optopt("", "color", "Configure coloring of output: auto = colorize if stdout is a tty and tests are run on serially (default); always = always colorize output; - never = never colorize output;", "auto|always|never")) + never = never colorize output;", "auto|always|never"), + getopts::optflag("", "boxplot", "Display a boxplot of the benchmark statistics"), + getopts::optopt("", "boxplot-width", "Set the boxplot width (default 50)", "WIDTH"), + getopts::optflag("", "stats", "Display the benchmark min, max, and quartiles")) } fn usage(binary: &str) { @@ -424,6 +432,21 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> { v))), }; + let show_boxplot = matches.opt_present("boxplot"); + let boxplot_width = match matches.opt_str("boxplot-width") { + Some(width) => { + match FromStr::from_str(width.as_slice()) { + Some(width) => width, + None => { + return Some(Err(format!("argument for --boxplot-width must be a uint"))); + } + } + } + None => 50, + }; + + let show_all_stats = matches.opt_present("stats"); + let test_opts = TestOpts { filter: filter, run_ignored: run_ignored, @@ -436,6 +459,9 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> { logfile: logfile, nocapture: nocapture, color: color, + show_boxplot: show_boxplot, + boxplot_width: boxplot_width, + show_all_stats: show_all_stats, }; Some(Ok(test_opts)) @@ -486,6 +512,9 @@ struct ConsoleTestState<T> { log_out: Option<File>, out: OutputLocation<T>, use_color: bool, + show_boxplot: bool, + boxplot_width: uint, + show_all_stats: bool, total: uint, passed: uint, failed: uint, @@ -512,6 +541,9 @@ impl<T: Writer> ConsoleTestState<T> { out: out, log_out: log_out, use_color: use_color(opts), + show_boxplot: opts.show_boxplot, + boxplot_width: opts.boxplot_width, + show_all_stats: opts.show_all_stats, total: 0u, passed: 0u, failed: 0u, @@ -607,8 +639,31 @@ impl<T: Writer> ConsoleTestState<T> { } TrBench(ref bs) => { try!(self.write_bench()); - self.write_plain(format!(": {}", - fmt_bench_samples(bs)).as_slice()) + + if self.show_boxplot { + let mut wr = Vec::new(); + + try!(stats::write_boxplot(&mut wr, &bs.ns_iter_summ, self.boxplot_width)); + + let s = String::from_utf8(wr).unwrap(); + + try!(self.write_plain(format!(": {}", s).as_slice())); + } + + if self.show_all_stats { + let mut wr = Vec::new(); + + try!(stats::write_5_number_summary(&mut wr, &bs.ns_iter_summ)); + + let s = String::from_utf8(wr).unwrap(); + + try!(self.write_plain(format!(": {}", s).as_slice())); + } else { + try!(self.write_plain(format!(": {}", + fmt_bench_samples(bs)).as_slice())); + } + + Ok(()) } }); self.write_plain("\n") @@ -681,14 +736,14 @@ impl<T: Writer> ConsoleTestState<T> { } Improvement(pct) => { improved += 1; - try!(self.write_plain(format!(": {}", *k).as_slice())); + try!(self.write_plain(format!(": {} ", *k).as_slice())); try!(self.write_improved()); try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); } Regression(pct) => { regressed += 1; - try!(self.write_plain(format!(": {}", *k).as_slice())); + try!(self.write_plain(format!(": {} ", *k).as_slice())); try!(self.write_regressed()); try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); @@ -860,6 +915,9 @@ fn should_sort_failures_before_printing_them() { log_out: None, out: Raw(Vec::new()), use_color: false, + show_boxplot: false, + boxplot_width: 0, + show_all_stats: false, total: 0u, passed: 0u, failed: 0u, @@ -1100,17 +1158,6 @@ fn calc_result(desc: &TestDesc, task_succeeded: bool) -> TestResult { } } - -impl ToJson for Metric { - fn to_json(&self) -> json::Json { - let mut map = TreeMap::new(); - map.insert("value".to_string(), json::Json::F64(self.value)); - map.insert("noise".to_string(), json::Json::F64(self.noise)); - json::Json::Object(map) - } -} - - impl MetricMap { pub fn new() -> MetricMap { @@ -1138,14 +1185,8 @@ impl MetricMap { pub fn save(&self, p: &Path) -> io::IoResult<()> { let mut file = try!(File::create(p)); let MetricMap(ref map) = *self; - - // FIXME(pcwalton): Yuck. - let mut new_map = TreeMap::new(); - for (ref key, ref value) in map.iter() { - new_map.insert(key.to_string(), (*value).clone()); - } - - new_map.to_json().to_pretty_writer(&mut file) + let mut enc = json::PrettyEncoder::new(&mut file); + map.encode(&mut enc) } /// Compare against another MetricMap. Optionally compare all diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index ab6756ffce3..c157fb10bd4 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -331,8 +331,8 @@ pub fn winsorize<T: Float + FromPrimitive>(samples: &mut [T], pct: T) { } /// Render writes the min, max and quartiles of the provided `Summary` to the provided `Writer`. -pub fn write_5_number_summary<T: Float + Show>(w: &mut io::Writer, - s: &Summary<T>) -> io::IoResult<()> { +pub fn write_5_number_summary<W: Writer, T: Float + Show>(w: &mut W, + s: &Summary<T>) -> io::IoResult<()> { let (q1,q2,q3) = s.quartiles; write!(w, "(min={}, q1={}, med={}, q3={}, max={})", s.min, @@ -353,8 +353,8 @@ pub fn write_5_number_summary<T: Float + Show>(w: &mut io::Writer, /// ```{.ignore} /// 10 | [--****#******----------] | 40 /// ``` -pub fn write_boxplot<T: Float + Show + FromPrimitive>( - w: &mut io::Writer, +pub fn write_boxplot<W: Writer, T: Float + Show + FromPrimitive>( + w: &mut W, s: &Summary<T>, width_hint: uint) -> io::IoResult<()> { @@ -473,7 +473,7 @@ mod tests { let summ2 = Summary::new(samples); let mut w = io::stdout(); - let w = &mut w as &mut io::Writer; + let w = &mut w; (write!(w, "\n")).unwrap(); write_5_number_summary(w, &summ2).unwrap(); (write!(w, "\n")).unwrap(); @@ -1028,7 +1028,7 @@ mod tests { fn test_boxplot_nonpositive() { fn t(s: &Summary<f64>, expected: String) { let mut m = Vec::new(); - write_boxplot(&mut m as &mut io::Writer, s, 30).unwrap(); + write_boxplot(&mut m, s, 30).unwrap(); let out = String::from_utf8(m).unwrap(); assert_eq!(out, expected); } diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index a77a6276a8b..06a0df852b9 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -1262,7 +1262,7 @@ mod tests { InvalidFormatSpecifier}; use std::f64; - use std::result::{Err, Ok}; + use std::result::Result::{Err, Ok}; use std::time::Duration; use self::test::Bencher; diff --git a/src/libunicode/normalize.rs b/src/libunicode/normalize.rs index cd46fc6a56d..29a8b1204b8 100644 --- a/src/libunicode/normalize.rs +++ b/src/libunicode/normalize.rs @@ -10,8 +10,9 @@ //! Functions for computing canonical and compatible decompositions for Unicode characters. -use core::cmp::{Equal, Less, Greater}; -use core::option::{Option, Some, None}; +use core::cmp::Ordering::{Equal, Less, Greater}; +use core::option::Option; +use core::option::Option::{Some, None}; use core::slice; use core::slice::SlicePrelude; use tables::normalization::{canonical_table, compatibility_table, composition_table}; diff --git a/src/libunicode/tables.rs b/src/libunicode/tables.rs index 7cece6701dc..c91ce5c6464 100644 --- a/src/libunicode/tables.rs +++ b/src/libunicode/tables.rs @@ -17,7 +17,7 @@ pub const UNICODE_VERSION: (uint, uint, uint) = (7, 0, 0); fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; r.binary_search(|&(lo,hi)| { if lo <= c && c <= hi { Equal } @@ -6241,7 +6241,7 @@ pub mod normalization { fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; use core::slice; match r.binary_search(|&(lo, hi, _)| { @@ -6366,10 +6366,11 @@ pub mod normalization { } pub mod conversions { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; use core::slice::SlicePrelude; use core::tuple::Tuple2; - use core::option::{Option, Some, None}; + use core::option::Option; + use core::option::Option::{Some, None}; use core::slice; pub fn to_lower(c: char) -> char { @@ -6934,12 +6935,13 @@ pub mod conversions { } pub mod charwidth { - use core::option::{Option, Some, None}; + use core::option::Option; + use core::option::Option::{Some, None}; use core::slice::SlicePrelude; use core::slice; fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; match r.binary_search(|&(lo, hi, _, _)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } @@ -7154,7 +7156,7 @@ pub mod grapheme { } fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat { - use core::cmp::{Equal, Less, Greater}; + use core::cmp::Ordering::{Equal, Less, Greater}; match r.binary_search(|&(lo, hi, _)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index a5f76142575..e4b2b682b2c 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -21,7 +21,8 @@ use core::slice::SlicePrelude; use core::iter::{Filter, AdditiveIterator, Iterator, IteratorExt}; use core::iter::{DoubleEndedIterator, DoubleEndedIteratorExt}; use core::kinds::Sized; -use core::option::{Option, None, Some}; +use core::option::Option; +use core::option::Option::{None, Some}; use core::str::{CharSplits, StrPrelude}; use u_char::UnicodeChar; use tables::grapheme::GraphemeCat; diff --git a/src/snapshots.txt b/src/snapshots.txt index 0faf6840f06..a1a840b4deb 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,12 @@ +S 2014-12-05 361baab + freebsd-x86_64 73cbae4168538a07facd81cca45ed672badb7c3a + linux-i386 211cf0fbdbc7045b765e7b92d92049bbe6788513 + linux-x86_64 f001cec306fc1ac77504884acf5dac2e7b39e164 + macos-i386 751dc02fac96114361c56eb45ce52e7a58d555e0 + macos-x86_64 58cad0275d7b33412501d7dd3386b924d2304e83 + winnt-i386 872c56b88cebd7d590fd00bcbd264f0003b4427b + winnt-x86_64 2187d8b3187c03f95cd4e56a582f55ec0cfa8df9 + S 2014-11-21 c9f6d69 freebsd-x86_64 0ef316e7c369177de043e69e964418bd637cbfc0 linux-i386 c8342e762a1720be939ed7c6a39bdaa27892f66f diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index d06e6c8cd19..863c3c879a7 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -19,28 +19,30 @@ // ignore-lexer-test FIXME #15679 use std::os; -use std::sync::{Arc, Future, Mutex}; +use std::sync::{Arc, Future, Mutex, Condvar}; use std::time::Duration; use std::uint; // A poor man's pipe. -type pipe = Arc<Mutex<Vec<uint>>>; +type pipe = Arc<(Mutex<Vec<uint>>, Condvar)>; fn send(p: &pipe, msg: uint) { - let mut arr = p.lock(); + let &(ref lock, ref cond) = &**p; + let mut arr = lock.lock(); arr.push(msg); - arr.cond.signal(); + cond.notify_one(); } fn recv(p: &pipe) -> uint { - let mut arr = p.lock(); + let &(ref lock, ref cond) = &**p; + let mut arr = lock.lock(); while arr.is_empty() { - arr.cond.wait(); + cond.wait(&arr); } arr.pop().unwrap() } fn init() -> (pipe,pipe) { - let m = Arc::new(Mutex::new(Vec::new())); + let m = Arc::new((Mutex::new(Vec::new()), Condvar::new())); ((&m).clone(), m) } diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs deleted file mode 100644 index 03066d40512..00000000000 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This test creates a bunch of tasks that simultaneously send to each -// other in a ring. The messages should all be basically -// independent. -// This is like msgsend-ring-pipes but adapted to use Arcs. - -// This also serves as a pipes test, because Arcs are implemented with pipes. - -// no-pretty-expanded FIXME #15189 -// ignore-lexer-test FIXME #15679 - -use std::os; -use std::sync::{RWLock, Arc, Future}; -use std::time::Duration; -use std::uint; - -// A poor man's pipe. -type pipe = Arc<RWLock<Vec<uint>>>; - -fn send(p: &pipe, msg: uint) { - let mut arr = p.write(); - arr.push(msg); - arr.cond.signal(); -} -fn recv(p: &pipe) -> uint { - let mut arr = p.write(); - while arr.is_empty() { - arr.cond.wait(); - } - arr.pop().unwrap() -} - -fn init() -> (pipe,pipe) { - let x = Arc::new(RWLock::new(Vec::new())); - ((&x).clone(), x) -} - - -fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) { - let mut num_chan = Some(num_chan); - let mut num_port = Some(num_port); - // Send/Receive lots of messages. - for j in range(0u, count) { - //println!("task %?, iter %?", i, j); - let num_chan2 = num_chan.take().unwrap(); - let num_port2 = num_port.take().unwrap(); - send(&num_chan2, i * j); - num_chan = Some(num_chan2); - let _n = recv(&num_port2); - //log(error, _n); - num_port = Some(num_port2); - }; -} - -fn main() { - let args = os::args(); - let args = if os::getenv("RUST_BENCH").is_some() { - vec!("".to_string(), "100".to_string(), "10000".to_string()) - } else if args.len() <= 1u { - vec!("".to_string(), "10".to_string(), "100".to_string()) - } else { - args.clone().into_iter().collect() - }; - - let num_tasks = from_str::<uint>(args[1].as_slice()).unwrap(); - let msg_per_task = from_str::<uint>(args[2].as_slice()).unwrap(); - - let (mut num_chan, num_port) = init(); - - let mut p = Some((num_chan, num_port)); - let dur = Duration::span(|| { - let (mut num_chan, num_port) = p.take().unwrap(); - - // create the ring - let mut futures = Vec::new(); - - for i in range(1u, num_tasks) { - //println!("spawning %?", i); - let (new_chan, num_port) = init(); - let num_chan_2 = num_chan.clone(); - let new_future = Future::spawn(proc() { - thread_ring(i, msg_per_task, num_chan_2, num_port) - }); - futures.push(new_future); - num_chan = new_chan; - }; - - // do our iteration - thread_ring(0, msg_per_task, num_chan, num_port); - - // synchronize - for f in futures.iter_mut() { - let _ = f.get(); - } - }); - - // all done, report stats. - let num_msgs = num_tasks * msg_per_task; - let rate = (num_msgs as f64) / (dur.num_milliseconds() as f64); - - println!("Sent {} messages in {} ms", num_msgs, dur.num_milliseconds()); - println!(" {} messages / second", rate / 1000.0); - println!(" {} μs / message", 1000000. / rate / 1000.0); -} diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 4005c11e6b6..45d2cbea8fa 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -77,8 +77,8 @@ fn sort_and_fmt(mm: &HashMap<Vec<u8> , uint>, total: uint) -> String { fn find(mm: &HashMap<Vec<u8> , uint>, key: String) -> uint { let key = key.into_ascii().as_slice().to_lowercase().into_string(); match mm.get(key.as_bytes()) { - option::None => { return 0u; } - option::Some(&num) => { return num; } + option::Option::None => { return 0u; } + option::Option::Some(&num) => { return num; } } } @@ -190,8 +190,8 @@ fn main() { // start processing if this is the one ('>', false) => { match line.as_slice().slice_from(1).find_str("THREE") { - option::Some(_) => { proc_mode = true; } - option::None => { } + option::Option::Some(_) => { proc_mode = true; } + option::Option::None => { } } } diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index b030e7bb93e..8ed041513c4 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -295,7 +295,7 @@ fn main() { let fd = std::io::File::open(&Path::new("shootout-k-nucleotide.data")); get_sequence(&mut std::io::BufferedReader::new(fd), ">THREE") } else { - get_sequence(&mut std::io::stdin(), ">THREE") + get_sequence(&mut *std::io::stdin().lock(), ">THREE") }; let input = Arc::new(input); diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 9cc86e91fbe..15a5cb0c9bf 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -21,7 +21,7 @@ extern crate getopts; use std::os; -use std::result::{Ok, Err}; +use std::result::Result::{Ok, Err}; use std::task; use std::time::Duration; diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 6664eeecd5d..c55f85f40e8 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -65,7 +65,7 @@ impl Sudoku { return true; } - pub fn read(mut reader: BufferedReader<StdReader>) -> Sudoku { + pub fn read(mut reader: &mut BufferedReader<StdReader>) -> Sudoku { /* assert first line is exactly "9,9" */ assert!(reader.read_line().unwrap() == "9,9".to_string()); @@ -284,7 +284,7 @@ fn main() { let mut sudoku = if use_default { Sudoku::from_vec(&DEFAULT_SUDOKU) } else { - Sudoku::read(io::stdin()) + Sudoku::read(&mut *io::stdin().lock()) }; sudoku.solve(); sudoku.write(&mut io::stdout()); diff --git a/src/test/compile-fail/rustc-diagnostics-2.rs b/src/test/compile-fail/better-expected.rs index c4e011bcea0..489f892726a 100644 --- a/src/test/compile-fail/rustc-diagnostics-2.rs +++ b/src/test/compile-fail/better-expected.rs @@ -8,13 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_diagnostic_macros)] - -__register_diagnostic!(E0001) -__register_diagnostic!(E0001) -//~^ ERROR diagnostic code E0001 already registered - fn main() { + let x: [int ..3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `..` } - -__build_diagnostic_array!(DIAGNOSTICS) diff --git a/src/test/compile-fail/borrow-tuple-fields.rs b/src/test/compile-fail/borrow-tuple-fields.rs index 519bad4e627..1d09143c24d 100644 --- a/src/test/compile-fail/borrow-tuple-fields.rs +++ b/src/test/compile-fail/borrow-tuple-fields.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - struct Foo(Box<int>, int); struct Bar(int, int); diff --git a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs index fcb09c20000..daad1afedaa 100644 --- a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs +++ b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs @@ -14,6 +14,6 @@ fn main() { //~^ ERROR: cannot assign to immutable captured outer variable in a proc `x` let s = std::io::stdin(); - proc() { s.lines(); }; + proc() { s.read_to_end(); }; //~^ ERROR: cannot borrow immutable captured outer variable in a proc `s` as mutable } diff --git a/src/test/compile-fail/column-offset-1-based.rs b/src/test/compile-fail/column-offset-1-based.rs index a00ded61758..621b480fe77 100644 --- a/src/test/compile-fail/column-offset-1-based.rs +++ b/src/test/compile-fail/column-offset-1-based.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -# //~ ERROR 11:1: 11:2 error: expected `[`, found `<eof>` +# //~ ERROR 11:1: 11:2 error: expected one of `!` or `[`, found `<eof>` diff --git a/src/test/compile-fail/empty-impl-semicolon.rs b/src/test/compile-fail/empty-impl-semicolon.rs index b5f17eef886..a598252f1b6 100644 --- a/src/test/compile-fail/empty-impl-semicolon.rs +++ b/src/test/compile-fail/empty-impl-semicolon.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -impl Foo; //~ ERROR expected `{`, found `;` +impl Foo; //~ ERROR expected one of `(`, `+`, `::`, or `{`, found `;` diff --git a/src/test/compile-fail/if-let.rs b/src/test/compile-fail/if-let.rs index b82fb7a94c9..88b6854bb1d 100644 --- a/src/test/compile-fail/if-let.rs +++ b/src/test/compile-fail/if-let.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(macro_rules,if_let)] +#![feature(macro_rules)] fn macros() { macro_rules! foo{ diff --git a/src/test/compile-fail/issue-1655.rs b/src/test/compile-fail/issue-1655.rs index 6bdcf5c5edc..a8704f7545f 100644 --- a/src/test/compile-fail/issue-1655.rs +++ b/src/test/compile-fail/issue-1655.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected `[`, found `vec` +// error-pattern:expected one of `!` or `[`, found `vec` mod blade_runner { #vec[doc( brief = "Blade Runner is probably the best movie ever", diff --git a/src/test/compile-fail/issue-18566.rs b/src/test/compile-fail/issue-18566.rs index 89b1d8540d8..f64d8fee2d8 100644 --- a/src/test/compile-fail/issue-18566.rs +++ b/src/test/compile-fail/issue-18566.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - struct MyPtr<'a>(&'a mut uint); impl<'a> Deref<uint> for MyPtr<'a> { fn deref<'b>(&'b self) -> &'b uint { self.0 } diff --git a/src/test/compile-fail/rustc-diagnostics-1.rs b/src/test/compile-fail/issue-18959.rs index 55d836092fa..3d126790335 100644 --- a/src/test/compile-fail/rustc-diagnostics-1.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -8,21 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_diagnostic_macros)] +pub trait Foo for Sized? { fn foo<T>(&self, ext_thing: &T); } +pub trait Bar for Sized?: Foo { } +impl<T: Foo> Bar for T { } -__register_diagnostic!(E0001) -__register_diagnostic!(E0003) - -fn main() { - __diagnostic_used!(E0002); - //~^ ERROR unknown diagnostic code E0002 +pub struct Thing; +impl Foo for Thing { + fn foo<T>(&self, _: &T) {} +} - __diagnostic_used!(E0001); - //~^ NOTE previous invocation +#[inline(never)] fn foo(b: &Bar) { b.foo(&0u) } - __diagnostic_used!(E0001); - //~^ WARNING diagnostic code E0001 already used +fn main() { + let mut thing = Thing; + let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object because trait `Foo` + foo(test); } - -__build_diagnostic_array!(DIAGNOSTICS) -//~^ WARN diagnostic code E0003 never used diff --git a/src/test/compile-fail/issue-19096.rs b/src/test/compile-fail/issue-19096.rs index 7f42abb3acc..6b67814aab3 100644 --- a/src/test/compile-fail/issue-19096.rs +++ b/src/test/compile-fail/issue-19096.rs @@ -12,5 +12,5 @@ fn main() { let t = (42i, 42i); - t.0::<int>; //~ ERROR expected one of `;`, `}`, found `::` + t.0::<int>; //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `::` } diff --git a/src/test/compile-fail/issue-19244-1.rs b/src/test/compile-fail/issue-19244-1.rs index 4fcbb878890..7ca83f21305 100644 --- a/src/test/compile-fail/issue-19244-1.rs +++ b/src/test/compile-fail/issue-19244-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - const TUP: (uint,) = (42,); fn main() { diff --git a/src/test/compile-fail/issue-19498.rs b/src/test/compile-fail/issue-19498.rs new file mode 100644 index 00000000000..02b9c42b65b --- /dev/null +++ b/src/test/compile-fail/issue-19498.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use self::A; //~ ERROR import `A` conflicts with existing submodule +use self::B; //~ ERROR import `B` conflicts with existing submodule +mod A {} +pub mod B {} + +mod C { + use C::D; //~ ERROR import `D` conflicts with existing submodule + mod D {} +} + +fn main() {} diff --git a/src/test/compile-fail/issue-3036.rs b/src/test/compile-fail/issue-3036.rs index 5f56f6b8b6b..16834f49165 100644 --- a/src/test/compile-fail/issue-3036.rs +++ b/src/test/compile-fail/issue-3036.rs @@ -13,4 +13,4 @@ fn main() { let x = 3 -} //~ ERROR: expected `;`, found `}` +} //~ ERROR: expected one of `.`, `;`, or an operator, found `}` diff --git a/src/test/compile-fail/issue-5806.rs b/src/test/compile-fail/issue-5806.rs index 702f02c721d..597366a1b35 100644 --- a/src/test/compile-fail/issue-5806.rs +++ b/src/test/compile-fail/issue-5806.rs @@ -18,9 +18,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-freebsd FIXME #12460 - #[path = "../compile-fail"] -mod foo; //~ ERROR: illegal operation on a directory +mod foo; //~ ERROR: a directory fn main() {} diff --git a/src/test/compile-fail/lint-missing-doc.rs b/src/test/compile-fail/lint-missing-doc.rs index 365081aee1a..8d4ecde692d 100644 --- a/src/test/compile-fail/lint-missing-doc.rs +++ b/src/test/compile-fail/lint-missing-doc.rs @@ -17,6 +17,9 @@ //! Some garbage docs for the crate here #![doc="More garbage"] +type Typedef = String; +pub type PubTypedef = String; //~ ERROR: missing documentation + struct Foo { a: int, b: int, diff --git a/src/test/compile-fail/lint-unnecessary-parens.rs b/src/test/compile-fail/lint-unnecessary-parens.rs index 826a4ea5a80..b71effa6f86 100644 --- a/src/test/compile-fail/lint-unnecessary-parens.rs +++ b/src/test/compile-fail/lint-unnecessary-parens.rs @@ -9,7 +9,6 @@ // except according to those terms. #![deny(unused_parens)] -#![feature(if_let,while_let)] #[deriving(Eq, PartialEq)] struct X { y: bool } diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index d9bf722f73e..b1a6c82a734 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -18,8 +18,8 @@ use std::mem::*; // shouldn't get errors for not using // everything imported // Should get errors for both 'Some' and 'None' -use std::option::{Some, None}; //~ ERROR unused import - //~^ ERROR unused import +use std::option::Option::{Some, None}; //~ ERROR unused import + //~^ ERROR unused import use test::A; //~ ERROR unused import // Be sure that if we just bring some methods into scope that they're also diff --git a/src/test/compile-fail/match-vec-invalid.rs b/src/test/compile-fail/match-vec-invalid.rs index 51e83c14aa0..3e073d34f32 100644 --- a/src/test/compile-fail/match-vec-invalid.rs +++ b/src/test/compile-fail/match-vec-invalid.rs @@ -11,7 +11,7 @@ fn main() { let a = Vec::new(); match a { - [1, tail.., tail..] => {}, //~ ERROR: expected `,`, found `..` + [1, tail.., tail..] => {}, //~ ERROR: expected one of `!`, `,`, or `@`, found `..` _ => () } } diff --git a/src/test/compile-fail/move-fragments-1.rs b/src/test/compile-fail/move-fragments-1.rs index ccf12cf79e1..e45862a7fc6 100644 --- a/src/test/compile-fail/move-fragments-1.rs +++ b/src/test/compile-fail/move-fragments-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - // Test that we correctly compute the move fragments for a fn. // // Note that the code below is not actually incorrect; the diff --git a/src/test/compile-fail/move-out-of-tuple-field.rs b/src/test/compile-fail/move-out-of-tuple-field.rs index 7f55a78e8b7..7fcb54e0467 100644 --- a/src/test/compile-fail/move-out-of-tuple-field.rs +++ b/src/test/compile-fail/move-out-of-tuple-field.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - struct Foo(Box<int>); fn main() { diff --git a/src/test/compile-fail/multitrait.rs b/src/test/compile-fail/multitrait.rs index 795e3807d5e..7add747fbfa 100644 --- a/src/test/compile-fail/multitrait.rs +++ b/src/test/compile-fail/multitrait.rs @@ -12,7 +12,7 @@ struct S { y: int } -impl Cmp, ToString for S { //~ ERROR: expected `{`, found `,` +impl Cmp, ToString for S { //~ ERROR: expected one of `(`, `+`, `::`, or `{`, found `,` fn eq(&&other: S) { false } fn to_string(&self) -> String { "hi".to_string() } } diff --git a/src/test/compile-fail/mut-patterns.rs b/src/test/compile-fail/mut-patterns.rs index a33a603f7f5..a78e82bb73c 100644 --- a/src/test/compile-fail/mut-patterns.rs +++ b/src/test/compile-fail/mut-patterns.rs @@ -12,5 +12,5 @@ pub fn main() { struct Foo { x: int } - let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected `;`, found `{` + let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` } diff --git a/src/test/compile-fail/rustc-diagnostics-3.rs b/src/test/compile-fail/new-unicode-escapes-1.rs index d160664a48c..f2422830a21 100644 --- a/src/test/compile-fail/rustc-diagnostics-3.rs +++ b/src/test/compile-fail/new-unicode-escapes-1.rs @@ -8,13 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -__register_diagnostic!(E0001) -//~^ ERROR macro undefined: '__register_diagnostic!' - -fn main() { - __diagnostic_used!(E0001); - //~^ ERROR macro undefined: '__diagnostic_used!' +pub fn main() { + let s = "\u{2603"; //~ ERROR unterminated unicode escape (needed a `}`) } - -__build_diagnostic_array!(DIAGNOSTICS) -//~^ ERROR macro undefined: '__build_diagnostic_array!' diff --git a/src/test/compile-fail/new-unicode-escapes-2.rs b/src/test/compile-fail/new-unicode-escapes-2.rs new file mode 100644 index 00000000000..5da8674c37e --- /dev/null +++ b/src/test/compile-fail/new-unicode-escapes-2.rs @@ -0,0 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let s = "\u{260311111111}"; //~ ERROR overlong unicode escape (can have at most 6 hex digits) +} diff --git a/src/test/compile-fail/new-unicode-escapes-3.rs b/src/test/compile-fail/new-unicode-escapes-3.rs new file mode 100644 index 00000000000..7c64d02efd7 --- /dev/null +++ b/src/test/compile-fail/new-unicode-escapes-3.rs @@ -0,0 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let s = "\u{d805}"; //~ ERROR illegal unicode character escape +} diff --git a/src/test/compile-fail/new-unicode-escapes-4.rs b/src/test/compile-fail/new-unicode-escapes-4.rs new file mode 100644 index 00000000000..ffc2b11e0c1 --- /dev/null +++ b/src/test/compile-fail/new-unicode-escapes-4.rs @@ -0,0 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let s = "\u{lol}"; //~ ERROR illegal character in unicode escape +} diff --git a/src/test/compile-fail/omitted-arg-in-item-fn.rs b/src/test/compile-fail/omitted-arg-in-item-fn.rs index c5ff885997b..729b45df8b4 100644 --- a/src/test/compile-fail/omitted-arg-in-item-fn.rs +++ b/src/test/compile-fail/omitted-arg-in-item-fn.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(x) { //~ ERROR expected `:`, found `)` +fn foo(x) { //~ ERROR expected one of `!`, `:`, or `@`, found `)` } diff --git a/src/test/compile-fail/pat-range-bad-dots.rs b/src/test/compile-fail/pat-range-bad-dots.rs index 5605caaeeed..7fe073a4c3d 100644 --- a/src/test/compile-fail/pat-range-bad-dots.rs +++ b/src/test/compile-fail/pat-range-bad-dots.rs @@ -10,7 +10,7 @@ pub fn main() { match 22i { - 0 .. 3 => {} //~ ERROR expected `=>`, found `..` + 0 .. 3 => {} //~ ERROR expected one of `...`, `=>`, or `|`, found `..` _ => {} } } diff --git a/src/test/compile-fail/raw-str-unbalanced.rs b/src/test/compile-fail/raw-str-unbalanced.rs index 4f3fb7d5b8a..3403b28fdc9 100644 --- a/src/test/compile-fail/raw-str-unbalanced.rs +++ b/src/test/compile-fail/raw-str-unbalanced.rs @@ -10,5 +10,5 @@ static s: &'static str = r#" - "## //~ ERROR expected `;`, found `#` + "## //~ ERROR expected one of `.`, `;`, or an operator, found `#` ; diff --git a/src/test/compile-fail/removed-syntax-closure-lifetime.rs b/src/test/compile-fail/removed-syntax-closure-lifetime.rs index a726e30b1de..a07832d5bb7 100644 --- a/src/test/compile-fail/removed-syntax-closure-lifetime.rs +++ b/src/test/compile-fail/removed-syntax-closure-lifetime.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type closure = Box<lt/fn()>; //~ ERROR expected `,`, found `/` +type closure = Box<lt/fn()>; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `>`, found `/` diff --git a/src/test/compile-fail/removed-syntax-enum-newtype.rs b/src/test/compile-fail/removed-syntax-enum-newtype.rs index b9c9c5f0a53..ba1b5a616df 100644 --- a/src/test/compile-fail/removed-syntax-enum-newtype.rs +++ b/src/test/compile-fail/removed-syntax-enum-newtype.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum e = int; //~ ERROR expected `{`, found `=` +enum e = int; //~ ERROR expected one of `<` or `{`, found `=` diff --git a/src/test/compile-fail/removed-syntax-fixed-vec.rs b/src/test/compile-fail/removed-syntax-fixed-vec.rs index 917b4e03ad0..fe49d1f4a8d 100644 --- a/src/test/compile-fail/removed-syntax-fixed-vec.rs +++ b/src/test/compile-fail/removed-syntax-fixed-vec.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type v = [int * 3]; //~ ERROR expected `]`, found `*` +type v = [int * 3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `*` diff --git a/src/test/compile-fail/removed-syntax-larrow-init.rs b/src/test/compile-fail/removed-syntax-larrow-init.rs index b2e856750df..1474cc9dd39 100644 --- a/src/test/compile-fail/removed-syntax-larrow-init.rs +++ b/src/test/compile-fail/removed-syntax-larrow-init.rs @@ -11,5 +11,5 @@ fn removed_moves() { let mut x = 0; let y <- x; - //~^ ERROR expected `;`, found `<-` + //~^ ERROR expected one of `!`, `:`, `;`, `=`, or `@`, found `<-` } diff --git a/src/test/compile-fail/removed-syntax-larrow-move.rs b/src/test/compile-fail/removed-syntax-larrow-move.rs index e39fbe0f950..552c9f2efa2 100644 --- a/src/test/compile-fail/removed-syntax-larrow-move.rs +++ b/src/test/compile-fail/removed-syntax-larrow-move.rs @@ -12,5 +12,5 @@ fn removed_moves() { let mut x = 0; let y = 0; y <- x; - //~^ ERROR expected one of `;`, `}`, found `<-` + //~^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `<-` } diff --git a/src/test/compile-fail/removed-syntax-mut-vec-expr.rs b/src/test/compile-fail/removed-syntax-mut-vec-expr.rs index b20da6346f7..437f871f8ea 100644 --- a/src/test/compile-fail/removed-syntax-mut-vec-expr.rs +++ b/src/test/compile-fail/removed-syntax-mut-vec-expr.rs @@ -11,5 +11,5 @@ fn f() { let v = [mut 1, 2, 3, 4]; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected `]`, found `1` + //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `]`, `{`, or an operator, found `1` } diff --git a/src/test/compile-fail/removed-syntax-mut-vec-ty.rs b/src/test/compile-fail/removed-syntax-mut-vec-ty.rs index c5eec2ef6e1..af469fadf98 100644 --- a/src/test/compile-fail/removed-syntax-mut-vec-ty.rs +++ b/src/test/compile-fail/removed-syntax-mut-vec-ty.rs @@ -10,4 +10,4 @@ type v = [mut int]; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected `]`, found `int` + //~^^ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `int` diff --git a/src/test/compile-fail/removed-syntax-ptr-lifetime.rs b/src/test/compile-fail/removed-syntax-ptr-lifetime.rs index 0468ddd389a..1a1c4c9b40a 100644 --- a/src/test/compile-fail/removed-syntax-ptr-lifetime.rs +++ b/src/test/compile-fail/removed-syntax-ptr-lifetime.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type bptr = &lifetime/int; //~ ERROR expected `;`, found `/` +type bptr = &lifetime/int; //~ ERROR expected one of `(`, `+`, `::`, or `;`, found `/` diff --git a/src/test/compile-fail/removed-syntax-record.rs b/src/test/compile-fail/removed-syntax-record.rs index b31e2538ab9..ae5a68575f7 100644 --- a/src/test/compile-fail/removed-syntax-record.rs +++ b/src/test/compile-fail/removed-syntax-record.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type t = { f: () }; //~ ERROR expected type, found token OpenDelim(Brace) +type t = { f: () }; //~ ERROR expected type, found `{` diff --git a/src/test/compile-fail/removed-syntax-uniq-mut-expr.rs b/src/test/compile-fail/removed-syntax-uniq-mut-expr.rs index 124b3738fab..c5559c4ea96 100644 --- a/src/test/compile-fail/removed-syntax-uniq-mut-expr.rs +++ b/src/test/compile-fail/removed-syntax-uniq-mut-expr.rs @@ -11,5 +11,5 @@ fn f() { let a_box = box mut 42; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected `;`, found `42` + //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, or an operator, found `42` } diff --git a/src/test/compile-fail/removed-syntax-uniq-mut-ty.rs b/src/test/compile-fail/removed-syntax-uniq-mut-ty.rs index 579bfed1331..8c3db89bad2 100644 --- a/src/test/compile-fail/removed-syntax-uniq-mut-ty.rs +++ b/src/test/compile-fail/removed-syntax-uniq-mut-ty.rs @@ -10,4 +10,4 @@ type mut_box = Box<mut int>; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected `,`, found `int` + //~^^ ERROR expected one of `(`, `+`, `,`, `::`, or `>`, found `int` diff --git a/src/test/compile-fail/removed-syntax-with-1.rs b/src/test/compile-fail/removed-syntax-with-1.rs index fd8cdb7b10e..c7f31045cb6 100644 --- a/src/test/compile-fail/removed-syntax-with-1.rs +++ b/src/test/compile-fail/removed-syntax-with-1.rs @@ -16,5 +16,5 @@ fn removed_with() { let a = S { foo: (), bar: () }; let b = S { foo: () with a }; - //~^ ERROR expected one of `,`, `}`, found `with` + //~^ ERROR expected one of `,`, `.`, `}`, or an operator, found `with` } diff --git a/src/test/compile-fail/struct-literal-in-for.rs b/src/test/compile-fail/struct-literal-in-for.rs index ccd711d8375..a37197b889d 100644 --- a/src/test/compile-fail/struct-literal-in-for.rs +++ b/src/test/compile-fail/struct-literal-in-for.rs @@ -20,7 +20,7 @@ impl Foo { fn main() { for x in Foo { - x: 3 //~ ERROR expected one of `;`, `}` + x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:` }.hi() { println!("yo"); } diff --git a/src/test/compile-fail/struct-literal-in-if.rs b/src/test/compile-fail/struct-literal-in-if.rs index d63c216c3be..9759e4f7bda 100644 --- a/src/test/compile-fail/struct-literal-in-if.rs +++ b/src/test/compile-fail/struct-literal-in-if.rs @@ -20,7 +20,7 @@ impl Foo { fn main() { if Foo { - x: 3 //~ ERROR expected one of `;`, `}` + x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:` }.hi() { println!("yo"); } diff --git a/src/test/compile-fail/struct-literal-in-match-discriminant.rs b/src/test/compile-fail/struct-literal-in-match-discriminant.rs index c740ba02062..297d3f7347f 100644 --- a/src/test/compile-fail/struct-literal-in-match-discriminant.rs +++ b/src/test/compile-fail/struct-literal-in-match-discriminant.rs @@ -14,7 +14,7 @@ struct Foo { fn main() { match Foo { - x: 3 //~ ERROR expected `=>` + x: 3 //~ ERROR expected one of `!`, `=>`, `@`, or `|`, found `:` } { Foo { x: x diff --git a/src/test/compile-fail/struct-literal-in-while.rs b/src/test/compile-fail/struct-literal-in-while.rs index 7b2c11e2597..5b1679cf9a1 100644 --- a/src/test/compile-fail/struct-literal-in-while.rs +++ b/src/test/compile-fail/struct-literal-in-while.rs @@ -20,7 +20,7 @@ impl Foo { fn main() { while Foo { - x: 3 //~ ERROR expected one of `;`, `}` + x: 3 //~ ERROR expected one of `!`, `.`, `::`, `;`, `{`, `}`, or an operator, found `:` }.hi() { println!("yo"); } diff --git a/src/test/compile-fail/issue-17718-extern-const.rs b/src/test/compile-fail/trailing-comma-array-repeat.rs index 235d1222d81..dadd6571583 100644 --- a/src/test/compile-fail/issue-17718-extern-const.rs +++ b/src/test/compile-fail/trailing-comma-array-repeat.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern { - const FOO: uint; //~ ERROR: unexpected token: `const` +fn main() { + let [_, ..,] = [(), ()]; //~ ERROR unexpected token: `]` } - -fn main() {} diff --git a/src/test/compile-fail/tuple-index-not-tuple.rs b/src/test/compile-fail/tuple-index-not-tuple.rs index d4ef0e20b26..33aeebb3691 100644 --- a/src/test/compile-fail/tuple-index-not-tuple.rs +++ b/src/test/compile-fail/tuple-index-not-tuple.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - struct Point { x: int, y: int } struct Empty; diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index f9bf2746794..609e34f2274 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tuple_indexing)] - struct Point(int, int); fn main() { diff --git a/src/test/compile-fail/unresolved-extern-mod-suggestion.rs b/src/test/compile-fail/unresolved-extern-mod-suggestion.rs index 33d3deb8733..c2ee62c195c 100644 --- a/src/test/compile-fail/unresolved-extern-mod-suggestion.rs +++ b/src/test/compile-fail/unresolved-extern-mod-suggestion.rs @@ -9,6 +9,7 @@ // except according to those terms. extern crate core; -use core; //~ ERROR unresolved import (maybe you meant `core::*`?) +use core; +//~^ ERROR import `core` conflicts with imported crate in this module fn main() {} diff --git a/src/test/compile-fail/while-let.rs b/src/test/compile-fail/while-let.rs index 0dd442ec3f6..ccf3d2dd750 100644 --- a/src/test/compile-fail/while-let.rs +++ b/src/test/compile-fail/while-let.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(macro_rules,while_let)] +#![feature(macro_rules)] fn macros() { macro_rules! foo{ diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs index 9a42cd92fdc..76cf3c1149d 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs @@ -58,11 +58,17 @@ // gdb-command: print none // gdb-check:$12 = None +// gdb-command: print some_fat +// gdb-check:$13 = Some = {"abc"} + +// gdb-command: print none_fat +// gdb-check:$14 = None + // gdb-command: print nested_variant1 -// gdb-check:$13 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}} +// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}} // gdb-command: print nested_variant2 -// gdb-check:$14 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}} +// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}} use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3}; use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar}; @@ -129,6 +135,8 @@ fn main() { let some = Some(110u); let none: Option<int> = None; + let some_fat = Some("abc"); + let none_fat: Option<&'static str> = None; let nested_variant1 = NestedVariant1( NestedStruct { diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index 11c594bac59..333a430e351 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -61,6 +61,12 @@ // lldb-command:print void_droid // lldb-check:[...]$5 = Void +// lldb-command:print some_str +// lldb-check:[...]$6 = Some(&str { data_ptr: [...], length: 3 }) + +// lldb-command:print none_str +// lldb-check:[...]$7 = None + // If a struct has exactly two variants, one of them is empty, and the other one // contains a non-nullable pointer, then this value is used as the discriminator. @@ -96,6 +102,9 @@ struct NamedFieldsRepr<'a> { fn main() { + let some_str: Option<&'static str> = Some("abc"); + let none_str: Option<&'static str> = None; + let some: Option<&u32> = Some(unsafe { std::mem::transmute(0x12345678u) }); let none: Option<&u32> = None; diff --git a/src/test/run-fail/result-get-panic.rs b/src/test/run-fail/result-get-panic.rs index 6098b97c79a..df14efd6c3a 100644 --- a/src/test/run-fail/result-get-panic.rs +++ b/src/test/run-fail/result-get-panic.rs @@ -10,8 +10,8 @@ // error-pattern:called `Result::unwrap()` on an `Err` value -use std::result; +use std::result::Result::Err; fn main() { - println!("{}", result::Err::<int,String>("kitty".to_string()).unwrap()); + println!("{}", Err::<int,String>("kitty".to_string()).unwrap()); } diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 715fae314b6..8a0c14d2d7e 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -9,12 +9,12 @@ // except according to those terms. extern crate rustc; -extern crate rustc_trans; +extern crate rustc_driver; extern crate syntax; use rustc::session::{build_session, Session}; -use rustc::session::config::{basic_options, build_configuration, OutputTypeExe}; -use rustc_trans::driver::driver::{Input, StrInput, compile_input}; +use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe}; +use rustc_driver::driver::{compile_input}; use syntax::diagnostics::registry::Registry; fn main() { @@ -55,7 +55,7 @@ fn compile(code: String, output: Path, sysroot: Path) { compile_input(sess, cfg, - &StrInput(code), + &Input::Str(code), &None, &Some(output), None); diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs index fd59b804da3..b68d8058381 100644 --- a/src/test/run-pass/deriving-cmp-shortcircuit.rs +++ b/src/test/run-pass/deriving-cmp-shortcircuit.rs @@ -39,5 +39,5 @@ pub fn main() { assert!(a != b); assert!(a < b); - assert_eq!(a.cmp(&b), ::std::cmp::Less); + assert_eq!(a.cmp(&b), ::std::cmp::Ordering::Less); } diff --git a/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs index 1187a9a8bc4..d63c264479a 100644 --- a/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs +++ b/src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs @@ -10,7 +10,7 @@ // ignore-test FIXME #11820: & is unreliable in deriving -use std::cmp::{Less,Equal,Greater}; +use std::cmp::Ordering::{Less,Equal,Greater}; #[deriving(Eq,Ord)] struct A<'a> { diff --git a/src/test/run-pass/enum-nullable-const-null-with-fields.rs b/src/test/run-pass/enum-nullable-const-null-with-fields.rs index a48f3bcd59c..4b839d740fc 100644 --- a/src/test/run-pass/enum-nullable-const-null-with-fields.rs +++ b/src/test/run-pass/enum-nullable-const-null-with-fields.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::result::{Result,Ok}; +use std::result::Result; +use std::result::Result::Ok; static C: Result<(), Box<int>> = Ok(()); diff --git a/src/test/run-pass/issue-13304.rs b/src/test/run-pass/issue-13304.rs index 047ff74035b..11003c6fc52 100644 --- a/src/test/run-pass/issue-13304.rs +++ b/src/test/run-pass/issue-13304.rs @@ -37,7 +37,7 @@ fn parent() { } fn child() { - for line in io::stdin().lines() { + for line in io::stdin().lock().lines() { println!("{}", line.unwrap()); } } diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs index 2339e3f6302..f5fdf8704ed 100644 --- a/src/test/run-pass/issue-14456.rs +++ b/src/test/run-pass/issue-14456.rs @@ -27,7 +27,7 @@ fn main() { fn child() { io::stdout().write_line("foo").unwrap(); io::stderr().write_line("bar").unwrap(); - assert_eq!(io::stdin().read_line().err().unwrap().kind, io::EndOfFile); + assert_eq!(io::stdin().lock().read_line().err().unwrap().kind, io::EndOfFile); } fn test() { diff --git a/src/test/run-pass/issue-16671.rs b/src/test/run-pass/issue-16671.rs index a0d384418f9..20bf1b260de 100644 --- a/src/test/run-pass/issue-16671.rs +++ b/src/test/run-pass/issue-16671.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-android seems to block forever + #![forbid(warnings)] // Pretty printing tests complain about `use std::predule::*` @@ -19,6 +21,6 @@ pub fn main() { let mut stdin = std::io::stdin(); spawn(proc() { - let _ = stdin.lines(); + let _ = stdin.read_to_end(); }); } diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass/issue-2804.rs index ec19b95ab1a..6f1f2cea8ec 100644 --- a/src/test/run-pass/issue-2804.rs +++ b/src/test/run-pass/issue-2804.rs @@ -24,14 +24,14 @@ enum object { fn lookup(table: json::Object, key: String, default: String) -> String { match table.find(&key.to_string()) { - option::Some(&Json::String(ref s)) => { + option::Option::Some(&Json::String(ref s)) => { s.to_string() } - option::Some(value) => { + option::Option::Some(value) => { println!("{} was expected to be a string but is a {}", key, value); default } - option::None => { + option::Option::None => { default } } diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index 2dac64b2ec8..81efacb9bcb 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -20,7 +20,7 @@ type rsrc_loader = proc(path: &Path):'static -> result::Result<String, String>; fn tester() { let loader: rsrc_loader = proc(_path) { - result::Ok("more blah".to_string()) + result::Result::Ok("more blah".to_string()) }; let path = path::Path::new("blah"); diff --git a/src/test/run-pass/new-unicode-escapes.rs b/src/test/run-pass/new-unicode-escapes.rs new file mode 100644 index 00000000000..2888389bcce --- /dev/null +++ b/src/test/run-pass/new-unicode-escapes.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let s = "\u{2603}"; + assert_eq!(s, "☃"); + + let s = "\u{2a10}\u{2A01}\u{2Aa0}"; + assert_eq!(s, "⨐⨁⪠"); + + let s = "\\{20}"; + let mut correct_s = String::from_str("\\"); + correct_s.push_str("{20}"); + assert_eq!(s, correct_s.as_slice()); +} diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index 520d067bca3..da1ad094df6 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -41,9 +41,9 @@ macro_rules! check_option { check_option!($e: $T, |ptr| assert!(*ptr == $e)); }}; ($e:expr: $T:ty, |$v:ident| $chk:expr) => {{ - assert!(option::None::<$T>.is_none()); + assert!(option::Option::None::<$T>.is_none()); let e = $e; - let s_ = option::Some::<$T>(e); + let s_ = option::Option::Some::<$T>(e); let $v = s_.as_ref().unwrap(); $chk }} diff --git a/src/test/run-pass/send_str_hashmap.rs b/src/test/run-pass/send_str_hashmap.rs index ef485723c7e..1b0f2ec0a32 100644 --- a/src/test/run-pass/send_str_hashmap.rs +++ b/src/test/run-pass/send_str_hashmap.rs @@ -11,7 +11,7 @@ extern crate collections; use std::collections::HashMap; -use std::option::Some; +use std::option::Option::Some; use std::str::SendStr; pub fn main() { diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index f72ca109b6e..9334b673b51 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -11,7 +11,7 @@ extern crate collections; use self::collections::TreeMap; -use std::option::Some; +use std::option::Option::Some; use std::str::SendStr; use std::string::ToString; diff --git a/src/test/run-pass/trailing-comma.rs b/src/test/run-pass/trailing-comma.rs index 5e93f8eedb7..00e05064080 100644 --- a/src/test/run-pass/trailing-comma.rs +++ b/src/test/run-pass/trailing-comma.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(advanced_slice_patterns,)] + fn f<T,>(_: T,) {} struct Foo<T,>; @@ -24,9 +26,13 @@ enum Baz { Qux(int,), } +#[allow(unused,)] pub fn main() { f::<int,>(0i,); let (_, _,) = (1i, 1i,); + let [_, _,] = [1i, 1,]; + let [_, _, .., _,] = [1i, 1, 1, 1,]; + let [_, _, _.., _,] = [1i, 1, 1, 1,]; let x: Foo<int,> = Foo::<int,>; diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs new file mode 100644 index 00000000000..f482b2e1e70 --- /dev/null +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -0,0 +1,80 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-test + +extern crate libc; + +use std::io::process::Command; +use std::iter::IteratorExt; + +use libc::funcs::posix88::unistd; + + +// "ps -A -o pid,sid,command" with GNU ps should output something like this: +// PID SID COMMAND +// 1 1 /sbin/init +// 2 0 [kthreadd] +// 3 0 [ksoftirqd/0] +// ... +// 12562 9237 ./spawn-failure +// 12563 9237 [spawn-failure] <defunct> +// 12564 9237 [spawn-failure] <defunct> +// ... +// 12592 9237 [spawn-failure] <defunct> +// 12593 9237 ps -A -o pid,sid,command +// 12884 12884 /bin/zsh +// 12922 12922 /bin/zsh +// ... + +#[cfg(unix)] +fn find_zombies() { + // http://man.freebsd.org/ps(1) + // http://man7.org/linux/man-pages/man1/ps.1.html + #[cfg(not(target_os = "macos"))] + const FIELDS: &'static str = "pid,sid,command"; + + // https://developer.apple.com/library/mac/documentation/Darwin/ + // Reference/ManPages/man1/ps.1.html + #[cfg(target_os = "macos")] + const FIELDS: &'static str = "pid,sess,command"; + + let my_sid = unsafe { unistd::getsid(0) }; + + let ps_cmd_output = Command::new("ps").args(&["-A", "-o", FIELDS]).output().unwrap(); + let ps_output = String::from_utf8_lossy(ps_cmd_output.output.as_slice()); + + let found = ps_output.split('\n').enumerate().any(|(line_no, line)| + 0 < line_no && 0 < line.len() && + my_sid == from_str(line.split(' ').filter(|w| 0 < w.len()).nth(1) + .expect("1st column should be Session ID") + ).expect("Session ID string into integer") && + line.contains("defunct") && { + println!("Zombie child {}", line); + true + } + ); + + assert!( ! found, "Found at least one zombie child"); +} + +#[cfg(windows)] +fn find_zombies() { } + +fn main() { + let too_long = format!("/NoSuchCommand{:0300}", 0u8); + + for _ in range(0u32, 100) { + let invalid = Command::new(too_long.as_slice()).spawn(); + assert!(invalid.is_err()); + } + + find_zombies(); +} |
