Used `HashMap` and `HashSet` as the base of most examples. Could change it up with different containers, but I don't think it's a big deal.
guide-tasks guide-container guide-pointers guide-testing \
guide-runtime complement-bugreport \
complement-lang-faq complement-design-faq complement-project-faq rust \
- rustdoc guide-unsafe
+ rustdoc guide-unsafe guide-strings
PDF_DOCS := tutorial rust
% The Strings Guide
-# Strings
-
Strings are an important concept to master in any programming language. If you
come from a managed language background, you may be surprised at the complexity
of string handling in a systems programming language. Efficient access and
Rust has two main types of strings: `&str` and `String`.
-## &str
+# &str
The first kind is a `&str`. This is pronounced a 'string slice.' String literals
are of the type `&str`:
means that they're a 'view' into an already-allocated string, such as a
`&'static str` or a `String`.
-## String
+# String
A `String` is a heap-allocated string. This string is growable, and is also
guaranteed to be UTF-8.
let stack_str: &str = str::from_utf8(x).unwrap();
```
-## Best Practices
+# Best Practices
-### `String` vs. `&str`
+## `String` vs. `&str`
In general, you should prefer `String` when you need ownership, and `&str` when
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
either kind of string into `foo` by using `.as_slice()` on any `String` you
need to pass in, so the `&str` version is more flexible.
-### Comparisons
+## Comparisons
To compare a String to a constant string, prefer `as_slice()`...
Converting a `String` to a `&str` is cheap, but converting the `&str` to a
`String` involves an allocation.
-## Other Documentation
+# Other Documentation
* [the `&str` API documentation](/std/str/index.html)
* [the `String` API documentation](std/string/index.html)
When you just use the double curly braces, Rust will attempt to display the
value in a meaningful way by checking out its type. If you want to specify the
format in a more detailed manner, there are a [wide number of options
-available](/std/fmt/index.html). Fow now, we'll just stick to the default:
+available](/std/fmt/index.html). For now, we'll just stick to the default:
integers aren't very complicated to print.
So, we've cleared up all of the confusion around bindings, with one exception:
# Guides
+* [Strings](guide-strings.html)
* [Pointers](guide-pointers.html)
* [References and Lifetimes](guide-lifetimes.html)
* [Containers and Iterators](guide-container.html)
operator to convert a variant to its discriminator value as an `int`:
~~~~
-# #[deriving(Show)] enum Direction { North }
-println!( "{} => {}", North, North as int );
+# enum Direction { North, East, South, West }
+println!( "North => {}", North as int );
~~~~
It is possible to set the discriminator values to chosen constant values:
This declaration defines a type `Shape` that can refer to such shapes, and two
functions, `Circle` and `Rectangle`, which can be used to construct values of
-the type. To create a new Circle, write `Circle(Point { x: 0.0, y: 0.0 },
-10.0)`.
+the type.
+
+To create a new `Circle`, write:
+
+~~~~
+# struct Point { x: f64, y: f64 }
+# enum Shape { Circle(Point, f64), Rectangle(Point, Point) }
+let circle = Circle(Point { x: 0.0, y: 0.0 }, 10.0);
+~~~~
All of these variant constructors may be used as patterns. The only way to
access the contents of an enum instance is the destructuring of a match. For
~~~~
use std::f64;
+
# struct Point {x: f64, y: f64}
# enum Shape { Circle(Point, f64), Rectangle(Point, Point) }
fn area(sh: Shape) -> f64 {
Rectangle(Point { x, y }, Point { x: x2, y: y2 }) => (x2 - x) * (y2 - y)
}
}
+
+let rect = Rectangle(Point { x: 0.0, y: 0.0 }, Point { x: 2.0, y: 2.0 });
+println!("area: {}", area(rect));
~~~~
Use a lone `_` to ignore an individual field. Ignore all fields of a variant
Enum variants may also be structs. For example:
~~~~
-# #![feature(struct_variant)]
+#![feature(struct_variant)]
use std::f64;
+
# struct Point { x: f64, y: f64 }
# fn square(x: f64) -> f64 { x * x }
enum Shape {
}
}
}
-# fn main() {}
+
+fn main() {
+ let rect = Rectangle {
+ top_left: Point { x: 0.0, y: 0.0 },
+ bottom_right: Point { x: 2.0, y: -2.0 }
+ };
+ println!("area: {}", area(rect));
+}
~~~~
> *Note:* This feature of the compiler is currently gated behind the
destructors. Example of types which are not `Send` are [`Gc<T>`][gc] and
[`Rc<T>`][rc], the shared-ownership types.
+> *Note:* See a [later chapter](#ownership-escape-hatches) for a discussion about
+> [`Gc<T>`][gc] and [`Rc<T>`][rc], and the [chapter about traits](#traits) for
+> a discussion about `Send`.
+
[gc]: http://doc.rust-lang.org/std/gc/struct.Gc.html
[rc]: http://doc.rust-lang.org/std/rc/struct.Rc.html
let view: &str = string.slice(0, 3);
~~~
+Square brackets denote indexing into a slice or fixed-size vector:
+
+~~~~
+let crayons: [&str, ..3] = ["BananaMania", "Beaver", "Bittersweet"];
+println!("Crayon 2 is '{}'", crayons[2]);
+~~~~
+
Mutable slices also exist, just as there are mutable references. However, there
are no mutable string slices. Strings are a multi-byte encoding (UTF-8) of
Unicode code points, so they cannot be freely mutated without the ability to
let ys: &mut [int] = &mut [1i, 2i, 3i];
~~~
-Square brackets denote indexing into a slice or fixed-size vector:
-
-~~~~
-# enum Crayon { Almond, AntiqueBrass, Apricot,
-# Aquamarine, Asparagus, AtomicTangerine,
-# BananaMania, Beaver, Bittersweet };
-# fn draw_scene(c: Crayon) { }
-let crayons: [Crayon, ..3] = [BananaMania, Beaver, Bittersweet];
-match crayons[0] {
- Bittersweet => draw_scene(crayons[0]),
- _ => ()
-}
-~~~~
-
A slice or fixed-size vector can be destructured using pattern matching:
~~~~
The `Rc` and `Gc` types are not sendable, so they cannot be used to share memory between tasks. Safe
immutable and mutable shared memory is provided by the `sync::arc` module.
+> *Note:* See a [later chapter](#traits) for a discussion about `Send` and sendable types.
+
# Closures
Named functions, like those we've seen so far, may not refer to local
## Deriving implementations for traits
-A small number of traits in `std` and `extra` can have implementations
+A small number of traits in can have implementations
that can be automatically derived. These instances are specified by
placing the `deriving` attribute on a data type declaration. For
example, the following will mean that `Circle` has an implementation
~~~
extern crate rand;
+use std::rand::{task_rng, Rng};
#[deriving(PartialEq)]
struct Circle { radius: f64 }
fn main() {
// Use the Show trait to print "A, B, C."
println!("{}, {}, {}", A, B, C);
+
+ let mut rng = task_rng();
+
+ // Use the Rand trait to generate a random variants.
+ for _ in range(0i, 10) {
+ println!("{}", rng.gen::<ABC>());
+ }
}
~~~
For that, Rust offers you the `extern crate` declaration:
~~~
+// `num` ships with Rust.
extern crate num;
-// `num` ships with Rust (much like `extra`; more details further down).
fn main() {
// The rational number '1/2':
*/
+#![stable]
+
use core::mem::transmute;
use core::cell::Cell;
use core::clone::Clone;
/// Immutable reference counted pointer type
#[unsafe_no_drop_flag]
+#[stable]
pub struct Rc<T> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_noshare: marker::NoShare
}
+#[stable]
impl<T> Rc<T> {
/// Construct a new reference-counted box
pub fn new(value: T) -> Rc<T> {
impl<T> Rc<T> {
/// Downgrade the reference-counted pointer to a weak reference
+ #[experimental = "Weak pointers may not belong in this module."]
pub fn downgrade(&self) -> Weak<T> {
self.inc_weak();
Weak {
}
}
+#[experimental = "Deref is experimental."]
impl<T> Deref<T> for Rc<T> {
/// Borrow the value contained in the reference-counted box
#[inline(always)]
}
#[unsafe_destructor]
+#[experimental = "Drop is experimental."]
impl<T> Drop for Rc<T> {
fn drop(&mut self) {
unsafe {
}
}
-#[unstable]
+#[unstable = "Clone is unstable."]
impl<T> Clone for Rc<T> {
#[inline]
fn clone(&self) -> Rc<T> {
}
}
+#[stable]
impl<T: Default> Default for Rc<T> {
#[inline]
fn default() -> Rc<T> {
}
}
+#[unstable = "PartialEq is unstable."]
impl<T: PartialEq> PartialEq for Rc<T> {
#[inline(always)]
fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
}
+#[unstable = "Eq is unstable."]
impl<T: Eq> Eq for Rc<T> {}
+#[unstable = "PartialOrd is unstable."]
impl<T: PartialOrd> PartialOrd for Rc<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
}
+#[unstable = "Ord is unstable."]
impl<T: Ord> Ord for Rc<T> {
#[inline]
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
}
+#[experimental = "Show is experimental."]
impl<T: fmt::Show> fmt::Show for Rc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
/// Weak reference to a reference-counted box
#[unsafe_no_drop_flag]
+#[experimental = "Weak pointers may not belong in this module."]
pub struct Weak<T> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_noshare: marker::NoShare
}
+#[experimental = "Weak pointers may not belong in this module."]
impl<T> Weak<T> {
/// Upgrade a weak reference to a strong reference
pub fn upgrade(&self) -> Option<Rc<T>> {
}
#[unsafe_destructor]
+#[experimental = "Weak pointers may not belong in this module."]
impl<T> Drop for Weak<T> {
fn drop(&mut self) {
unsafe {
}
#[unstable]
+#[experimental = "Weak pointers may not belong in this module."]
impl<T> Clone for Weak<T> {
#[inline]
fn clone(&self) -> Weak<T> {
}
/// Convert the `Rawlink` into an Option value
- fn resolve_immut(&self) -> Option<&T> {
- unsafe { self.p.to_option() }
+ fn resolve_immut<'a>(&self) -> Option<&'a T> {
+ unsafe {
+ mem::transmute(self.p.to_option())
+ }
}
/// Convert the `Rawlink` into an Option value
- fn resolve(&mut self) -> Option<&mut T> {
+ fn resolve<'a>(&mut self) -> Option<&'a mut T> {
if self.p.is_null() {
None
} else {
/// Move the last element to the front of the list.
///
/// If the list is empty, do nothing.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut dl = DList::new();
+ /// dl.push_back(1i);
+ /// dl.push_back(2);
+ /// dl.push_back(3);
+ ///
+ /// dl.rotate_forward();
+ ///
+ /// for e in dl.iter() {
+ /// println!("{}", e); // prints 3, then 1, then 2
+ /// }
+ /// ```
#[inline]
pub fn rotate_forward(&mut self) {
self.pop_back_node().map(|tail| {
/// Move the first element to the back of the list.
///
/// If the list is empty, do nothing.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut dl = DList::new();
+ /// dl.push_back(1i);
+ /// dl.push_back(2);
+ /// dl.push_back(3);
+ ///
+ /// dl.rotate_backward();
+ ///
+ /// for e in dl.iter() {
+ /// println!("{}", e); // prints 2, then 3, then 1
+ /// }
+ /// ```
#[inline]
pub fn rotate_backward(&mut self) {
self.pop_front_node().map(|head| {
/// Add all elements from `other` to the end of the list
///
/// O(1)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a = DList::new();
+ /// let mut b = DList::new();
+ /// a.push_back(1i);
+ /// a.push_back(2);
+ /// b.push_back(3i);
+ /// b.push_back(4);
+ ///
+ /// a.append(b);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 1, then 2, then 3, then 4
+ /// }
+ /// ```
pub fn append(&mut self, mut other: DList<T>) {
match self.list_tail.resolve() {
None => *self = other,
/// Add all elements from `other` to the beginning of the list
///
/// O(1)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a = DList::new();
+ /// let mut b = DList::new();
+ /// a.push_back(1i);
+ /// a.push_back(2);
+ /// b.push_back(3i);
+ /// b.push_back(4);
+ ///
+ /// a.prepend(b);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 3, then 4, then 1, then 2
+ /// }
+ /// ```
#[inline]
pub fn prepend(&mut self, mut other: DList<T>) {
mem::swap(self, &mut other);
/// or at the end.
///
/// O(N)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a: DList<int> = DList::new();
+ /// a.push_back(2i);
+ /// a.push_back(4);
+ /// a.push_back(7);
+ /// a.push_back(8);
+ ///
+ /// // insert 11 before the first odd number in the list
+ /// a.insert_when(11, |&e, _| e % 2 == 1);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 2, then 4, then 11, then 7, then 8
+ /// }
+ /// ```
pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) {
{
let mut it = self.mut_iter();
#[cfg(test)]
mod tests {
use std::iter::AdditiveIterator;
+ use std::iter::range;
use std::default::Default;
use std::char::Char;
use std::clone::Clone;
assert_eq!(pos, v.len());
}
+ #[test]
+ fn test_chars_decoding() {
+ let mut bytes = [0u8, ..4];
+ for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+ let len = c.encode_utf8(bytes);
+ let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+ if Some(c) != s.chars().next() {
+ fail!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+ }
+
+ #[test]
+ fn test_chars_rev_decoding() {
+ let mut bytes = [0u8, ..4];
+ for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+ let len = c.encode_utf8(bytes);
+ let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+ if Some(c) != s.chars().rev().next() {
+ fail!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+ }
+
#[test]
fn test_iterator_clone() {
let s = "ศไทย中华Việt Nam";
#[cfg(test)]
mod bench {
use test::Bencher;
+ use test::black_box;
use super::*;
+ use std::option::{None, Some};
use std::iter::{Iterator, DoubleEndedIterator};
use std::collections::Collection;
#[bench]
fn char_iterator(b: &mut Bencher) {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().count(), len));
+ b.iter(|| s.chars().count());
+ }
+
+ #[bench]
+ fn char_iterator_for(b: &mut Bencher) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+ b.iter(|| {
+ for ch in s.chars() { black_box(ch) }
+ });
}
#[bench]
Mary had a little lamb, Little lamb
Mary had a little lamb, Little lamb
Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().count(), len));
+ b.iter(|| s.chars().count());
}
#[bench]
fn char_iterator_rev(b: &mut Bencher) {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().rev().count(), len));
+ b.iter(|| s.chars().rev().count());
+ }
+
+ #[bench]
+ fn char_iterator_rev_for(b: &mut Bencher) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+ b.iter(|| {
+ for ch in s.chars().rev() { black_box(ch) }
+ });
}
#[bench]
//! assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
//! ```
+#![stable]
+
use option::{Option, Some};
/// Trait for values that can be compared for equality and inequality.
/// Eventually, this will be implemented by default for types that implement
/// `Eq`.
#[lang="eq"]
+#[unstable = "Definition may change slightly after trait reform"]
pub trait PartialEq {
/// This method tests for `self` and `other` values to be equal, and is used by `==`.
fn eq(&self, other: &Self) -> bool;
/// - reflexive: `a == a`;
/// - symmetric: `a == b` implies `b == a`; and
/// - transitive: `a == b` and `b == c` implies `a == c`.
+#[unstable = "Definition may change slightly after trait reform"]
pub trait Eq: PartialEq {
// FIXME #13101: this method is used solely by #[deriving] to
// assert that every component of a type implements #[deriving]
/// An ordering is, e.g, a result of a comparison between two values.
#[deriving(Clone, PartialEq, Show)]
+#[stable]
pub enum Ordering {
/// An ordering where a compared value is less [than another].
Less = -1i,
/// true; and
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for
/// both `==` and `>`.
+#[unstable = "Definition may change slightly after trait reform"]
pub trait Ord: Eq + PartialOrd {
/// This method returns an ordering between `self` and `other` values.
///
fn cmp(&self, other: &Self) -> Ordering;
}
+#[unstable = "Trait is unstable."]
impl Eq for Ordering {}
+#[unstable = "Trait is unstable."]
impl Ord for Ordering {
#[inline]
fn cmp(&self, other: &Ordering) -> Ordering {
}
}
+#[unstable = "Trait is unstable."]
impl PartialOrd for Ordering {
#[inline]
fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
/// If the first ordering is different, the first ordering is all that must be returned.
/// If the first ordering is equal, then second ordering is returned.
#[inline]
+#[deprecated = "Just call .cmp() on an Ordering"]
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
match o1 {
Equal => o2,
/// `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE 754-2008 section
/// 5.11).
#[lang="ord"]
+#[unstable = "Definition may change slightly after trait reform"]
pub trait PartialOrd: PartialEq {
/// This method returns an ordering between `self` and `other` values
/// if one exists.
/// of different types. The most common use case for this relation is
/// container types; e.g. it is often desirable to be able to use `&str`
/// values to look up entries in a container with `String` keys.
+#[experimental = "Better solutions may be discovered."]
pub trait Equiv<T> {
/// Implement this function to decide equivalent values.
fn equiv(&self, other: &T) -> bool;
/// Compare and return the minimum of two values.
#[inline]
+#[stable]
pub fn min<T: Ord>(v1: T, v2: T) -> T {
if v1 < v2 { v1 } else { v2 }
}
/// Compare and return the maximum of two values.
#[inline]
+#[stable]
pub fn max<T: Ord>(v1: T, v2: T) -> T {
if v1 > v2 { v1 } else { v2 }
}
macro_rules! eq_impl(
($($t:ty)*) => ($(
+ #[unstable = "Trait is unstable."]
impl PartialEq for $t {
#[inline]
fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
)*)
)
+ #[unstable = "Trait is unstable."]
impl PartialEq for () {
#[inline]
fn eq(&self, _other: &()) -> bool { true }
macro_rules! totaleq_impl(
($($t:ty)*) => ($(
+ #[unstable = "Trait is unstable."]
impl Eq for $t {}
)*)
)
macro_rules! ord_impl(
($($t:ty)*) => ($(
+ #[unstable = "Trait is unstable."]
impl PartialOrd for $t {
#[inline]
fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
)*)
)
+ #[unstable = "Trait is unstable."]
impl PartialOrd for () {
#[inline]
fn partial_cmp(&self, _: &()) -> Option<Ordering> {
}
}
+ #[unstable = "Trait is unstable."]
impl PartialOrd for bool {
#[inline]
fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
macro_rules! totalord_impl(
($($t:ty)*) => ($(
+ #[unstable = "Trait is unstable."]
impl Ord for $t {
#[inline]
fn cmp(&self, other: &$t) -> Ordering {
)*)
)
+ #[unstable = "Trait is unstable."]
impl Ord for () {
#[inline]
fn cmp(&self, _other: &()) -> Ordering { Equal }
}
+ #[unstable = "Trait is unstable."]
impl Ord for bool {
#[inline]
fn cmp(&self, other: &bool) -> Ordering {
totalord_impl!(char uint u8 u16 u32 u64 int i8 i16 i32 i64)
// & pointers
+ #[unstable = "Trait is unstable."]
impl<'a, T: PartialEq> PartialEq for &'a T {
#[inline]
fn eq(&self, other: & &'a T) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: & &'a T) -> bool { *(*self) != *(*other) }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: PartialOrd> PartialOrd for &'a T {
#[inline]
fn partial_cmp(&self, other: &&'a T) -> Option<Ordering> {
#[inline]
fn gt(&self, other: & &'a T) -> bool { *(*self) > *(*other) }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: Ord> Ord for &'a T {
#[inline]
fn cmp(&self, other: & &'a T) -> Ordering { (**self).cmp(*other) }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: Eq> Eq for &'a T {}
// &mut pointers
+ #[unstable = "Trait is unstable."]
impl<'a, T: PartialEq> PartialEq for &'a mut T {
#[inline]
fn eq(&self, other: &&'a mut T) -> bool { **self == *(*other) }
#[inline]
fn ne(&self, other: &&'a mut T) -> bool { **self != *(*other) }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: PartialOrd> PartialOrd for &'a mut T {
#[inline]
fn partial_cmp(&self, other: &&'a mut T) -> Option<Ordering> {
#[inline]
fn gt(&self, other: &&'a mut T) -> bool { **self > **other }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: Ord> Ord for &'a mut T {
#[inline]
fn cmp(&self, other: &&'a mut T) -> Ordering { (**self).cmp(*other) }
}
+ #[unstable = "Trait is unstable."]
impl<'a, T: Eq> Eq for &'a mut T {}
}
//! The `Default` trait for types which may have meaningful default values
+#![stable]
+
/// A trait that types which have a useful default value should implement.
pub trait Default {
/// Return the "default value" for a type.
Section: Iterators
*/
-/// External iterator for a string's characters.
-/// Use with the `std::iter` module.
+/// Iterator for the char (representing *Unicode Scalar Values*) of a string
+///
+/// Created with the method `.chars()`.
#[deriving(Clone)]
pub struct Chars<'a> {
- /// The slice remaining to be iterated
- string: &'a str,
+ iter: slice::Items<'a, u8>
+}
+
+// Return the initial codepoint accumulator for the first byte.
+// The first byte is special, only want bottom 5 bits for width 2, 4 bits
+// for width 3, and 3 bits for width 4
+macro_rules! utf8_first_byte(
+ ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
+)
+
+// return the value of $ch updated with continuation byte $byte
+macro_rules! utf8_acc_cont_byte(
+ ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & CONT_MASK) as u32)
+)
+
+macro_rules! utf8_is_cont_byte(
+ ($byte:expr) => (($byte & !CONT_MASK) == TAG_CONT_U8)
+)
+
+#[inline]
+fn unwrap_or_0(opt: Option<&u8>) -> u8 {
+ match opt {
+ Some(&byte) => byte,
+ None => 0,
+ }
}
impl<'a> Iterator<char> for Chars<'a> {
#[inline]
fn next(&mut self) -> Option<char> {
- // Decode the next codepoint, then update
- // the slice to be just the remaining part
- if self.string.len() != 0 {
- let CharRange {ch, next} = self.string.char_range_at(0);
- unsafe {
- self.string = raw::slice_unchecked(self.string, next, self.string.len());
+ // Decode UTF-8, using the valid UTF-8 invariant
+ let x = match self.iter.next() {
+ None => return None,
+ Some(&next_byte) if next_byte < 128 => return Some(next_byte as char),
+ Some(&next_byte) => next_byte,
+ };
+
+ // Multibyte case follows
+ // Decode from a byte combination out of: [[[x y] z] w]
+ // NOTE: Performance is sensitive to the exact formulation here
+ let init = utf8_first_byte!(x, 2);
+ let y = unwrap_or_0(self.iter.next());
+ let mut ch = utf8_acc_cont_byte!(init, y);
+ if x >= 0xE0 {
+ // [[x y z] w] case
+ // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
+ let z = unwrap_or_0(self.iter.next());
+ let y_z = utf8_acc_cont_byte!((y & CONT_MASK) as u32, z);
+ ch = init << 12 | y_z;
+ if x >= 0xF0 {
+ // [x y z w] case
+ // use only the lower 3 bits of `init`
+ let w = unwrap_or_0(self.iter.next());
+ ch = (init & 7) << 18 | utf8_acc_cont_byte!(y_z, w);
}
- Some(ch)
- } else {
- None
+ }
+
+ // str invariant says `ch` is a valid Unicode Scalar Value
+ unsafe {
+ Some(mem::transmute(ch))
}
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
- (self.string.len().saturating_add(3)/4, Some(self.string.len()))
+ let (len, _) = self.iter.size_hint();
+ (len.saturating_add(3) / 4, Some(len))
}
}
impl<'a> DoubleEndedIterator<char> for Chars<'a> {
#[inline]
fn next_back(&mut self) -> Option<char> {
- if self.string.len() != 0 {
- let CharRange {ch, next} = self.string.char_range_at_reverse(self.string.len());
- unsafe {
- self.string = raw::slice_unchecked(self.string, 0, next);
+ let w = match self.iter.next_back() {
+ None => return None,
+ Some(&back_byte) if back_byte < 128 => return Some(back_byte as char),
+ Some(&back_byte) => back_byte,
+ };
+
+ // Multibyte case follows
+ // Decode from a byte combination out of: [x [y [z w]]]
+ let mut ch;
+ let z = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(z, 2);
+ if utf8_is_cont_byte!(z) {
+ let y = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(y, 3);
+ if utf8_is_cont_byte!(y) {
+ let x = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(x, 4);
+ ch = utf8_acc_cont_byte!(ch, y);
}
- Some(ch)
- } else {
- None
+ ch = utf8_acc_cont_byte!(ch, z);
+ }
+ ch = utf8_acc_cont_byte!(ch, w);
+
+ // str invariant says `ch` is a valid Unicode Scalar Value
+ unsafe {
+ Some(mem::transmute(ch))
}
}
}
/// Use with the `std::iter` module.
#[deriving(Clone)]
pub struct CharOffsets<'a> {
- /// The original string to be iterated
- string: &'a str,
+ front_offset: uint,
iter: Chars<'a>,
}
impl<'a> Iterator<(uint, char)> for CharOffsets<'a> {
#[inline]
fn next(&mut self) -> Option<(uint, char)> {
- // Compute the byte offset by using the pointer offset between
- // the original string slice and the iterator's remaining part
- let offset = self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
- self.iter.next().map(|ch| (offset, ch))
+ let (pre_len, _) = self.iter.iter.size_hint();
+ match self.iter.next() {
+ None => None,
+ Some(ch) => {
+ let index = self.front_offset;
+ let (len, _) = self.iter.iter.size_hint();
+ self.front_offset += pre_len - len;
+ Some((index, ch))
+ }
+ }
}
#[inline]
impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> {
#[inline]
fn next_back(&mut self) -> Option<(uint, char)> {
- self.iter.next_back().map(|ch| {
- let offset = self.iter.string.len() +
- self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
- (offset, ch)
- })
+ match self.iter.next_back() {
+ None => None,
+ Some(ch) => {
+ let (len, _) = self.iter.iter.size_hint();
+ let index = self.front_offset + len;
+ Some((index, ch))
+ }
+ }
}
}
// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
// %xF4 %x80-8F 2( UTF8-tail )
match w {
- 2 => if second & 192 != TAG_CONT_U8 {err!()},
+ 2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()},
3 => {
- match (first, second, next!() & 192) {
+ match (first, second, next!() & !CONT_MASK) {
(0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) |
(0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
(0xED , 0x80 .. 0x9F, TAG_CONT_U8) |
}
}
4 => {
- match (first, second, next!() & 192, next!() & 192) {
+ match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) {
(0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
pub next: uint,
}
-// Return the initial codepoint accumulator for the first byte.
-// The first byte is special, only want bottom 5 bits for width 2, 4 bits
-// for width 3, and 3 bits for width 4
-macro_rules! utf8_first_byte(
- ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
-)
-
-// return the value of $ch updated with continuation byte $byte
-macro_rules! utf8_acc_cont_byte(
- ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32)
-)
-
-static TAG_CONT_U8: u8 = 128u8;
+/// Mask of the value bits of a continuation byte
+static CONT_MASK: u8 = 0b0011_1111u8;
+/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte
+static TAG_CONT_U8: u8 = 0b1000_0000u8;
/// Unsafe operations
pub mod raw {
#[inline]
fn chars(&self) -> Chars<'a> {
- Chars{string: *self}
+ Chars{iter: self.as_bytes().iter()}
}
#[inline]
#[inline]
fn char_indices(&self) -> CharOffsets<'a> {
- CharOffsets{string: *self, iter: self.chars()}
+ CharOffsets{front_offset: 0, iter: self.chars()}
}
#[inline]
// Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
fn multibyte_char_range_at_reverse(s: &str, mut i: uint) -> CharRange {
// while there is a previous byte == 10......
- while i > 0 && s.as_bytes()[i] & 192u8 == TAG_CONT_U8 {
+ while i > 0 && s.as_bytes()[i] & !CONT_MASK == TAG_CONT_U8 {
i -= 1u;
}
}
/// Puts `prefix` on a line above this label, with a blank line separator.
- pub fn prefix_line(self, prefix: LabelText) -> LabelText {
+ pub fn prefix_line(self, prefix: LabelText) -> LabelText<'static> {
prefix.suffix_line(self)
}
/// Puts `suffix` on a line below this label, with a blank line separator.
- pub fn suffix_line(self, suffix: LabelText) -> LabelText {
+ pub fn suffix_line(self, suffix: LabelText) -> LabelText<'static> {
let prefix = self.pre_escaped_content().into_string();
let suffix = suffix.pre_escaped_content();
EscStr(str::Owned(prefix.append(r"\n\n").append(suffix.as_slice())))
}
impl<'a,T> FromIterator<T> for MaybeOwnedVector<'a,T> {
- fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeOwnedVector<T> {
+ fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeOwnedVector<'a,T> {
// If we are building from scratch, might as well build the
// most flexible variant.
Growable(FromIterator::from_iter(iterator))
type UnsafeTaskReceiver = raw::Closure;
trait ClosureConverter {
fn from_fn(|&mut Scheduler, Box<GreenTask>|) -> Self;
- fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|;
+ fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|:'static ;
}
impl ClosureConverter for UnsafeTaskReceiver {
fn from_fn(f: |&mut Scheduler, Box<GreenTask>|) -> UnsafeTaskReceiver {
unsafe { mem::transmute(f) }
}
- fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>| {
+ fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|:'static {
unsafe { mem::transmute(self) }
}
}
};
// Look in attributes 100% of the time to make sure the attribute is marked
- // as used. After doing this, however, favor crate names from the command
- // line.
+ // as used. After doing this, however, we still prioritize a crate name from
+ // the command line over one found in the #[crate_name] attribute. If we
+ // find both we ensure that they're the same later on as well.
let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
.and_then(|at| at.value_str().map(|s| (at, s)));
match sess {
Some(sess) => {
match sess.opts.crate_name {
- Some(ref s) => return validate(s.clone(), None),
+ Some(ref s) => {
+ match attr_crate_name {
+ Some((attr, ref name)) if s.as_slice() != name.get() => {
+ let msg = format!("--crate-name and #[crate_name] \
+ are required to match, but `{}` \
+ != `{}`", s, name);
+ sess.span_err(attr.span, msg.as_slice());
+ }
+ _ => {},
+ }
+ return validate(s.clone(), None);
+ }
None => {}
}
}
add_dynamic_crate(cmd, sess, src.dylib.unwrap())
}
cstore::RequireStatic => {
- add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap())
+ add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap())
}
}
// Adds the static "rlib" versions of all crates to the command line.
fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
- cnum: ast::CrateNum, cratepath: Path) {
+ cratepath: Path) {
// When performing LTO on an executable output, all of the
// bytecode from the upstream libraries has already been
// included in our object file output. We need to modify all of
// If we're not doing LTO, then our job is simply to just link
// against the archive.
if sess.lto() {
- let name = sess.cstore.get_crate_data(cnum).name.clone();
+ let name = cratepath.filename_str().unwrap();
+ let name = name.slice(3, name.len() - 5); // chop off lib/.rlib
time(sess.time_passes(),
format!("altering {}.rlib", name).as_slice(),
(), |()| {
};
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
- debug!("reading {}", name);
+ let file = path.filename_str().unwrap();
+ let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
+ debug!("reading {}", file);
let bc = time(sess.time_passes(),
format!("read {}.bytecode.deflate", name).as_slice(),
(),
|_| {
archive.read(format!("{}.bytecode.deflate",
- name).as_slice())
+ file).as_slice())
});
let bc = bc.expect("missing compressed bytecode in archive!");
let bc = time(sess.time_passes(),
- format!("inflate {}.bc", name).as_slice(),
+ format!("inflate {}.bc", file).as_slice(),
(),
|_| {
match flate::inflate_bytes(bc) {
E0091,
E0092,
E0093,
- E0094
+ E0094,
+ E0095,
+ E0096,
+ E0097,
+ E0098,
+ E0099,
+ E0100,
+ E0101,
+ E0102,
+ E0103,
+ E0104,
+ E0105,
+ E0106,
+ E0107,
+ E0108,
+ E0109,
+ E0110,
+ E0111,
+ E0112,
+ E0113,
+ E0114,
+ E0115,
+ E0116,
+ E0117,
+ E0118,
+ E0119,
+ E0120,
+ E0121,
+ E0122,
+ E0123,
+ E0124,
+ E0125,
+ E0126,
+ E0127,
+ E0128,
+ E0129,
+ E0130,
+ E0131,
+ E0132,
+ E0133,
+ E0134,
+ E0135,
+ E0136,
+ E0137,
+ E0138,
+ E0139,
+ E0140,
+ E0141,
+ E0142,
+ E0143,
+ E0144,
+ E0145,
+ E0146,
+ E0147,
+ E0148,
+ E0149,
+ E0150,
+ E0151,
+ E0152,
+ E0153,
+ E0154,
+ E0155,
+ E0156,
+ E0157
)
pub out_directory: Path,
pub out_filestem: String,
pub single_output_file: Option<Path>,
+ extra: String,
}
impl OutputFilenames {
}
pub fn temp_path(&self, flavor: link::OutputType) -> Path {
- let base = self.out_directory.join(self.out_filestem.as_slice());
+ let base = self.out_directory.join(self.filestem());
match flavor {
link::OutputTypeBitcode => base.with_extension("bc"),
link::OutputTypeAssembly => base.with_extension("s"),
}
pub fn with_extension(&self, extension: &str) -> Path {
- let stem = self.out_filestem.as_slice();
- self.out_directory.join(stem).with_extension(extension)
+ self.out_directory.join(self.filestem()).with_extension(extension)
+ }
+
+ fn filestem(&self) -> String {
+ format!("{}{}", self.out_filestem, self.extra)
}
}
out_directory: dirpath,
out_filestem: stem,
single_output_file: None,
+ extra: sess.opts.cg.extra_filename.clone(),
}
}
out_directory: out_file.dir_path(),
out_filestem: out_file.filestem_str().unwrap().to_string(),
single_output_file: ofile,
+ extra: sess.opts.cg.extra_filename.clone(),
}
}
}
}
pub mod middle {
- pub mod def;
- pub mod trans;
- pub mod ty;
- pub mod ty_fold;
- pub mod subst;
- pub mod resolve;
- pub mod resolve_lifetime;
- pub mod typeck;
+ pub mod astencode;
+ pub mod borrowck;
+ pub mod cfg;
+ pub mod check_const;
pub mod check_loop;
pub mod check_match;
- pub mod check_const;
pub mod check_static;
- pub mod borrowck;
+ pub mod const_eval;
pub mod dataflow;
- pub mod mem_categorization;
- pub mod liveness;
- pub mod kind;
+ pub mod dead;
+ pub mod def;
+ pub mod dependency_format;
+ pub mod effect;
+ pub mod entry;
+ pub mod expr_use_visitor;
pub mod freevars;
- pub mod pat_util;
- pub mod region;
- pub mod const_eval;
- pub mod astencode;
+ pub mod graph;
+ pub mod intrinsicck;
+ pub mod kind;
pub mod lang_items;
+ pub mod liveness;
+ pub mod mem_categorization;
+ pub mod pat_util;
pub mod privacy;
- pub mod entry;
- pub mod effect;
pub mod reachable;
- pub mod graph;
- pub mod cfg;
- pub mod dead;
- pub mod expr_use_visitor;
- pub mod dependency_format;
- pub mod weak_lang_items;
+ pub mod region;
+ pub mod resolve;
+ pub mod resolve_lifetime;
pub mod save;
- pub mod intrinsicck;
pub mod stability;
+ pub mod subst;
+ pub mod trans;
+ pub mod ty;
+ pub mod ty_fold;
+ pub mod typeck;
+ pub mod weak_lang_items;
}
pub mod front {
ebml_w: &mut Encoder,
id: NodeId,
variants: &[P<Variant>],
- index: &mut Vec<entry<i64>>,
- generics: &ast::Generics) {
+ index: &mut Vec<entry<i64>>) {
debug!("encode_enum_variant_info(id={:?})", id);
let mut disr_val = 0;
encode_stability(ebml_w, stab);
match variant.node.kind {
- ast::TupleVariantKind(ref args)
- if args.len() > 0 && generics.ty_params.len() == 0 => {
- encode_symbol(ecx, ebml_w, variant.node.id);
- }
ast::TupleVariantKind(_) => {},
ast::StructVariantKind(_) => {
let fields = ty::lookup_struct_fields(ecx.tcx, def_id);
encode_stability(ebml_w, stab);
ebml_w.end_tag();
}
- ItemEnum(ref enum_definition, ref generics) => {
+ ItemEnum(ref enum_definition, _) => {
add_to_index(item, ebml_w, index);
ebml_w.start_tag(tag_items_data_item);
ebml_w,
item.id,
(*enum_definition).variants.as_slice(),
- index,
- generics);
+ index);
}
ItemStruct(struct_def, _) => {
let fields = ty::lookup_struct_fields(tcx, def_id);
// except according to those terms.
use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val};
-use middle::const_eval::{eval_const_expr, lookup_const_by_id};
+use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id};
use middle::def::*;
use middle::pat_util::*;
use middle::ty::*;
use syntax::ast::*;
use syntax::ast_util::{is_unguarded, walk_pat};
use syntax::codemap::{Span, Spanned, DUMMY_SP};
-use syntax::owned_slice::OwnedSlice;
+use syntax::fold::{Folder, noop_fold_pat};
use syntax::print::pprust::pat_to_string;
+use syntax::parse::token;
use syntax::visit;
use syntax::visit::{Visitor, FnKind};
use util::ppaux::ty_to_string;
}
}
+impl FromIterator<Vec<Gc<Pat>>> for Matrix {
+ fn from_iter<T: Iterator<Vec<Gc<Pat>>>>(mut iterator: T) -> Matrix {
+ Matrix(iterator.collect())
+ }
+}
+
pub struct MatchCheckCtxt<'a> {
pub tcx: &'a ty::ctxt
}
}
pub fn check_crate(tcx: &ty::ctxt, krate: &Crate) {
- let mut cx = MatchCheckCtxt { tcx: tcx, };
-
+ let mut cx = MatchCheckCtxt { tcx: tcx };
visit::walk_crate(&mut cx, krate, ());
-
tcx.sess.abort_if_errors();
}
// If the type *is* empty, it's vacuously exhaustive
return;
}
- let m: Matrix = Matrix(arms
+
+ let mut static_inliner = StaticInliner { tcx: cx.tcx };
+ let matrix: Matrix = arms
.iter()
.filter(|&arm| is_unguarded(arm))
.flat_map(|arm| arm.pats.iter())
- .map(|pat| vec!(pat.clone()))
- .collect());
- check_exhaustive(cx, ex.span, &m);
+ .map(|pat| vec![static_inliner.fold_pat(*pat)])
+ .collect();
+ check_exhaustive(cx, ex.span, &matrix);
},
_ => ()
}
}
+fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool {
+ match eval_const_expr(tcx, expr) {
+ const_float(f) => f.is_nan(),
+ _ => false
+ }
+}
+
// Check for unreachable patterns
fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
let mut seen = Matrix(vec!());
+ let mut static_inliner = StaticInliner { tcx: cx.tcx };
for arm in arms.iter() {
for pat in arm.pats.iter() {
+ let inlined = static_inliner.fold_pat(*pat);
+
// Check that we do not match against a static NaN (#6804)
- let pat_matches_nan: |&Pat| -> bool = |p| {
- let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
- match opt_def {
- Some(DefStatic(did, false)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- match eval_const_expr(cx.tcx, &*const_expr) {
- const_float(f) if f.is_nan() => true,
- _ => false
- }
+ walk_pat(&*inlined, |p| {
+ match p.node {
+ PatLit(expr) if is_expr_const_nan(cx.tcx, &*expr) => {
+ span_warn!(cx.tcx.sess, pat.span, E0003,
+ "unmatchable NaN in pattern, \
+ use the is_nan method in a guard instead");
}
- _ => false
- }
- };
-
- walk_pat(&**pat, |p| {
- if pat_matches_nan(p) {
- span_warn!(cx.tcx.sess, p.span, E0003,
- "unmatchable NaN in pattern, use the is_nan method in a guard instead"
- );
+ _ => ()
}
true
});
- let v = vec!(*pat);
+ let v = vec![inlined];
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"),
Useful => (),
}
}
-fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
- match is_useful(cx, m, [wild()], ConstructWitness) {
+fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) {
+ match is_useful(cx, matrix, [wild()], ConstructWitness) {
UsefulWithWitness(pats) => {
let witness = match pats.as_slice() {
[witness] => witness,
}
}
-fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
- ty::with_path(tcx, id, |mut path| Path {
- global: false,
- segments: path.last().map(|elem| PathSegment {
- identifier: Ident::new(elem.name()),
- lifetimes: vec!(),
- types: OwnedSlice::empty()
- }).move_iter().collect(),
- span: DUMMY_SP,
- })
+pub struct StaticInliner<'a> {
+ pub tcx: &'a ty::ctxt
+}
+
+impl<'a> Folder for StaticInliner<'a> {
+ fn fold_pat(&mut self, pat: Gc<Pat>) -> Gc<Pat> {
+ match pat.node {
+ PatIdent(..) | PatEnum(..) => {
+ let def = self.tcx.def_map.borrow().find_copy(&pat.id);
+ match def {
+ Some(DefStatic(did, _)) => {
+ let const_expr = lookup_const_by_id(self.tcx, did).unwrap();
+ const_expr_to_pat(self.tcx, const_expr)
+ },
+ _ => noop_fold_pat(pat, self)
+ }
+ }
+ _ => noop_fold_pat(pat, self)
+ }
+ }
}
/// Constructs a partial witness for a pattern given a list of
ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
let (vid, is_structure) = match ctor {
- &Variant(vid) => (vid,
- ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
- _ => (cid, true)
+ &Variant(vid) =>
+ (vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
+ _ =>
+ (cid, ty::lookup_struct_fields(cx.tcx, cid).iter()
+ .any(|field| field.name != token::special_idents::unnamed_field.name))
};
if is_structure {
let fields = ty::lookup_struct_fields(cx.tcx, vid);
},
Some(constructor) => {
- let matrix = Matrix(rows.iter().filter_map(|r|
- default(cx, r.as_slice())).collect());
+ let matrix = rows.iter().filter_map(|r| default(cx, r.as_slice())).collect();
match is_useful(cx, &matrix, v.tail(), witness) {
UsefulWithWitness(pats) => {
let arity = constructor_arity(cx, &constructor, left_ty);
match pat.node {
PatIdent(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
- Some(&DefStatic(did, false)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
- },
+ Some(&DefStatic(..)) =>
+ cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefStruct(_)) => vec!(Single),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!()
},
PatEnum(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
- Some(&DefStatic(did, false)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
- },
+ Some(&DefStatic(..)) =>
+ cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
PatStruct(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
+ Some(&DefStatic(..)) =>
+ cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
}
fn range_covered_by_constructor(ctor: &Constructor,
- from: &const_val,to: &const_val) -> Option<bool> {
+ from: &const_val, to: &const_val) -> Option<bool> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
&PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
match opt_def {
+ Some(DefStatic(..)) =>
+ cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
},
- Some(DefStatic(did, _)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- let e_v = eval_const_expr(cx.tcx, &*const_expr);
- match range_covered_by_constructor(constructor, &e_v, &e_v) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
- cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
- None
- }
- }
- }
- _ => {
- Some(Vec::from_elem(arity, wild()))
- }
+ _ => Some(Vec::from_elem(arity, wild()))
}
}
&PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
match def {
- DefStatic(did, _) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- let e_v = eval_const_expr(cx.tcx, &*const_expr);
- match range_covered_by_constructor(constructor, &e_v, &e_v) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
- cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
- None
- }
- }
- }
+ DefStatic(..) =>
+ cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None,
DefVariant(..) | DefFn(..) | DefStruct(..) => {
Some(match args {
// Is this a struct or an enum variant?
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
let class_id = match def {
+ DefStatic(..) =>
+ cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
Some(variant_id)
} else {
LocalFor => "`for` loop"
};
- match is_refutable(cx, loc.pat) {
+ let mut static_inliner = StaticInliner { tcx: cx.tcx };
+ match is_refutable(cx, static_inliner.fold_pat(loc.pat)) {
Some(pat) => {
span_err!(cx.tcx.sess, loc.pat.span, E0005,
"refutable pattern in {} binding: `{}` not covered",
use metadata::csearch;
use middle::astencode;
-
use middle::def;
+use middle::pat_util::def_to_path;
use middle::ty;
use middle::typeck::astconv;
use util::nodemap::{DefIdMap};
use syntax::{ast, ast_map, ast_util};
use std::rc::Rc;
-use std::gc::Gc;
+use std::gc::{Gc, GC};
//
// This pass classifies expressions by their constant-ness.
const_nil
}
+pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: Gc<Expr>) -> Gc<Pat> {
+ let pat = match expr.node {
+ ExprTup(ref exprs) =>
+ PatTup(exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect()),
+
+ ExprCall(callee, ref args) => {
+ let def = tcx.def_map.borrow().get_copy(&callee.id);
+ tcx.def_map.borrow_mut().find_or_insert(expr.id, def);
+ let path = match def {
+ def::DefStruct(def_id) => def_to_path(tcx, def_id),
+ def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
+ _ => unreachable!()
+ };
+ let pats = args.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect();
+ PatEnum(path, Some(pats))
+ }
+
+ ExprStruct(ref path, ref fields, None) => {
+ let field_pats = fields.iter().map(|field| FieldPat {
+ ident: field.ident.node,
+ pat: const_expr_to_pat(tcx, field.expr)
+ }).collect();
+ PatStruct(path.clone(), field_pats, false)
+ }
+
+ ExprVec(ref exprs) => {
+ let pats = exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect();
+ PatVec(pats, None, vec![])
+ }
+
+ ExprPath(ref path) => {
+ let opt_def = tcx.def_map.borrow().find_copy(&expr.id);
+ match opt_def {
+ Some(def::DefStruct(..)) =>
+ PatStruct(path.clone(), vec![], false),
+ Some(def::DefVariant(..)) =>
+ PatEnum(path.clone(), None),
+ _ => {
+ match lookup_const(tcx, &*expr) {
+ Some(actual) => return const_expr_to_pat(tcx, actual),
+ _ => unreachable!()
+ }
+ }
+ }
+ }
+
+ _ => PatLit(expr)
+ };
+ box (GC) Pat { id: expr.id, node: pat, span: expr.span }
+}
+
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
match eval_const_expr_partial(tcx, e) {
Ok(r) => r,
match self.unsafe_context {
SafeContext => {
// Report an error.
- self.tcx.sess.span_err(span,
- format!("{} requires unsafe function or \
- block",
- description).as_slice())
+ span_err!(self.tcx.sess, span, E0133,
+ "{} requires unsafe function or block",
+ description);
}
UnsafeBlock(block_id) => {
// OK, but record this.
match ty::get(base_type).sty {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
ty::ty_str => {
- self.tcx.sess.span_err(e.span,
- "modification of string types is not allowed");
+ span_err!(self.tcx.sess, e.span, E0134,
+ "modification of string types is not allowed");
}
_ => {}
},
ty::ty_str => {
- self.tcx.sess.span_err(e.span,
- "modification of string types is not allowed");
+ span_err!(self.tcx.sess, e.span, E0135,
+ "modification of string types is not allowed");
}
_ => {}
}
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'main' functions");
+ span_err!(ctxt.session, item.span, E0136,
+ "multiple 'main' functions");
}
} else {
// This isn't main
if ctxt.attr_main_fn.is_none() {
ctxt.attr_main_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'main' functions");
+ span_err!(ctxt.session, item.span, E0137,
+ "multiple functions with a #[main] attribute");
}
}
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'start' functions");
+ span_err!(ctxt.session, item.span, E0138,
+ "multiple 'start' functions");
}
}
}
fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) {
if type_size_is_affected_by_type_parameters(self.tcx, from) {
- self.tcx.sess.span_err(span,
- "cannot transmute from a type that \
- contains type parameters");
+ span_err!(self.tcx.sess, span, E0139,
+ "cannot transmute from a type that contains type parameters");
}
if type_size_is_affected_by_type_parameters(self.tcx, to) {
- self.tcx.sess.span_err(span,
- "cannot transmute to a type that contains \
- type parameters");
+ span_err!(self.tcx.sess, span, E0140,
+ "cannot transmute to a type that contains type parameters");
}
let restriction = TransmuteRestriction {
let struct_ty = ty::mk_struct(cx.tcx, struct_did,
subst::Substs::empty());
if !ty::type_is_sendable(cx.tcx, struct_ty) {
- cx.tcx.sess.span_err(span,
- "cannot implement a destructor on a \
- structure that does not satisfy Send");
- cx.tcx.sess.span_note(span,
- "use \"#[unsafe_destructor]\" on the \
- implementation to force the compiler to \
- allow this");
+ span_err!(cx.tcx.sess, span, E0125,
+ "cannot implement a destructor on a \
+ structure that does not satisfy Send");
+ span_note!(cx.tcx.sess, span,
+ "use \"#[unsafe_destructor]\" on the implementation \
+ to force the compiler to allow this");
}
} else {
- cx.tcx.sess.span_err(span,
- "cannot implement a destructor on a structure \
- with type parameters");
- cx.tcx.sess.span_note(span,
- "use \"#[unsafe_destructor]\" on the \
- implementation to force the compiler to \
- allow this");
+ span_err!(cx.tcx.sess, span, E0141,
+ "cannot implement a destructor on a structure \
+ with type parameters");
+ span_note!(cx.tcx.sess, span,
+ "use \"#[unsafe_destructor]\" on the implementation \
+ to force the compiler to allow this");
}
}
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
debug!("checking impl with self type {}", ty::get(self_ty).sty);
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
- cx.tcx.sess.span_err(self_type.span,
- format!("the type `{}', which does not fulfill `{}`, cannot implement this \
- trait",
- ty_to_string(cx.tcx, self_ty),
- missing.user_string(cx.tcx)).as_slice());
- cx.tcx.sess.span_note(self_type.span,
- format!("types implementing this trait must fulfill `{}`",
- trait_def.bounds.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, self_type.span, E0142,
+ "the type `{}', which does not fulfill `{}`, cannot implement this trait",
+ ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
+ span_note!(cx.tcx.sess, self_type.span,
+ "types implementing this trait must fulfill `{}`",
+ trait_def.bounds.user_string(cx.tcx));
});
// If this is a destructor, check kinds.
}
fn check_for_bare(cx: &Context, fv: &freevar_entry) {
- cx.tcx.sess.span_err(
- fv.span,
- "can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
+ span_err!(cx.tcx.sess, fv.span, E0143,
+ "can't capture dynamic environment in a fn item; \
+ use the || {} closure form instead", "{ ... }");
} // same check is done in resolve.rs, but shouldn't be done
let fty = ty::node_id_to_type(cx.tcx, id);
ty,
type_param_def.bounds.builtin_bounds,
|missing| {
- cx.tcx.sess.span_err(
- sp,
- format!("instantiating a type parameter with an incompatible type \
- `{}`, which does not fulfill `{}`",
- ty_to_string(cx.tcx, ty),
- missing.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, sp, E0144,
+ "instantiating a type parameter with an incompatible type \
+ `{}`, which does not fulfill `{}`",
+ ty_to_string(cx.tcx, ty),
+ missing.user_string(cx.tcx));
});
}
// Emit a less mysterious error message in this case.
match referenced_ty {
Some(rty) => {
- cx.tcx.sess.span_err(sp,
- format!("cannot implicitly borrow variable of type `{}` in a \
- bounded stack closure (implicit reference does not \
- fulfill `{}`)",
- ty_to_string(cx.tcx, rty),
- missing.user_string(cx.tcx)).as_slice())
+ span_err!(cx.tcx.sess, sp, E0145,
+ "cannot implicitly borrow variable of type `{}` in a \
+ bounded stack closure (implicit reference does not fulfill `{}`)",
+ ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
}
None => {
- cx.tcx.sess.span_err(sp,
- format!("cannot capture variable of type `{}`, which does \
- not fulfill `{}`, in a bounded closure",
- ty_to_string(cx.tcx, ty),
- missing.user_string(cx.tcx)).as_slice())
+ span_err!(cx.tcx.sess, sp, E0146,
+ "cannot capture variable of type `{}`, which does \
+ not fulfill `{}`, in a bounded closure",
+ ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
}
}
- cx.tcx.sess.span_note(
- sp,
- format!("this closure's environment must satisfy `{}`",
- bounds.user_string(cx.tcx)).as_slice());
+ span_note!(cx.tcx.sess, sp,
+ "this closure's environment must satisfy `{}`",
+ bounds.user_string(cx.tcx));
});
}
pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
bounds: ty::BuiltinBounds) {
check_builtin_bounds(cx, ty, bounds, |missing| {
- cx.tcx.sess.span_err(sp,
- format!("cannot pack type `{}`, which does not fulfill \
- `{}`, as a trait bounded by {}",
- ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx),
- bounds.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, sp, E0147,
+ "cannot pack type `{}`, which does not fulfill `{}`, as a trait bounded by {}",
+ ty_to_string(cx.tcx, ty),
+ missing.user_string(cx.tcx),
+ bounds.user_string(cx.tcx));
});
}
ty_to_string(cx.tcx, ty),
ty::type_contents(cx.tcx, ty).to_string());
if ty::type_moves_by_default(cx.tcx, ty) {
- cx.tcx.sess.span_err(
- sp,
- format!("copying a value of non-copyable type `{}`",
- ty_to_string(cx.tcx, ty)).as_slice());
- cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
+ span_err!(cx.tcx.sess, sp, E0148,
+ "copying a value of non-copyable type `{}`",
+ ty_to_string(cx.tcx, ty));
+ span_note!(cx.tcx.sess, sp, "{}", reason.as_slice());
}
}
pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
if !ty::type_is_static(tcx, ty) {
match ty::get(ty).sty {
- ty::ty_param(..) => {
- tcx.sess.span_err(sp,
- format!("value may contain references; \
- add `'static` bound to `{}`",
- ty_to_string(tcx, ty)).as_slice());
- }
- _ => {
- tcx.sess.span_err(sp, "value may contain references");
- }
+ ty::ty_param(..) => {
+ span_err!(tcx.sess, sp, E0149,
+ "value may contain references; \
+ add `'static` bound to `{}`",
+ ty_to_string(tcx, ty));
+ }
+ _ => {
+ span_err!(tcx.sess, sp, E0150,
+ "value may contain references");
+ }
}
false
} else {
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
if !ty::type_is_sized(tcx, ty) {
- tcx.sess.span_err(sp,
- format!("variable `{}` has dynamically sized type \
- `{}`",
- name,
- ty_to_string(tcx, ty)).as_slice());
+ span_err!(tcx.sess, sp, E0151,
+ "variable `{}` has dynamically sized type `{}`",
+ name, ty_to_string(tcx, ty));
}
}
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
+use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use syntax::visit::Visitor;
use syntax::visit;
match item_index {
Some(item_index) => {
- self.collect_item(item_index, local_def(item.id))
+ self.collect_item(item_index, local_def(item.id), item.span)
}
None => {}
}
}
}
- pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
+ pub fn collect_item(&mut self, item_index: uint,
+ item_def_id: ast::DefId, span: Span) {
// Check for duplicates.
match self.items.items.get(item_index) {
&Some(original_def_id) if original_def_id != item_def_id => {
- self.session.err(format!("duplicate entry for `{}`",
- LanguageItems::item_name(
- item_index)).as_slice());
+ span_err!(self.session, span, E0152,
+ "duplicate entry for `{}`", LanguageItems::item_name(item_index));
}
&Some(_) | &None => {
// OK.
crate_store.iter_crate_data(|crate_number, _crate_metadata| {
each_lang_item(crate_store, crate_number, |node_id, item_index| {
let def_id = ast::DefId { krate: crate_number, node: node_id };
- self.collect_item(item_index, def_id);
+ self.collect_item(item_index, def_id, DUMMY_SP);
true
});
})
use middle::def::*;
use middle::resolve;
+use middle::ty;
use std::collections::HashMap;
use std::gc::{Gc, GC};
use syntax::ast::*;
use syntax::ast_util::{walk_pat};
use syntax::codemap::{Span, DUMMY_SP};
+use syntax::owned_slice::OwnedSlice;
pub type PatIdMap = HashMap<Ident, NodeId>;
pub fn wild() -> Gc<Pat> {
box (GC) Pat { id: 0, node: PatWild, span: DUMMY_SP }
}
+
+pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
+ ty::with_path(tcx, id, |mut path| Path {
+ global: false,
+ segments: path.last().map(|elem| PathSegment {
+ identifier: Ident::new(elem.name()),
+ lifetimes: vec!(),
+ types: OwnedSlice::empty()
+ }).move_iter().collect(),
+ span: DUMMY_SP,
+ })
+}
this.record_def(path_id, (def, lp));
}
Some((DefStruct(_), _)) => {
- this.session.span_err(t.span,
- "super-struct is defined \
- in a different crate")
+ span_err!(this.session, t.span, E0154,
+ "super-struct is defined in a different crate");
},
- Some(_) => this.session.span_err(t.span,
- "super-struct is not a struct type"),
- None => this.session.span_err(t.span,
- "super-struct could not be resolved"),
+ Some(_) => {
+ span_err!(this.session, t.span, E0155,
+ "super-struct is not a struct type");
+ }
+ None => {
+ span_err!(this.session, t.span, E0156,
+ "super-struct could not be resolved");
+ }
}
},
_ => this.session.span_bug(t.span, "path not mapped to a TyPath")
if path.segments
.iter()
.any(|s| !s.lifetimes.is_empty()) {
- self.session.span_err(path.span,
- "lifetime parameters \
- are not allowed on \
- this type")
+ span_err!(self.session, path.span, E0157,
+ "lifetime parameters are not allowed on this type");
} else if path.segments
.iter()
.any(|s| s.types.len() > 0) {
- self.session.span_err(path.span,
- "type parameters are \
- not allowed on this \
- type")
+ span_err!(self.session, path.span, E0153,
+ "type parameters are not allowed on this type");
}
}
None => {
let ident = path1.node;
let renamed = mtwt::resolve(ident);
- match self.resolve_bare_identifier_pattern(ident) {
+ match self.resolve_bare_identifier_pattern(ident, pattern.span) {
FoundStructOrEnumVariant(def, lp)
if mode == RefutableMode => {
debug!("(resolving pattern) resolving `{}` to \
});
}
- fn resolve_bare_identifier_pattern(&mut self, name: Ident)
+ fn resolve_bare_identifier_pattern(&mut self, name: Ident, span: Span)
-> BareIdentifierPatternResolution {
let module = self.current_module.clone();
match self.resolve_item_in_lexical_scope(module,
def @ DefStatic(_, false) => {
return FoundConst(def, LastMod(AllPublic));
}
+ DefStatic(_, true) => {
+ self.resolve_error(span,
+ "mutable static variables cannot be referenced in a pattern");
+ return BareIdentifierPatternUnresolved;
+ }
_ => {
return BareIdentifierPatternUnresolved;
}
use middle::const_eval;
use middle::def;
use middle::check_match;
+use middle::check_match::StaticInliner;
use middle::lang_items::StrEqFnLangItem;
use middle::pat_util::*;
use middle::resolve::DefMap;
use syntax::ast;
use syntax::ast::Ident;
use syntax::codemap::Span;
+use syntax::fold::Folder;
use syntax::parse::token::InternedString;
-// An option identifying a literal: either an expression or a DefId of a static expression.
-enum Lit {
- ExprLit(Gc<ast::Expr>),
- ConstLit(ast::DefId), // the def ID of the constant
-}
-
#[deriving(PartialEq)]
pub enum VecLenOpt {
vec_len_eq,
// An option identifying a branch (either a literal, an enum variant or a
// range)
enum Opt {
- lit(Lit),
+ lit(Gc<ast::Expr>),
var(ty::Disr, Rc<adt::Repr>, ast::DefId),
range(Gc<ast::Expr>, Gc<ast::Expr>),
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
-fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc<ast::Expr> {
- match *a {
- ExprLit(existing_a_expr) => existing_a_expr,
- ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap()
- }
-}
-
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
match (a, b) {
- (&lit(a), &lit(b)) => {
- let a_expr = lit_to_expr(tcx, &a);
- let b_expr = lit_to_expr(tcx, &b);
+ (&lit(a_expr), &lit(b_expr)) => {
match const_eval::compare_lit_exprs(tcx, &*a_expr, &*b_expr) {
Some(val1) => val1 == 0,
None => fail!("compare_list_exprs: type mismatch"),
range_result(Result<'a>, Result<'a>),
}
-fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
+fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
let _icx = push_ctxt("match::trans_opt");
let ccx = bcx.ccx();
- let mut bcx = bcx;
match *o {
- lit(ExprLit(ref lit_expr)) => {
- let lit_datum = unpack_datum!(bcx, expr::trans(bcx, &**lit_expr));
- let lit_datum = lit_datum.assert_rvalue(bcx); // literals are rvalues
- let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
- return single_result(Result::new(bcx, lit_datum.val));
- }
- lit(l @ ConstLit(ref def_id)) => {
- let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_to_expr(bcx.tcx(), &l).id);
- let (llval, _) = consts::get_const_val(bcx.ccx(), *def_id);
+ lit(lit_expr) => {
+ let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
+ let (llval, _) = consts::const_expr(ccx, &*lit_expr, true);
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
let _indenter = indenter();
let ctor = match opt {
- &lit(x) => {
- check_match::ConstantValue(const_eval::eval_const_expr(
- bcx.tcx(), &*lit_to_expr(bcx.tcx(), &x)))
- }
- &range(ref lo, ref hi) => check_match::ConstantRange(
- const_eval::eval_const_expr(bcx.tcx(), &**lo),
- const_eval::eval_const_expr(bcx.tcx(), &**hi)
+ &lit(expr) => check_match::ConstantValue(
+ const_eval::eval_const_expr(bcx.tcx(), &*expr)
+ ),
+ &range(lo, hi) => check_match::ConstantRange(
+ const_eval::eval_const_expr(bcx.tcx(), &*lo),
+ const_eval::eval_const_expr(bcx.tcx(), &*hi)
),
&vec_len(len, _, _) => check_match::Slice(len),
&var(_, _, def_id) => check_match::Variant(def_id)
let cur = *br.pats.get(col);
match cur.node {
ast::PatLit(l) => {
- add_to_set(ccx.tcx(), &mut found, lit(ExprLit(l)));
+ add_to_set(ccx.tcx(), &mut found, lit(l));
}
ast::PatIdent(..) => {
// This is either an enum variant or a variable binding.
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
- Some(def::DefStatic(const_did, false)) => {
- add_to_set(ccx.tcx(), &mut found,
- lit(ConstLit(const_did)));
- }
_ => {}
}
}
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
- Some(def::DefStatic(const_did, false)) => {
- add_to_set(ccx.tcx(), &mut found,
- lit(ConstLit(const_did)));
- }
_ => {}
}
}
bindings_map: create_bindings_map(bcx, *arm.pats.get(0))
}).collect();
+ let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() };
let mut matches = Vec::new();
for arm_data in arm_datas.iter() {
- matches.extend(arm_data.arm.pats.iter().map(|p| Match {
- pats: vec!(*p),
+ matches.extend(arm_data.arm.pats.iter().map(|&p| Match {
+ pats: vec![static_inliner.fold_pat(p)],
data: arm_data,
bound_ptrs: Vec::new(),
}));
}
}
}
- Some(def::DefStatic(_, false)) => {
- }
_ => {
// Nothing to do here.
}
}
/**
- * Begin initializing a new value of the given case of the given
- * representation. The fields, if any, should then be initialized via
- * `trans_field_ptr`.
+ * Set the discriminant for a new value of the given case of the given
+ * representation.
*/
-pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
+pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
match *r {
CEnum(ity, min, max) => {
assert_discr_in_range(ity, min, max, discr);
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::{i8, i16, i32, i64};
-use std::gc::Gc;
use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
use syntax::abi::{RustIntrinsic, Abi};
use syntax::ast_util::{local_def, is_local};
llfndecl);
}
+pub fn trans_named_tuple_constructor<'a>(mut bcx: &'a Block<'a>,
+ ctor_ty: ty::t,
+ disr: ty::Disr,
+ args: callee::CallArgs,
+ dest: expr::Dest) -> Result<'a> {
+
+ let ccx = bcx.fcx.ccx;
+ let tcx = &ccx.tcx;
+
+ let result_ty = match ty::get(ctor_ty).sty {
+ ty::ty_bare_fn(ref bft) => bft.sig.output,
+ _ => ccx.sess().bug(
+ format!("trans_enum_variant_constructor: \
+ unexpected ctor return type {}",
+ ctor_ty.repr(tcx)).as_slice())
+ };
+
+ // Get location to store the result. If the user does not care about
+ // the result, just make a stack slot
+ let llresult = match dest {
+ expr::SaveIn(d) => d,
+ expr::Ignore => {
+ if !type_is_zero_size(ccx, result_ty) {
+ alloc_ty(bcx, result_ty, "constructor_result")
+ } else {
+ C_undef(type_of::type_of(ccx, result_ty))
+ }
+ }
+ };
+
+ if !type_is_zero_size(ccx, result_ty) {
+ let repr = adt::represent_type(ccx, result_ty);
+
+ match args {
+ callee::ArgExprs(exprs) => {
+ let fields = exprs.iter().map(|x| *x).enumerate().collect::<Vec<_>>();
+ bcx = expr::trans_adt(bcx, &*repr, disr, fields.as_slice(),
+ None, expr::SaveIn(llresult));
+ }
+ _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
+ }
+ }
+
+ // If the caller doesn't care about the result
+ // drop the temporary we made
+ let bcx = match dest {
+ expr::SaveIn(_) => bcx,
+ expr::Ignore => glue::drop_ty(bcx, llresult, result_ty)
+ };
+
+ Result::new(bcx, llresult)
+}
+
pub fn trans_tuple_struct(ccx: &CrateContext,
_fields: &[ast::StructField],
ctor_id: ast::NodeId,
if !type_is_zero_size(fcx.ccx, result_ty) {
let repr = adt::represent_type(ccx, result_ty);
- adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
let lldestptr = adt::trans_field_ptr(bcx,
&*repr,
i);
arg_datum.store_to(bcx, lldestptr);
}
+ adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
}
finish_fn(&fcx, bcx, result_ty);
}
-fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
- sp: Span, id: ast::NodeId, vi: &[Rc<ty::VariantInfo>],
- i: &mut uint) {
- for variant in enum_definition.variants.iter() {
- let disr_val = vi[*i].disr_val;
- *i += 1;
-
- match variant.node.kind {
- ast::TupleVariantKind(ref args) if args.len() > 0 => {
- let llfn = get_item_val(ccx, variant.node.id);
- trans_enum_variant(ccx, id, &**variant, args.as_slice(),
- disr_val, ¶m_substs::empty(), llfn);
- }
- ast::TupleVariantKind(_) => {
- // Nothing to do.
- }
- ast::StructVariantKind(struct_def) => {
- trans_struct_def(ccx, struct_def);
- }
- }
- }
-
- enum_variant_size_lint(ccx, enum_definition, sp, id);
-}
-
fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) {
let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
ast::ItemMod(ref m) => {
trans_mod(ccx, m);
}
- ast::ItemEnum(ref enum_definition, ref generics) => {
- if !generics.is_type_parameterized() {
- let vi = ty::enum_variants(ccx.tcx(), local_def(item.id));
- let mut i = 0;
- trans_enum_def(ccx, enum_definition, item.span, item.id, vi.as_slice(), &mut i);
- }
+ ast::ItemEnum(ref enum_definition, _) => {
+ enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
}
ast::ItemStatic(_, m, ref expr) => {
// Recurse on the expression to catch items in blocks
ast::ItemForeignMod(ref foreign_mod) => {
foreign::trans_foreign_mod(ccx, foreign_mod);
}
- ast::ItemStruct(struct_def, ref generics) => {
- if !generics.is_type_parameterized() {
- trans_struct_def(ccx, struct_def);
- }
- }
ast::ItemTrait(..) => {
// Inside of this trait definition, we won't be actually translating any
// functions, but the trait still needs to be walked. Otherwise default
}
}
-pub fn trans_struct_def(ccx: &CrateContext, struct_def: Gc<ast::StructDef>) {
- // If this is a tuple-like struct, translate the constructor.
- match struct_def.ctor_id {
- // We only need to translate a constructor if there are fields;
- // otherwise this is a unit-like struct.
- Some(ctor_id) if struct_def.fields.len() > 0 => {
- let llfndecl = get_item_val(ccx, ctor_id);
- trans_tuple_struct(ccx, struct_def.fields.as_slice(),
- ctor_id, ¶m_substs::empty(), llfndecl);
- }
- Some(_) | None => {}
- }
-}
-
// Translate a module. Doing this amounts to translating the items in the
// module; there ends up being no artifact (aside from linkage names) of
// separate modules in the compiled program. That's because modules exist
}
}
- pub fn pred_iter(self) -> Preds {
+ pub fn pred_iter(self) -> Preds<'static> {
self.as_value().user_iter()
.filter(|user| user.is_a_terminator_inst())
.map(|user| user.get_parent().unwrap())
use arena::TypedArena;
use back::abi;
use back::link;
+use driver::session;
use llvm::{ValueRef, get_param};
use llvm;
use metadata::csearch;
use std::gc::Gc;
use syntax::ast;
+use syntax::ast_map;
use synabi = syntax::abi;
pub struct MethodData {
pub enum CalleeData {
Closure(Datum<Lvalue>),
+ // Constructor for enum variant/tuple-like-struct
+ // i.e. Some, Ok
+ NamedTupleConstructor(subst::Substs, ty::Disr),
+
// Represents a (possibly monomorphized) top-level fn item or method
// item. Note that this is just the fn-ptr and is not a Rust closure
// value (which is a pair).
debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
let expr_ty = node_id_type(bcx, ref_expr.id);
match def {
+ def::DefFn(did, _) if {
+ let def_id = if did.krate != ast::LOCAL_CRATE {
+ inline::maybe_instantiate_inline(bcx.ccx(), did)
+ } else {
+ did
+ };
+ match bcx.tcx().map.find(def_id.node) {
+ Some(ast_map::NodeStructCtor(_)) => true,
+ _ => false
+ }
+ } => {
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, 0)
+ }
+ }
def::DefFn(did, _) if match ty::get(expr_ty).sty {
ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic,
_ => false
ref_expr.id))
}
def::DefVariant(tid, vid, _) => {
- // nullary variants are not callable
- assert!(ty::enum_variant_with_id(bcx.tcx(),
- tid,
- vid).args.len() > 0u);
- fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
+ let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+
+ // Nullary variants are not callable
+ assert!(vinfo.args.len() > 0u);
+
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, vinfo.disr_val)
+ }
}
- def::DefStruct(def_id) => {
- fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
+ def::DefStruct(_) => {
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, 0)
+ }
}
def::DefStatic(..) |
def::DefArg(..) |
}
};
- // We must monomorphise if the fn has type parameters or is a default method.
- let must_monomorphise = !substs.types.is_empty() || is_default;
+ // We must monomorphise if the fn has type parameters, is a default method,
+ // or is a named tuple constructor.
+ let must_monomorphise = if !substs.types.is_empty() || is_default {
+ true
+ } else if def_id.krate == ast::LOCAL_CRATE {
+ let map_node = session::expect(
+ ccx.sess(),
+ tcx.map.find(def_id.node),
+ || "local item should be in ast map".to_string());
+
+ match map_node {
+ ast_map::NodeVariant(v) => match v.node.kind {
+ ast::TupleVariantKind(ref args) => args.len() > 0,
+ _ => false
+ },
+ ast_map::NodeStructCtor(_) => true,
+ _ => false
+ }
+ } else {
+ false
+ };
// Create a monomorphic version of generic functions
if must_monomorphise {
arg_cleanup_scope, args,
dest.unwrap(), substs);
}
+ NamedTupleConstructor(substs, disr) => {
+ assert!(dest.is_some());
+ fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
+
+ let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
+ return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
+ args, dest.unwrap());
+ }
};
// Intrinsics should not become actual functions.
let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
// Create the closure.
- adt::trans_start_init(bcx, &*repr, dest_addr, 0);
for freevar in freevars_ptr.iter() {
let datum = expr::trans_local_var(bcx, freevar.def);
let upvar_slot_dest = adt::trans_field_ptr(bcx,
0);
bcx = datum.store_to(bcx, upvar_slot_dest);
}
+ adt::trans_set_discr(bcx, &*repr, dest_addr, 0);
bcx
}
// Nullary variant.
let ty = expr_ty(bcx, ref_expr);
let repr = adt::represent_type(bcx.ccx(), ty);
- adt::trans_start_init(bcx, &*repr, lldest,
- variant_info.disr_val);
+ adt::trans_set_discr(bcx, &*repr, lldest,
+ variant_info.disr_val);
return bcx;
}
}
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
let repr = adt::represent_type(bcx.ccx(), ty);
- adt::trans_start_init(bcx, &*repr, lldest, 0);
+ adt::trans_set_discr(bcx, &*repr, lldest, 0);
}
_ => {}
}
* Note that `fields` may be empty; the base expression must always be
* evaluated for side-effects.
*/
-struct StructBaseInfo {
+pub struct StructBaseInfo {
/// The base expression; will be evaluated after all explicit fields.
expr: Gc<ast::Expr>,
/// The indices of fields to copy paired with their types.
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
-fn trans_adt<'a>(
- bcx: &'a Block<'a>,
- repr: &adt::Repr,
- discr: ty::Disr,
- fields: &[(uint, Gc<ast::Expr>)],
- optbase: Option<StructBaseInfo>,
- dest: Dest)
- -> &'a Block<'a> {
+pub fn trans_adt<'a>(bcx: &'a Block<'a>,
+ repr: &adt::Repr,
+ discr: ty::Disr,
+ fields: &[(uint, Gc<ast::Expr>)],
+ optbase: Option<StructBaseInfo>,
+ dest: Dest) -> &'a Block<'a> {
let _icx = push_ctxt("trans_adt");
let fcx = bcx.fcx;
let mut bcx = bcx;
// failure occur before the ADT as a whole is ready.
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
- adt::trans_start_init(bcx, repr, addr, discr);
-
for &(i, ref e) in fields.iter() {
let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
let e_ty = expr_ty_adjusted(bcx, &**e);
}
}
+ adt::trans_set_discr(bcx, repr, addr, discr);
+
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
return bcx;
}
// See [Note-arg-mode]
-pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef,
- static_ti: Option<&tydesc_info>) {
- let _icx = push_ctxt("call_tydesc_glue_full");
- let ccx = bcx.ccx();
- // NB: Don't short-circuit even if this block is unreachable because
- // GC-based cleanup needs to the see that the roots are live.
- if bcx.unreachable.get() && !ccx.sess().no_landing_pads() { return; }
-
- let static_glue_fn = static_ti.map(|sti| lazily_emit_visit_glue(ccx, sti));
-
- // When static type info is available, avoid casting to a generic pointer.
- let llrawptr = if static_glue_fn.is_none() {
- PointerCast(bcx, v, Type::i8p(ccx))
- } else {
- v
- };
+pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef) {
+ let _icx = push_ctxt("call_visit_glue");
- let llfn = {
- match static_glue_fn {
- None => {
- // Select out the glue function to call from the tydesc
- let llfnptr = GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]);
- Load(bcx, llfnptr)
- }
- Some(sgf) => sgf
- }
- };
+ // Select the glue function to call from the tydesc
+ let llfn = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]));
+ let llrawptr = PointerCast(bcx, v, Type::i8p(bcx.ccx()));
Call(bcx, llfn, [llrawptr], []);
}
let td = *llargs.get(0);
let visitor = *llargs.get(1);
let td = PointerCast(bcx, td, ccx.tydesc_type().ptr_to());
- glue::call_visit_glue(bcx, visitor, td, None);
+ glue::call_visit_glue(bcx, visitor, td);
C_nil(ccx)
}
(_, "offset") => {
ByBoxExplicitSelfCategory,
}
+/// Pushes all the lifetimes in the given type onto the given list. A
+/// "lifetime in a type" is a lifetime specified by a reference or a lifetime
+/// in a list of type substitutions. This does *not* traverse into nominal
+/// types, nor does it resolve fictitious types.
+pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
+ typ: t) {
+ walk_ty(typ, |typ| {
+ match get(typ).sty {
+ ty_rptr(region, _) => accumulator.push(region),
+ ty_enum(_, ref substs) |
+ ty_trait(box TyTrait {
+ substs: ref substs,
+ ..
+ }) |
+ ty_struct(_, ref substs) => {
+ match substs.regions {
+ subst::ErasedRegions => {}
+ subst::NonerasedRegions(ref regions) => {
+ for region in regions.iter() {
+ accumulator.push(*region)
+ }
+ }
+ }
+ }
+ ty_closure(ref closure_ty) => {
+ match closure_ty.store {
+ RegionTraitStore(region, _) => accumulator.push(region),
+ UniqTraitStore => {}
+ }
+ }
+ ty_nil |
+ ty_bot |
+ ty_bool |
+ ty_char |
+ ty_int(_) |
+ ty_uint(_) |
+ ty_float(_) |
+ ty_box(_) |
+ ty_uniq(_) |
+ ty_str |
+ ty_vec(_, _) |
+ ty_ptr(_) |
+ ty_bare_fn(_) |
+ ty_tup(_) |
+ ty_param(_) |
+ ty_infer(_) |
+ ty_unboxed_closure(_) |
+ ty_err => {}
+ }
+ })
+}
+
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::ty;
use middle::ty_fold::TypeFolder;
+use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
use middle::typeck::rscope::RegionScope;
use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
use middle::typeck;
match rscope.anon_regions(default_span, 1) {
Err(()) => {
debug!("optional region in illegal location");
- this.tcx().sess.span_err(
- default_span, "missing lifetime specifier");
+ span_err!(this.tcx().sess, default_span, E0106,
+ "missing lifetime specifier");
ty::ReStatic
}
rscope.anon_regions(path.span, expected_num_region_params);
if supplied_num_region_params != 0 || anon_regions.is_err() {
- tcx.sess.span_err(
- path.span,
- format!("wrong number of lifetime parameters: \
- expected {} but found {}",
- expected_num_region_params,
- supplied_num_region_params).as_slice());
+ span_err!(tcx.sess, path.span, E0107,
+ "wrong number of lifetime parameters: expected {} but found {}",
+ expected_num_region_params, supplied_num_region_params);
}
match anon_regions {
if supplied_ty_param_count > required_ty_param_count
&& !this.tcx().sess.features.default_type_params.get() {
- this.tcx().sess.span_err(path.span, "default type parameters are \
- experimental and possibly buggy");
- this.tcx().sess.span_note(path.span, "add #![feature(default_type_params)] \
- to the crate attributes to enable");
+ span_err!(this.tcx().sess, path.span, E0108,
+ "default type parameters are experimental and possibly buggy");
+ span_note!(this.tcx().sess, path.span,
+ "add #![feature(default_type_params)] to the crate attributes to enable");
}
let tps = path.segments.iter().flat_map(|s| s.types.iter())
flags: uint) {
if (flags & NO_TPS) != 0u {
if !path.segments.iter().all(|s| s.types.is_empty()) {
- tcx.sess.span_err(
- path.span,
+ span_err!(tcx.sess, path.span, E0109,
"type parameters are not allowed on this type");
}
}
if (flags & NO_REGIONS) != 0u {
if !path.segments.last().unwrap().lifetimes.is_empty() {
- tcx.sess.span_err(
- path.span,
+ span_err!(tcx.sess, path.span, E0110,
"region parameters are not allowed on this type");
}
}
Some(ty::mk_mach_float(ft))
}
ast::TyStr => {
- tcx.sess.span_err(ast_ty.span,
- "bare `str` is not a type");
+ span_err!(tcx.sess, ast_ty.span, E0037,
+ "bare `str` is not a type");
// return /something/ so they can at least get more errors
Some(ty::mk_uniq(tcx, ty::mk_str(tcx)))
}
.iter()
.flat_map(|s| s.types.iter())
.count() > 1 {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Box` has only one type parameter")
+ span_err!(this.tcx().sess, path.span, E0047,
+ "`Box` has only one type parameter");
}
for inner_ast_type in path.segments
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Box<str>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0111,
+ "`Box<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
- this.tcx()
- .sess
- .span_err(path.span,
+ span_err!(this.tcx().sess, path.span, E0112,
"`Box<[T]>` is not a type");
ty::mk_err()
}
}
}))
}
- this.tcx().sess.span_err(path.span,
- "not enough type parameters \
- supplied to `Box<T>`");
+ span_err!(this.tcx().sess, path.span, E0113,
+ "not enough type parameters supplied to `Box<T>`");
Some(ty::mk_err())
}
def::DefTy(did) | def::DefStruct(did)
.iter()
.flat_map(|s| s.types.iter())
.count() > 1 {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc` has only one type parameter")
+ span_err!(this.tcx().sess, path.span, E0048,
+ "`Gc` has only one type parameter");
}
for inner_ast_type in path.segments
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc<str>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0114,
+ "`Gc<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc<[T]>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0115,
+ "`Gc<[T]>` is not a type");
ty::mk_err()
}
_ => ty::mk_box(this.tcx(), typ),
Option<ty::ExplicitSelfCategory>) {
debug!("ty_of_method_or_bare_fn");
- // new region names that appear inside of the fn decl are bound to
- // that function type
+ // New region names that appear inside of the arguments of the function
+ // declaration are bound to that function type.
let rb = rscope::BindingRscope::new(id);
+ // `implied_output_region` is the region that will be assumed for any
+ // region parameters in the return type. In accordance with the rules for
+ // lifetime elision, we can determine it in two ways. First (determined
+ // here), if self is by-reference, then the implied output region is the
+ // region of the self parameter.
let mut explicit_self_category_result = None;
- let self_ty = opt_self_info.and_then(|self_info| {
- // Figure out and record the explicit self category.
- let explicit_self_category =
- determine_explicit_self_category(this, &rb, &self_info);
- explicit_self_category_result = Some(explicit_self_category);
- match explicit_self_category {
- ty::StaticExplicitSelfCategory => None,
- ty::ByValueExplicitSelfCategory => {
- Some(self_info.untransformed_self_ty)
- }
- ty::ByReferenceExplicitSelfCategory(region, mutability) => {
- Some(ty::mk_rptr(this.tcx(), region,
- ty::mt {ty: self_info.untransformed_self_ty,
- mutbl: mutability}))
- }
- ty::ByBoxExplicitSelfCategory => {
- Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty))
+ let (self_ty, mut implied_output_region) = match opt_self_info {
+ None => (None, None),
+ Some(self_info) => {
+ // Figure out and record the explicit self category.
+ let explicit_self_category =
+ determine_explicit_self_category(this, &rb, &self_info);
+ explicit_self_category_result = Some(explicit_self_category);
+ match explicit_self_category {
+ ty::StaticExplicitSelfCategory => (None, None),
+ ty::ByValueExplicitSelfCategory => {
+ (Some(self_info.untransformed_self_ty), None)
+ }
+ ty::ByReferenceExplicitSelfCategory(region, mutability) => {
+ (Some(ty::mk_rptr(this.tcx(),
+ region,
+ ty::mt {
+ ty: self_info.untransformed_self_ty,
+ mutbl: mutability
+ })),
+ Some(region))
+ }
+ ty::ByBoxExplicitSelfCategory => {
+ (Some(ty::mk_uniq(this.tcx(),
+ self_info.untransformed_self_ty)),
+ None)
+ }
}
}
- });
+ };
// HACK(eddyb) replace the fake self type in the AST with the actual type.
let input_tys = if self_ty.is_some() {
decl.inputs.as_slice()
};
let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None));
+ let self_and_input_tys: Vec<_> =
+ self_ty.move_iter().chain(input_tys).collect();
+
+ // Second, if there was exactly one lifetime (either a substitution or a
+ // reference) in the arguments, then any anonymous regions in the output
+ // have that lifetime.
+ if implied_output_region.is_none() {
+ let mut self_and_input_tys_iter = self_and_input_tys.iter();
+ if self_ty.is_some() {
+ // Skip the first argument if `self` is present.
+ drop(self_and_input_tys_iter.next())
+ }
- let self_and_input_tys = self_ty.move_iter().chain(input_tys).collect();
+ let mut accumulator = Vec::new();
+ for input_type in self_and_input_tys_iter {
+ ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type)
+ }
+ if accumulator.len() == 1 {
+ implied_output_region = Some(*accumulator.get(0));
+ }
+ }
let output_ty = match decl.output.node {
ast::TyInfer => this.ty_infer(decl.output.span),
- _ => ast_ty_to_ty(this, &rb, &*decl.output)
+ _ => {
+ match implied_output_region {
+ Some(implied_output_region) => {
+ let rb = ImpliedSingleRscope {
+ region: implied_output_region,
+ };
+ ast_ty_to_ty(this, &rb, &*decl.output)
+ }
+ None => {
+ // All regions must be explicitly specified in the output
+ // if the lifetime elision rules do not apply. This saves
+ // the user from potentially-confusing errors.
+ let rb = ExplicitRscope;
+ ast_ty_to_ty(this, &rb, &*decl.output)
+ }
+ }
+ }
};
(ty::BareFnTy {
!ty::trait_ref_contains_error(&r_exp_trait_ref)
{
let tcx = vcx.tcx();
- tcx.sess.span_err(span,
- format!("expected {}, but found {} ({})",
- ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
- ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
- ty::type_err_to_str(tcx, err)).as_slice());
+ span_err!(tcx.sess, span, E0095, "expected {}, but found {} ({})",
+ ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
+ ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
+ ty::type_err_to_str(tcx, err));
}
}
}
1 => return Some(found.get(0).clone()),
_ => {
if !is_early {
- vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
+ span_err!(vcx.tcx().sess, span, E0096,
+ "multiple applicable methods in scope");
}
return Some(found.get(0).clone());
}
if !mutability_allowed(mt.mutbl, mutbl) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.tcx()
- .sess
- .span_err(ex.span, "types differ in mutability");
+ span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability");
}
_ => {}
}
(&ty::ty_uniq(ty), _) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.ccx.tcx.sess.span_err(
- ex.span,
- format!("can only cast an boxed pointer \
- to a boxed object, not a {}",
- ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+ span_err!(fcx.ccx.tcx.sess, ex.span, E0098,
+ "can only cast an boxed pointer to a boxed object, not a {}",
+ ty::ty_sort_string(fcx.tcx(), src_ty));
}
_ => {}
}
(&ty::ty_rptr(_, ty::mt{ty, ..}), _) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.ccx.tcx.sess.span_err(
- ex.span,
- format!("can only cast an &-pointer \
- to an &-object, not a {}",
- ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+ span_err!(fcx.ccx.tcx.sess, ex.span, E0099,
+ "can only cast an &-pointer to an &-object, not a {}",
+ ty::ty_sort_string(fcx.tcx(), src_ty));
}
_ => {}
}
Some(&def::DefStruct(_)) => {
}
_ => {
- self.tcx().sess.span_err(
- reason.span(self.tcx()),
- "cannot coerce non-statically resolved bare fn")
+ span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
+ "cannot coerce non-statically resolved bare fn");
}
}
if !self.tcx.sess.has_errors() {
match self.reason {
ResolvingExpr(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this expression: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0101,
+ "cannot determine a type for this expression: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingLocal(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this local variable: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0102,
+ "cannot determine a type for this local variable: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingPattern(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this pattern binding: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0103,
+ "cannot determine a type for this pattern binding: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingUpvar(upvar_id) => {
let span = self.reason.span(self.tcx);
- self.tcx.sess.span_err(
- span,
- format!("cannot resolve lifetime for \
- captured variable `{}`: {}",
- ty::local_var_name_str(
- self.tcx,
- upvar_id.var_id).get().to_string(),
- infer::fixup_err_to_string(e)).as_slice());
+ span_err!(self.tcx.sess, span, E0104,
+ "cannot resolve lifetime for captured variable `{}`: {}",
+ ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
+ infer::fixup_err_to_string(e));
}
ResolvingImplRes(span) => {
- self.tcx
- .sess
- .span_err(span,
- "cannot determine a type for impl \
- supertrait");
+ span_err!(self.tcx.sess, span, E0105,
+ "cannot determine a type for impl supertrait");
}
ResolvingUnboxedClosure(_) => {
if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) {
// This is an error.
let session = &self.cc.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot associate methods with a type outside the \
- crate the type is defined in; define and implement \
- a trait or new type instead");
+ span_err!(session, item.span, E0116,
+ "cannot associate methods with a type outside the \
+ crate the type is defined in; define and implement \
+ a trait or new type instead");
}
}
ItemImpl(_, Some(ref trait_ref), _, _) => {
if trait_def_id.krate != LOCAL_CRATE {
let session = &self.cc.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot provide an extension implementation \
- where both trait and type are not defined in this crate");
+ span_err!(session, item.span, E0117,
+ "cannot provide an extension implementation \
+ where both trait and type are not defined in this crate");
}
}
self_type.ty) {
None => {
let session = &self.crate_context.tcx.sess;
- session.span_err(item.span,
- "no base type found for inherent implementation; \
- implement a trait or new type instead");
+ span_err!(session, item.span, E0118,
+ "no base type found for inherent implementation; \
+ implement a trait or new type instead");
}
Some(_) => {
// Nothing to do.
if self.polytypes_unify(polytype_a.clone(), polytype_b) {
let session = &self.crate_context.tcx.sess;
- session.span_err(
- self.span_of_impl(impl_a),
- format!("conflicting implementations for trait `{}`",
- ty::item_path_str(
- self.crate_context.tcx,
- trait_def_id)).as_slice());
+ span_err!(session, self.span_of_impl(impl_a), E0119,
+ "conflicting implementations for trait `{}`",
+ ty::item_path_str(self.crate_context.tcx, trait_def_id));
if impl_b.krate == LOCAL_CRATE {
- session.span_note(self.span_of_impl(impl_b),
- "note conflicting implementation here");
+ span_note!(session, self.span_of_impl(impl_b),
+ "note conflicting implementation here");
} else {
let crate_store = &self.crate_context.tcx.sess.cstore;
let cdata = crate_store.get_crate_data(impl_b.krate);
- session.note(
- format!("conflicting implementation in crate \
- `{}`",
- cdata.name).as_slice());
+ span_note!(session, self.span_of_impl(impl_a),
+ "conflicting implementation in crate `{}`",
+ cdata.name);
}
}
}
{
match tcx.map.find(impl_did.node) {
Some(ast_map::NodeItem(item)) => {
- tcx.sess.span_err((*item).span,
- "the Drop trait may \
- only be implemented \
- on structures");
+ span_err!(tcx.sess, item.span, E0120,
+ "the Drop trait may only be implemented on structures");
}
_ => {
tcx.sess.bug("didn't find impl in ast \
}
fn ty_infer(&self, span: Span) -> ty::t {
- self.tcx.sess.span_err(span, "the type placeholder `_` is not \
- allowed within types on item \
- signatures.");
+ span_err!(self.tcx.sess, span, E0121,
+ "the type placeholder `_` is not allowed within types on item signatures.");
ty::mk_err()
}
}
thing: &'static str) {
for ty_param in generics.ty_params.iter() {
if ty_param.bounds.len() > 0 {
- ccx.tcx.sess.span_err(
- span,
- format!("trait bounds are not allowed in {} definitions",
- thing).as_slice());
+ span_err!(ccx.tcx.sess, span, E0122,
+ "trait bounds are not allowed in {} definitions", thing);
}
}
}
generics: &ast::Generics) {
if generics.ty_params.len() > 0 &&
!(abi == abi::Rust || abi == abi::RustIntrinsic) {
- ccx.tcx.sess.span_err(span,
- "foreign functions may not use type parameters");
+ span_err!(ccx.tcx.sess, span, E0123,
+ "foreign functions may not use type parameters");
}
}
if result.name != special_idents::unnamed_field.name {
let dup = match seen_fields.find(&result.name) {
Some(prev_span) => {
- tcx.sess.span_err(
- f.span,
- format!("field `{}` is already declared",
- token::get_name(result.name)).as_slice());
- tcx.sess.span_note(*prev_span,
- "previously declared here");
+ span_err!(tcx.sess, f.span, E0124,
+ "field `{}` is already declared",
+ token::get_name(result.name));
+ span_note!(tcx.sess, *prev_span, "previously declared here");
true
},
None => false,
Some(ast_map::NodeItem(i)) => match i.node {
ast::ItemStruct(struct_def, _) => {
if !struct_def.is_virtual {
- tcx.sess.span_err(t.span,
- "struct inheritance is only \
- allowed from virtual structs");
+ span_err!(tcx.sess, t.span, E0126,
+ "struct inheritance is only \
+ allowed from virtual structs");
}
},
_ => {},
{
// This means a trait inherited from the same
// supertrait more than once.
- tcx.sess.span_err(sp, "duplicate supertrait in \
- trait declaration");
+ span_err!(tcx.sess, sp, E0127,
+ "duplicate supertrait in trait declaration");
break;
} else {
ty_trait_refs.push(trait_ref);
ty::walk_ty(ty, |t| {
match ty::get(t).sty {
ty::ty_param(p) => if p.idx > cur_idx {
- ccx.tcx.sess.span_err(
- path.span,
- "type parameters with a default cannot use \
- forward declared identifiers")
+ span_err!(ccx.tcx.sess, path.span, E0128,
+ "type parameters with a default cannot use \
+ forward declared identifiers");
},
_ => {}
}
|trait_ref| {
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
if trait_def.bounds.contains_elem(ty::BoundSized) {
- tcx.sess.span_err(span,
- format!("incompatible bounds on type parameter {}, \
- bound {} does not allow unsized type",
- token::get_ident(ident),
- ppaux::trait_ref_to_string(tcx,
- &*trait_ref)).as_slice());
+ span_err!(tcx.sess, span, E0129,
+ "incompatible bounds on type parameter {}, \
+ bound {} does not allow unsized type",
+ token::get_ident(ident),
+ ppaux::trait_ref_to_string(tcx, &*trait_ref));
}
true
});
match (*i).pat.node {
ast::PatIdent(_, _, _) => (),
ast::PatWild => (),
- _ => ccx.tcx.sess.span_err((*i).pat.span,
- "patterns aren't allowed in foreign function declarations")
+ _ => {
+ span_err!(ccx.tcx.sess, (*i).pat.span, E0130,
+ "patterns aren't allowed in foreign function declarations");
+ }
}
}
match it.node {
ast::ItemFn(_, _, _, ref ps, _)
if ps.is_parameterized() => {
- tcx.sess.span_err(
- main_span,
- "main function is not allowed to have type parameters");
+ span_err!(ccx.tcx.sess, main_span, E0131,
+ "main function is not allowed to have type parameters");
return;
}
_ => ()
match it.node {
ast::ItemFn(_,_,_,ref ps,_)
if ps.is_parameterized() => {
- tcx.sess.span_err(
- start_span,
- "start function is not allowed to have type parameters");
+ span_err!(tcx.sess, start_span, E0132,
+ "start function is not allowed to have type parameters");
return;
}
_ => ()
fn anon_regions(&self,
_: Span,
count: uint)
- -> Result<Vec<ty::Region> , ()> {
+ -> Result<Vec<ty::Region>, ()> {
let idx = self.anon_bindings.get();
self.anon_bindings.set(idx + count);
Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
ty::BrAnon(idx + i))))
}
}
+
+/// A scope in which we generate one specific region. This occurs after the
+/// `->` (i.e. in the return type) of function signatures.
+pub struct ImpliedSingleRscope {
+ pub region: ty::Region,
+}
+
+impl RegionScope for ImpliedSingleRscope {
+ fn anon_regions(&self, _: Span, count: uint)
+ -> Result<Vec<ty::Region>,()> {
+ Ok(Vec::from_elem(count, self.region.clone()))
+ }
+}
+
//! one that doesn't; the one that doesn't might get decent parallel
//! build speedups.
-#![crate_id = "rustc_back#0.11.0-pre"]
#![crate_name = "rustc_back"]
#![experimental]
#![comment = "The Rust compiler minimal-dependency dumping-ground"]
html_root_url = "http://doc.rust-lang.org/")]
#![feature(globs, phase, macro_rules)]
-#![allow(unused_attribute)] // NOTE: remove after stage0
#[phase(plugin, link)]
extern crate log;
#![allow(non_snake_case_functions)]
#![allow(dead_code)]
-#![crate_id = "rustc_llvm#0.11.0"]
#![crate_name = "rustc_llvm"]
#![experimental]
#![license = "MIT/ASL2"]
#![feature(globs)]
#![feature(link_args)]
-#![allow(unused_attribute)] // NOTE: remove after stage0
extern crate libc;
type TLSValue = Box<LocalData + Send>;
// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map() -> Option<&mut Map> {
+unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
if !Local::exists(None::<Task>) { return None }
let task: *mut Task = Local::unsafe_borrow();
impl<'a> LocalIo<'a> {
/// Returns the local I/O: either the local scheduler's I/O services or
/// the native I/O services.
- pub fn borrow() -> Option<LocalIo> {
+ pub fn borrow() -> Option<LocalIo<'a>> {
// FIXME(#11053): bad
//
// This is currently very unsafely implemented. We don't actually
use super::super::Loop;
use super::super::local_loop;
- fn l() -> &mut Loop { &mut local_loop().loop_ }
+ fn l() -> &'static mut Loop { &mut local_loop().loop_ }
#[test]
fn file_test_full_simple_sync() {
}
}
#[test]
+ #[ignore] // FIXME(#15763)
fn test_decode_errors_struct() {
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
/// println!("{}", *book);
/// }
/// ```
+///
+/// The easiest way to use `HashSet` with a custom type is to derive
+/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the
+/// future be implied by `Eq`.
+///
+/// ```rust
+/// use std::collections::HashSet;
+///
+/// #[deriving(Hash, Eq, PartialEq, Show)]
+/// struct Viking<'a> {
+/// name: &'a str,
+/// power: uint,
+/// }
+///
+/// let mut vikings = HashSet::new();
+///
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Olaf", power: 4u });
+/// vikings.insert(Viking { name: "Harald", power: 8u });
+///
+/// // Use derived implementation to print the vikings.
+/// for x in vikings.iter() {
+/// println!("{}", x);
+/// }
+/// ```
#[deriving(Clone)]
pub struct HashSet<T, H = RandomSipHasher> {
map: HashMap<T, (), H>
}
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
- fn eq(&self, other: &HashSet<T, H>) -> bool {
- if self.len() != other.len() { return false; }
-
- self.iter().all(|key| other.contains(key))
- }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
- fn len(&self) -> uint { self.map.len() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
- fn clear(&mut self) { self.map.clear() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
- fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
-
- fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
- self.iter().all(|v| !other.contains(v))
- }
-
- fn is_subset(&self, other: &HashSet<T, H>) -> bool {
- self.iter().all(|v| other.contains(v))
- }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
- fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
-
- fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
-}
-
impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
- /// Create an empty HashSet
+ /// Create an empty HashSet.
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// ```
#[inline]
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::with_capacity(10);
/// ```
#[inline]
/// keys.
///
/// The hash set is also created with the default initial capacity.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::sip::SipHasher;
+ ///
+ /// let h = SipHasher::new();
+ /// let mut set = HashSet::with_hasher(h);
+ /// set.insert(2u);
+ /// ```
#[inline]
pub fn with_hasher(hasher: H) -> HashSet<T, H> {
HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher)
/// is designed to allow `HashSet`s to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::sip::SipHasher;
+ ///
+ /// let h = SipHasher::new();
+ /// let mut set = HashSet::with_capacity_and_hasher(10u, h);
+ /// set.insert(1i);
+ /// ```
#[inline]
pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet<T, H> {
HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// set.reserve(10);
/// ```
/// Returns true if the hash set contains a value equivalent to the
/// given query value.
+ ///
+ /// # Example
+ ///
+ /// This is a slightly silly example where we define the number's
+ /// parity as the equivilance class. It is important that the
+ /// values hash the same, which is why we implement `Hash`.
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::Hash;
+ /// use std::hash::sip::SipState;
+ ///
+ /// #[deriving(Eq, PartialEq)]
+ /// struct EvenOrOdd {
+ /// num: uint
+ /// };
+ ///
+ /// impl Hash for EvenOrOdd {
+ /// fn hash(&self, state: &mut SipState) {
+ /// let parity = self.num % 2;
+ /// parity.hash(state);
+ /// }
+ /// }
+ ///
+ /// impl Equiv<EvenOrOdd> for EvenOrOdd {
+ /// fn equiv(&self, other: &EvenOrOdd) -> bool {
+ /// self.num % 2 == other.num % 2
+ /// }
+ /// }
+ ///
+ /// let mut set = HashSet::new();
+ /// set.insert(EvenOrOdd { num: 3u });
+ ///
+ /// assert!(set.contains_equiv(&EvenOrOdd { num: 3u }));
+ /// assert!(set.contains_equiv(&EvenOrOdd { num: 5u }));
+ /// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u }));
+ /// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u }));
+ ///
+ /// ```
pub fn contains_equiv<Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool {
self.map.contains_key_equiv(value)
}
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let mut set = HashSet::new();
/// set.insert("a");
/// set.insert("b");
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let mut set = HashSet::new();
/// set.insert("a".to_string());
/// set.insert("b".to_string());
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
}
}
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
+ fn eq(&self, other: &HashSet<T, H>) -> bool {
+ if self.len() != other.len() { return false; }
+
+ self.iter().all(|key| other.contains(key))
+ }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
+ fn len(&self) -> uint { self.map.len() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
+ fn clear(&mut self) { self.map.clear() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
+ fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
+
+ fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
+ self.iter().all(|v| !other.contains(v))
+ }
+
+ fn is_subset(&self, other: &HashSet<T, H>) -> bool {
+ self.iter().all(|v| other.contains(v))
+ }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
+ fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
+
+ fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
+}
+
+
impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
}
}
-/// Generate a random value using the task-local random number
-/// generator.
+/// Generates a random value using the task-local random number generator.
///
-/// # Example
+/// `random()` can generate various types of random things, and so may require
+/// type hinting to generate the specific type you want.
+///
+/// # Examples
///
/// ```rust
-/// use std::rand::random;
+/// use std::rand;
+///
+/// let x = rand::random();
+/// println!("{}", 2u * x);
+///
+/// let y = rand::random::<f64>();
+/// println!("{}", y);
///
-/// if random() {
-/// let x = random();
-/// println!("{}", 2u * x);
-/// } else {
-/// println!("{}", random::<f64>());
+/// if rand::random() { // generates a boolean
+/// println!("Better lucky than good!");
/// }
/// ```
#[inline]
//! # }
//! ```
-#![experimental]
+#![stable]
use any::Any;
use comm::channel;
use rt::task;
use rt::task::Task;
use str::{Str, SendStr, IntoMaybeOwned};
+use string::String;
use sync::Future;
+use to_str::ToString;
/// A means of spawning a task
pub trait Spawner {
impl<S: Spawner> TaskBuilder<S> {
/// Name the task-to-be. Currently the name is used for identification
/// only in failure messages.
+ #[unstable = "IntoMaybeOwned will probably change."]
pub fn named<T: IntoMaybeOwned<'static>>(mut self, name: T) -> TaskBuilder<S> {
self.name = Some(name.into_maybe_owned());
self
}
/// Redirect task-local stdout.
+ #[experimental = "May not want to make stdio overridable here."]
pub fn stdout(mut self, stdout: Box<Writer + Send>) -> TaskBuilder<S> {
self.stdout = Some(stdout);
self
}
/// Redirect task-local stderr.
+ #[experimental = "May not want to make stdio overridable here."]
pub fn stderr(mut self, stderr: Box<Writer + Send>) -> TaskBuilder<S> {
self.stderr = Some(stderr);
self
/// future returns `result::Ok` containing the value returned by the
/// function. If the child task fails then the future returns `result::Err`
/// containing the argument to `fail!(...)` 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>>> {
// currently, the on_exit proc provided by librustrt only works for unit
/// Execute a function in a newly-spawnedtask and block until the task
/// completes or fails. Equivalent to `.try_future(f).unwrap()`.
+ #[unstable = "Error type may change."]
pub fn try<T:Send>(self, f: proc():Send -> T) -> Result<T, Box<Any + Send>> {
self.try_future(f).unwrap()
}
/// value of the function or an error if the task failed.
///
/// This is equivalent to `TaskBuilder::new().try`.
+#[unstable = "Error type may change."]
pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> {
TaskBuilder::new().try(f)
}
/// task's result.
///
/// This is equivalent to `TaskBuilder::new().try_future`.
+#[experimental = "Futures are experimental."]
pub fn try_future<T:Send>(f: proc():Send -> T) -> Future<Result<T, Box<Any + Send>>> {
TaskBuilder::new().try_future(f)
}
/* Lifecycle functions */
/// Read the name of the current task.
+#[deprecated = "Use `task::name()`."]
pub fn with_task_name<U>(blk: |Option<&str>| -> U) -> U {
use rt::task::Task;
}
}
+/// Read the name of the current task.
+#[stable]
+pub fn name() -> Option<String> {
+ use rt::task::Task;
+
+ let task = Local::borrow(None::<Task>);
+ match task.name {
+ Some(ref name) => Some(name.as_slice().to_string()),
+ None => None
+ }
+}
+
/// Yield control to the task scheduler.
+#[unstable = "Name will change."]
pub fn deschedule() {
use rt::local::Local;
/// True if the running task is currently failing (e.g. will return `true` inside a
/// destructor that is run while unwinding the stack after a call to `fail!()`).
+#[unstable = "May move to a different module."]
pub fn failing() -> bool {
use rt::task::Task;
Local::borrow(None::<Task>).unwinder.unwinding()
use boxed::BoxAny;
use result;
use result::{Ok, Err};
- use str::StrAllocating;
use string::String;
use std::io::{ChanReader, ChanWriter};
use prelude::*;
#[test]
fn test_unnamed_task() {
- spawn(proc() {
- with_task_name(|name| {
- assert!(name.is_none());
- })
- })
+ try(proc() {
+ assert!(name().is_none());
+ }).map_err(|_| ()).unwrap();
}
#[test]
fn test_owned_named_task() {
- TaskBuilder::new().named("ada lovelace".to_string()).spawn(proc() {
- with_task_name(|name| {
- assert!(name.unwrap() == "ada lovelace");
- })
- })
+ TaskBuilder::new().named("ada lovelace".to_string()).try(proc() {
+ assert!(name().unwrap() == "ada lovelace".to_string());
+ }).map_err(|_| ()).unwrap();
}
#[test]
fn test_static_named_task() {
- TaskBuilder::new().named("ada lovelace").spawn(proc() {
- with_task_name(|name| {
- assert!(name.unwrap() == "ada lovelace");
- })
- })
+ TaskBuilder::new().named("ada lovelace").try(proc() {
+ assert!(name().unwrap() == "ada lovelace".to_string());
+ }).map_err(|_| ()).unwrap();
}
#[test]
fn test_send_named_task() {
- TaskBuilder::new().named("ada lovelace".into_maybe_owned()).spawn(proc() {
- with_task_name(|name| {
- assert!(name.unwrap() == "ada lovelace");
- })
- })
+ TaskBuilder::new().named("ada lovelace".into_maybe_owned()).try(proc() {
+ assert!(name().unwrap() == "ada lovelace".to_string());
+ }).map_err(|_| ()).unwrap();
}
#[test]
});
assert_eq!(rx.recv(), 1);
} #[ignore(reason = "flaky on libnative")])
+
+ test!(fn issue_15761() {
+ fn repro() {
+ let (tx1, rx1) = sync_channel::<()>(3);
+ let (tx2, rx2) = sync_channel::<()>(3);
+
+ spawn(proc() {
+ rx1.recv();
+ tx2.try_send(()).unwrap();
+ });
+
+ tx1.try_send(()).unwrap();
+ rx2.recv();
+ }
+
+ for _ in range(0u, 100) {
+ repro()
+ }
+ })
}
}
} else {
// If the buffer has some space and the capacity isn't 0, then we
- // just enqueue the data for later retrieval.
+ // just enqueue the data for later retrieval, ensuring to wake up
+ // any blocked receiver if there is one.
assert!(state.buf.size() < state.buf.cap());
state.buf.enqueue(t);
+ match mem::replace(&mut state.blocker, NoneBlocked) {
+ BlockedReceiver(task) => wakeup(task, guard),
+ NoneBlocked => {}
+ BlockedSender(..) => unreachable!(),
+ }
Ok(())
}
}
fn pe_vis(&self) -> ast::Visibility;
}
-
-/// can't use the standard cfg(stage0) tricks here, because the error occurs in
-/// parsing, before cfg gets a chance to save the day. (yes, interleaved parsing
-/// / expansion / configuring would solve this problem...)
-
-// NOTE: remove after next snapshot
-/// to be more specific: after a snapshot, swap out the "PRE" stuff, and
-// swap in the "POST" stuff.
-
-/// PRE
-macro_rules! mf_method_body{
- ($slf:ident, $field_pat:pat, $result:ident) => {
- match $slf.node {
- $field_pat => $result,
- MethMac(_) => {
- fail!("expected an AST without macro invocations");
- }
- }
- }
-}
-
-/// POST
-/*
-#[cfg(not(stage0))]
macro_rules! mf_method{
($meth_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => {
fn $meth_name<'a>(&'a self) -> $field_ty {
}
}
}
-}*/
-
-
-// PRE
-impl PostExpansionMethod for Method {
- fn pe_ident(&self) -> ast::Ident {
- mf_method_body!(self, MethDecl(ident,_,_,_,_,_,_,_),ident)
- }
- fn pe_generics<'a>(&'a self) -> &'a ast::Generics {
- mf_method_body!(self, MethDecl(_,ref generics,_,_,_,_,_,_),generics)
- }
- fn pe_abi(&self) -> Abi {
- mf_method_body!(self, MethDecl(_,_,abi,_,_,_,_,_),abi)
- }
- fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf {
- mf_method_body!(self, MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self)
- }
- fn pe_fn_style(&self) -> ast::FnStyle{
- mf_method_body!(self, MethDecl(_,_,_,_,fn_style,_,_,_),fn_style)
- }
- fn pe_fn_decl(&self) -> P<ast::FnDecl> {
- mf_method_body!(self, MethDecl(_,_,_,_,_,decl,_,_),decl)
- }
- fn pe_body(&self) -> P<ast::Block> {
- mf_method_body!(self, MethDecl(_,_,_,_,_,_,body,_),body)
- }
- fn pe_vis(&self) -> ast::Visibility {
- mf_method_body!(self, MethDecl(_,_,_,_,_,_,_,vis),vis)
- }
}
-// POST
-/*
-#[cfg(not(stage0))]
+
impl PostExpansionMethod for Method {
- mf_method!(pe_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_),ident)
+ mf_method!(pe_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_,_),ident)
mf_method!(pe_generics,&'a ast::Generics,
- MethDecl(_,ref generics,_,_,_,_,_),generics)
+ MethDecl(_,ref generics,_,_,_,_,_,_),generics)
+ mf_method!(pe_abi,Abi,MethDecl(_,_,abi,_,_,_,_,_),abi)
mf_method!(pe_explicit_self,&'a ast::ExplicitSelf,
- MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self)
- mf_method!(pe_fn_style,ast::FnStyle,MethDecl(_,_,_,fn_style,_,_,_),fn_style)
- mf_method!(pe_fn_decl,P<ast::FnDecl>,MethDecl(_,_,_,_,decl,_,_),decl)
- mf_method!(pe_body,P<ast::Block>,MethDecl(_,_,_,_,_,body,_),body)
- mf_method!(pe_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,vis),vis)
+ MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self)
+ mf_method!(pe_fn_style,ast::FnStyle,MethDecl(_,_,_,_,fn_style,_,_,_),fn_style)
+ mf_method!(pe_fn_decl,P<ast::FnDecl>,MethDecl(_,_,_,_,_,decl,_,_),decl)
+ mf_method!(pe_body,P<ast::Block>,MethDecl(_,_,_,_,_,_,body,_),body)
+ mf_method!(pe_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,_,vis),vis)
}
-*/
#[cfg(test)]
mod test {
#![macro_escape]
-// NOTE: remove after next snapshot
-#[cfg(stage0)]
-#[macro_export]
-macro_rules! __register_diagnostic(
- ($code:tt, $description:tt) => ();
- ($code:tt) => ()
-)
-
#[macro_export]
macro_rules! register_diagnostic(
($code:tt, $description:tt) => (__register_diagnostic!($code, $description));
($code:tt) => (__register_diagnostic!($code))
)
-// NOTE: remove after next snapshot
-#[cfg(stage0)]
-#[macro_export]
-macro_rules! __build_diagnostic_array(
- ($name:ident) => {
- pub static $name: [(&'static str, &'static str), ..0] = [];
- }
-)
-
-// NOTE: remove after next snapshot
-#[cfg(stage0)]
-#[macro_export]
-macro_rules! __diagnostic_used(
- ($code:ident) => {
- ()
- }
-)
-
#[macro_export]
macro_rules! span_err(
- ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+ ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+ $session.span_err_with_code($span, format!($($message)*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_warn(
- ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+ ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- ($session).span_warn_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+ $session.span_warn_with_code($span, format!($($message)*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_note(
- ($session:expr, $span:expr, $($arg:expr),*) => ({
- ($session).span_note($span, format!($($arg),*).as_slice())
+ ($session:expr, $span:expr, $($message:tt)*) => ({
+ ($session).span_note($span, format!($($message)*).as_slice())
})
)
use std::gc::Gc;
/// The types of pointers
+#[deriving(Clone)]
pub enum PtrTy<'a> {
/// &'lifetime mut
Borrowed(Option<&'a str>, ast::Mutability),
/// A path, e.g. `::std::option::Option::<int>` (global). Has support
/// for type parameters and a lifetime.
+#[deriving(Clone)]
pub struct Path<'a> {
pub path: Vec<&'a str> ,
pub lifetime: Option<&'a str>,
}
/// A type. Supports pointers (except for *), Self, and literals
+#[deriving(Clone)]
pub enum Ty<'a> {
Self,
/// &/Box/ Ty
borrowed(box Self)
}
-pub fn nil_ty() -> Ty<'static> {
+pub fn nil_ty<'r>() -> Ty<'r> {
Tuple(Vec::new())
}
}
/// Lifetimes and bounds on type parameters
+#[deriving(Clone)]
pub struct LifetimeBounds<'a> {
pub lifetimes: Vec<&'a str>,
pub bounds: Vec<(&'a str, Option<ast::TyParamBound>, Vec<Path<'a>>)>,
}
impl<'a> LifetimeBounds<'a> {
- pub fn empty() -> LifetimeBounds<'static> {
+ pub fn empty() -> LifetimeBounds<'a> {
LifetimeBounds {
lifetimes: Vec::new(), bounds: Vec::new()
}
}
}
+ fn describe_num_args(&self) -> String {
+ match self.args.len() {
+ 0 => "no arguments given".to_string(),
+ 1 => "there is 1 argument".to_string(),
+ x => format!("there are {} arguments", x),
+ }
+ }
+
fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
match arg {
Exact(arg) => {
if self.args.len() <= arg {
- let msg = format!("invalid reference to argument `{}` (there \
- are {} arguments)", arg, self.args.len());
+ let msg = format!("invalid reference to argument `{}` ({:s})",
+ arg, self.describe_num_args());
+
self.ecx.span_err(self.fmtsp, msg.as_slice());
return;
}
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
-#![allow(unused_attribute)] // NOTE: remove after stage0
extern crate core;
+S 2014-07-17 9fc8394
+ freebsd-x86_64 5a4b645e2b42ae06224cc679d4a43b3d89be1482
+ linux-i386 a5e1bb723020ac35173d49600e76b0935e257a6a
+ linux-x86_64 1a2407df17442d93d1c34c916269a345658045d7
+ macos-i386 6648fa88e41ad7c0991a085366e36d56005873ca
+ macos-x86_64 71b2d1dfd0abe1052908dc091e098ed22cf272c6
+ winnt-i386 c26f0a713c5fadf99cce935f60dce0ea403fb411
+
S 2014-07-09 8ddd286
freebsd-x86_64 de0c39057f409b69e5ddb888ba3e20b90d63f5db
linux-i386 28bef31f2a017e1998256d0c2b2e0a0c9221451b
}
trait Helper<T> {
- fn helper_borrow<'a>(&'a self) -> &'a T;
+ fn helper_borrow(&self) -> &T;
}
impl<T> Helper<T> for Option<T> {
- fn helper_borrow<'a>(&'a self) -> &'a T {
+ fn helper_borrow(&self) -> &T {
self.as_ref().unwrap()
}
}
impl<T, H: Helper<T>> Deref<T> for DerefWithHelper<H, T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
self.helper.helper_borrow()
}
}
}
}
- fn iter<'a>(&'a self) -> Items<'a> {
+ fn iter(&self) -> Items {
Items { cur: None, items: self.items.iter() }
}
}
struct Foo(int);
-fn foo() -> &int {
+fn foo<'a>() -> &'a int {
let &Foo(ref x) = &Foo(3); //~ ERROR borrowed value does not live long enough
x
}
// other `&mut` pointers.
trait Foo {
- fn f1<'a>(&'a mut self) -> &'a ();
+ fn f1(&mut self) -> &();
fn f2(&mut self);
}
}
impl<T> Deref<T> for Own<T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
unsafe { &*self.value }
}
}
impl<T> DerefMut<T> for Own<T> {
- fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+ fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.value }
}
}
self.y = y;
}
- fn x_ref<'a>(&'a self) -> &'a int {
+ fn x_ref(&self) -> &int {
&self.x
}
- fn y_mut<'a>(&'a mut self) -> &'a mut int {
+ fn y_mut(&mut self) -> &mut int {
&mut self.y
}
}
let _i = &mut x.y;
}
-fn deref_extend_field<'a>(x: &'a Own<Point>) -> &'a int {
+fn deref_extend_field(x: &Own<Point>) -> &int {
&x.y
}
-fn deref_extend_mut_field1<'a>(x: &'a Own<Point>) -> &'a mut int {
+fn deref_extend_mut_field1(x: &Own<Point>) -> &mut int {
&mut x.y //~ ERROR cannot borrow
}
-fn deref_extend_mut_field2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
+fn deref_extend_mut_field2(x: &mut Own<Point>) -> &mut int {
&mut x.y
}
-fn deref_extend_mut_field3<'a>(x: &'a mut Own<Point>) {
+fn deref_extend_mut_field3(x: &mut Own<Point>) {
// Hmm, this is unfortunate, because with box it would work,
// but it's presently the expected outcome. See `deref_extend_mut_field4`
// for the workaround.
x.set(0, 0);
}
-fn deref_extend_method<'a>(x: &'a Own<Point>) -> &'a int {
+fn deref_extend_method(x: &Own<Point>) -> &int {
x.x_ref()
}
-fn deref_extend_mut_method1<'a>(x: &'a Own<Point>) -> &'a mut int {
+fn deref_extend_mut_method1(x: &Own<Point>) -> &mut int {
x.y_mut() //~ ERROR cannot borrow
}
-fn deref_extend_mut_method2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
+fn deref_extend_mut_method2(x: &mut Own<Point>) -> &mut int {
x.y_mut()
}
}
impl<T> Deref<T> for Rc<T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
unsafe { &*self.value }
}
}
self.y = y;
}
- fn x_ref<'a>(&'a self) -> &'a int {
+ fn x_ref(&self) -> &int {
&self.x
}
- fn y_mut<'a>(&'a mut self) -> &'a mut int {
+ fn y_mut(&mut self) -> &mut int {
&mut self.y
}
}
let _i = &mut x.y; //~ ERROR cannot borrow
}
-fn deref_extend_field<'a>(x: &'a Rc<Point>) -> &'a int {
+fn deref_extend_field(x: &Rc<Point>) -> &int {
&x.y
}
-fn deref_extend_mut_field1<'a>(x: &'a Rc<Point>) -> &'a mut int {
+fn deref_extend_mut_field1(x: &Rc<Point>) -> &mut int {
&mut x.y //~ ERROR cannot borrow
}
-fn deref_extend_mut_field2<'a>(x: &'a mut Rc<Point>) -> &'a mut int {
+fn deref_extend_mut_field2(x: &mut Rc<Point>) -> &mut int {
&mut x.y //~ ERROR cannot borrow
}
x.set(0, 0); //~ ERROR cannot borrow
}
-fn deref_extend_method<'a>(x: &'a Rc<Point>) -> &'a int {
+fn deref_extend_method(x: &Rc<Point>) -> &int {
x.x_ref()
}
-fn deref_extend_mut_method1<'a>(x: &'a Rc<Point>) -> &'a mut int {
+fn deref_extend_mut_method1(x: &Rc<Point>) -> &mut int {
x.y_mut() //~ ERROR cannot borrow
}
-fn deref_extend_mut_method2<'a>(x: &'a mut Rc<Point>) -> &'a mut int {
+fn deref_extend_mut_method2(x: &mut Rc<Point>) -> &mut int {
x.y_mut() //~ ERROR cannot borrow
}
use std::gc::{GC, Gc};
-fn foo<'a>(x: &'a Gc<int>) -> &'a int {
+fn foo(x: &Gc<int>) -> &int {
match x {
&ref y => {
&**y // Do not expect an error here
trait Foo {
- fn borrowed<'a>(&'a self) -> &'a ();
+ fn borrowed(&self) -> &();
}
-fn borrowed_receiver<'a>(x: &'a Foo) -> &'a () {
+fn borrowed_receiver(x: &Foo) -> &() {
x.borrowed()
}
-fn owned_receiver(x: Box<Foo>) -> &() {
+fn owned_receiver(x: Box<Foo>) -> &'static () {
x.borrowed() //~ ERROR `*x` does not live long enough
}
}
impl<T> Index<uint, T> for MyVec<T> {
- fn index<'a>(&'a self, &i: &uint) -> &'a T {
+ fn index(&self, &i: &uint) -> &T {
self.data.get(i)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn a() -> &[int] {
+fn a<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let tail = match vec {
tail
}
-fn b() -> &[int] {
+fn b<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let init = match vec {
init
}
-fn c() -> &[int] {
+fn c<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let slice = match vec {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn a() -> &int {
+fn a<'a>() -> &'a int {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR `vec` does not live long enough
let tail = match vec {
AddFlags { bits: bits }
}
-fn arg<'a>(x: &'a AddFlags) -> &'a AddFlags {
+fn arg(x: &AddFlags) -> &AddFlags {
x
}
impl AddFlags {
- fn get<'a>(&'a self) -> &'a AddFlags {
+ fn get(&self) -> &AddFlags {
self
}
}
--- /dev/null
+// 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.
+
+// compile-flags: --crate-name foo
+
+#![crate_name = "bar"]
+//~^ ERROR: --crate-name and #[crate_name] are required to match, but `foo` != `bar`
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn read_lines_borrowed() -> Vec<&str> {
+fn read_lines_borrowed<'a>() -> Vec<&'a str> {
let raw_lines: Vec<String> = vec!("foo ".to_string(), " bar".to_string());
raw_lines.iter().map(|l| l.as_slice().trim()).collect()
//~^ ERROR `raw_lines` does not live long enough
format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
+ // bad number of arguments, see #15780
+
+ format!("{0}");
+ //~^ ERROR invalid reference to argument `0` (no arguments given)
+
+ format!("{0} {1}", 1);
+ //~^ ERROR invalid reference to argument `1` (there is 1 argument)
+
+ format!("{0} {1} {2}", 1, 2);
+ //~^ ERROR invalid reference to argument `2` (there are 2 arguments)
+
+ format!("{0} {1}");
+ //~^ ERROR invalid reference to argument `0` (no arguments given)
+ //~^^ ERROR invalid reference to argument `1` (no arguments given)
+
// bad syntax of the format string
format!("{"); //~ ERROR: expected `}` but string was terminated
struct Foo;
impl Deref<Foo> for Foo {
- fn deref<'a>(&'a self) -> &'a Foo {
+ fn deref(&self) -> &Foo {
self
}
}
fn drop (&mut self) {}
}
-fn createTest() -> &Test {
+fn createTest<'a>() -> &'a Test {
let testValue = &Test; //~ ERROR borrowed value does not live long enough
return testValue;
}
x: &'a Q
}
-fn thing<Q>(x: &Q) -> thing<Q> {
+fn thing<'a,Q>(x: &Q) -> thing<'a,Q> {
thing{ x: x } //~ ERROR cannot infer
}
A(Box<MyTrait>),
}
-fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
+fn get_tw_map(tw: &TraitWrapper) -> &MyTrait {
match *tw {
A(box ref map) => map, //~ ERROR cannot be dereferenced
}
A { p: p }
}
-fn make_make_a() -> A {
+fn make_make_a<'a>() -> A<'a> {
let b: Box<B> = box B {i:1};
let bb: &B = &*b; //~ ERROR does not live long enough
make_a(bb)
--- /dev/null
+// 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.
+
+// Lifetime annotation needed because we have no arguments.
+fn f() -> &int { //~ ERROR missing lifetime specifier
+ fail!()
+}
+
+// Lifetime annotation needed because we have two by-reference parameters.
+fn g(_: &int, _: &int) -> &int { //~ ERROR missing lifetime specifier
+ fail!()
+}
+
+struct Foo<'a> {
+ x: &'a int,
+}
+
+// Lifetime annotation needed because we have two lifetimes: one as a parameter
+// and one on the reference.
+fn h(_: &Foo) -> &int { //~ ERROR missing lifetime specifier
+ fail!()
+}
+
+fn main() {}
+
// ignore-tidy-linelength
struct Foo<'x> { bar: int }
-fn foo1(x: &Foo) -> &int {
+fn foo1<'a>(x: &Foo) -> &'a int {
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo1<'a>(x: &'a Foo) -> &'a int
&x.bar //~ ERROR: cannot infer
}
&x.bar //~ ERROR: cannot infer
}
-fn foo3(x: &Foo) -> (&int, &int) {
+fn foo3<'a>(x: &Foo) -> (&'a int, &'a int) {
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo3<'a>(x: &'a Foo) -> (&'a int, &'a int)
(&x.bar, &x.bar) //~ ERROR: cannot infer
//~^ ERROR: cannot infer
}
-fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &int) {
+fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) {
//~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo4<'a>(x: &'a Foo) -> (&'a int, &'a int, &'a int)
(&x.bar, &x.bar, &x.bar) //~ ERROR: cannot infer
//~^ ERROR: cannot infer
}
-fn foo5(x: &int) -> &int {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo5<'a>(x: &'a int) -> &'a int
- x //~ ERROR: mismatched types
- //~^ ERROR: cannot infer
-}
-
struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int }
-fn bar1(x: &Bar) -> (&int, &int, &int) {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'a, 'b, 'c, 'd>(x: &'d Bar<'b, 'a, 'c>) -> (&'a int, &'d int, &'d int)
+fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) {
+//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int)
(x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types
//~^ ERROR: cannot infer
//~^^ ERROR: cannot infer
}
-fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&int, &int, &int) {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'d, 'a, 'b, 'c>(x: &'d Bar<'a, 'b, 'c>) -> (&'b int, &'d int, &'d int)
+fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) {
+//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int)
(x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types
//~^ ERROR: cannot infer
//~^^ ERROR: cannot infer
struct Cat<'x, T> { cat: &'x int, t: T }
struct Dog<'y> { dog: &'y int }
-fn cat<'x>(x: Cat<'x, Dog>) -> &int {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat<'a, 'x>(x: Cat<'x, Dog<'a>>) -> &'a int
- x.t.dog //~ ERROR: mismatched types
-}
-fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &int {
-//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'y int
+fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x int {
+//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x int
x.t.dog //~ ERROR: mismatched types
}
bar: &'x int
}
-impl<'x> Baz<'x> {
- fn baz1(&self) -> &int {
- //~^ NOTE: consider using an explicit lifetime parameter as shown: fn baz1(&self) -> &'x int
- self.bar //~ ERROR: mismatched types
- }
-}
impl<'a> Baz<'a> {
- fn baz2(&self, x: &int) -> (&int, &int) {
- //~^ NOTE: consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'b int) -> (&'a int, &'b int)
+ fn baz2<'b>(&self, x: &int) -> (&'b int, &'b int) {
+ // The lifetime that gets assigned to `x` seems somewhat random.
+ // I have disabled this test for the time being. --pcwalton
(self.bar, x) //~ ERROR: cannot infer
//~^ ERROR: mismatched types
//~^^ ERROR: mismatched types
--- /dev/null
+// 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.
+
+struct NewBool(bool);
+
+enum Direction {
+ North,
+ East,
+ South,
+ West
+}
+
+static TRUE_TRUE: (bool, bool) = (true, true);
+
+fn nonexhaustive_1() {
+ match (true, false) {
+ //~^ ERROR non-exhaustive patterns: `(true, false)` not covered
+ TRUE_TRUE => (),
+ (false, false) => (),
+ (false, true) => ()
+ }
+}
+
+fn unreachable_1() {
+ match (true, false) {
+ TRUE_TRUE => (),
+ (false, false) => (),
+ (false, true) => (),
+ (true, false) => (),
+ (true, true) => ()
+ //~^ ERROR unreachable pattern
+ }
+}
+
+static NONE: Option<Direction> = None;
+static EAST: Direction = East;
+
+fn nonexhaustive_2() {
+ match Some(Some(North)) {
+ //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
+ Some(NONE) => (),
+ Some(Some(North)) => (),
+ Some(Some(EAST)) => (),
+ Some(Some(South)) => (),
+ None => ()
+ }
+}
+
+fn unreachable_2() {
+ match Some(Some(North)) {
+ Some(NONE) => (),
+ Some(Some(North)) => (),
+ Some(Some(EAST)) => (),
+ Some(Some(South)) => (),
+ Some(Some(West)) => (),
+ Some(Some(East)) => (),
+ //~^ ERROR unreachable pattern
+ None => ()
+ }
+}
+
+static NEW_FALSE: NewBool = NewBool(false);
+struct Foo {
+ bar: Option<Direction>,
+ baz: NewBool
+}
+
+static STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
+
+fn nonexhaustive_3() {
+ match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
+ Foo { bar: None, baz: NewBool(true) } => (),
+ Foo { bar: _, baz: NEW_FALSE } => (),
+ Foo { bar: Some(West), baz: NewBool(true) } => (),
+ Foo { bar: Some(South), .. } => (),
+ Foo { bar: Some(EAST), .. } => ()
+ }
+}
+
+fn unreachable_3() {
+ match (Foo { bar: Some(EAST), baz: NewBool(true) }) {
+ Foo { bar: None, baz: NewBool(true) } => (),
+ Foo { bar: _, baz: NEW_FALSE } => (),
+ Foo { bar: Some(West), baz: NewBool(true) } => (),
+ Foo { bar: Some(South), .. } => (),
+ Foo { bar: Some(EAST), .. } => (),
+ Foo { bar: Some(North), baz: NewBool(true) } => (),
+ Foo { bar: Some(EAST), baz: NewBool(false) } => ()
+ //~^ ERROR unreachable pattern
+ }
+}
+
+fn main() {
+ nonexhaustive_1();
+ nonexhaustive_2();
+ nonexhaustive_3();
+ unreachable_1();
+ unreachable_2();
+ unreachable_3();
+}
}
#[main]
-fn foo() { //~ ERROR multiple 'main' functions
+fn foo() { //~ ERROR multiple functions with a #[main] attribute
}
mod foo {
#[main]
- fn main2() { //~ ERROR multiple 'main' functions
+ fn main2() { //~ ERROR multiple functions with a #[main] attribute
}
}
}
}
-fn map_nums(x: &ast, f: |uint| -> uint) -> &ast {
+fn map_nums<'a,'b>(x: &ast, f: |uint| -> uint) -> &'a ast<'b> {
match *x {
num(x) => {
return &num(f(x)); //~ ERROR borrowed value does not live long enough
add(&'a ast<'a>, &'a ast<'a>)
}
-fn mk_add_bad2<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast {
+fn mk_add_bad2<'a,'b>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast<'b> {
add(x, y) //~ ERROR cannot infer
}
}
// Meets F, but not G.
-fn baz<'a>(x: &'a S) -> &'a S {
+fn baz(x: &S) -> &S {
fail!()
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn of<T>() -> |T| { fail!(); }
+fn of<'a,T>() -> |T|:'a { fail!(); }
fn subtype<T>(x: |T|) { fail!(); }
fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
g: ||: 'static
}
-fn take1(p: parameterized1) -> parameterized1 { p }
+fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
//~^ ERROR mismatched types
//~^^ ERROR cannot infer
return &p.x;
}
-fn foo(p: Gc<point>) -> &int {
+fn foo<'a>(p: Gc<point>) -> &'a int {
let xc = x_coord(&*p); //~ ERROR `*p` does not live long enough
assert_eq!(*xc, 3);
return xc;
use std::gc::Gc;
-fn borrow<'r, T>(x: &'r T) -> &'r T {x}
+fn borrow<T>(x: &T) -> &T {x}
fn foo(cond: || -> bool, make_box: || -> Gc<int>) {
let mut y: ∫
g: |direct<'a>|: 'static
}
-fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types
+fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types
//~^ ERROR cannot infer
fn take_indirect1(p: indirect1) -> indirect1 { p }
-fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types
+fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types
//~^ ERROR cannot infer
fn main() {}
Variant1
}
-fn structLifetime() -> &Test {
+fn structLifetime<'a>() -> &'a Test {
let testValue = &Test; //~ ERROR borrowed value does not live long enough
testValue
}
-fn variantLifetime() -> &MyEnum {
+fn variantLifetime<'a>() -> &'a MyEnum {
let testValue = &Variant1; //~ ERROR borrowed value does not live long enough
testValue
}
f(&3)
}
-fn return_it() -> &int {
+fn return_it<'a>() -> &'a int {
with(|o| o) //~ ERROR mismatched types
//~^ ERROR lifetime of return value does not outlive the function call
//~^^ ERROR cannot infer
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f<'a>(_x : &'a int) -> &'a int {
+fn f(_x: &int) -> &int {
return &3; //~ ERROR borrowed value does not live long enough
}
p: &'r X
}
-fn make_a<'r>(p:&'r X) -> A<'r> {
+fn make_a(p:&X) -> A {
A{p:p}
}
-fn make_make_a() -> A {
+fn make_make_a<'a>() -> A<'a> {
let b: Box<B> = box B {
i: 1,
};
// instead of spitting out a custom error about some identifier collisions
// (we should allow shadowing)
match 4i {
- a => {}
- _ => {} //~ ERROR: unreachable pattern
+ a => {} //~ ERROR mutable static variables cannot be referenced in a pattern
+ _ => {}
+ }
+}
+
+struct NewBool(bool);
+enum Direction {
+ North,
+ East,
+ South,
+ West
+}
+static NEW_FALSE: NewBool = NewBool(false);
+struct Foo {
+ bar: Option<Direction>,
+ baz: NewBool
+}
+
+static mut STATIC_MUT_FOO: Foo = Foo { bar: Some(West), baz: NEW_FALSE };
+
+fn mutable_statics() {
+ match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ Foo { bar: None, baz: NewBool(true) } => (),
+ STATIC_MUT_FOO => (),
+ //~^ ERROR mutable static variables cannot be referenced in a pattern
+ Foo { bar: Some(South), .. } => (),
+ Foo { bar: Some(EAST), .. } => (),
+ Foo { bar: Some(North), baz: NewBool(true) } => (),
+ Foo { bar: Some(EAST), baz: NewBool(false) } => ()
}
}
rm $(TMPDIR)/$(call BIN,bar)
$(RUSTC) foo1.rs
rm $(TMPDIR)/$(call BIN,foo)
- $(RUSTC) foo1.rs --crate-name bar
- rm $(TMPDIR)/$(call BIN,bar)
- $(RUSTC) foo1.rs --crate-name bar -o $(TMPDIR)/bar1
+ $(RUSTC) foo1.rs -o $(TMPDIR)/bar1
rm $(TMPDIR)/$(call BIN,bar1)
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) -C extra-filename=bar foo.rs -C save-temps
+ rm $(TMPDIR)/foobar.o
+ rm $(TMPDIR)/$(call BIN,foobar)
--- /dev/null
+// 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.
+
+fn main() {}
}
impl Box {
- fn get<'a>(&'a self) -> &'a uint {
+ fn get(&self) -> &uint {
&self.x
}
fn set(&mut self, x: uint) {
impl<T> Map<int, T> for cat<T> {
fn contains_key(&self, k: &int) -> bool { *k <= self.meows }
- fn find<'a>(&'a self, k: &int) -> Option<&'a T> {
+ fn find(&self, k: &int) -> Option<&T> {
if *k <= self.meows {
Some(&self.name)
} else {
true
}
- fn find_mut<'a>(&'a mut self, _k: &int) -> Option<&'a mut T> { fail!() }
+ fn find_mut(&mut self, _k: &int) -> Option<&mut T> { fail!() }
fn remove(&mut self, k: &int) -> bool {
if self.find(k).is_some() {
}
impl<T> cat<T> {
- pub fn get<'a>(&'a self, k: &int) -> &'a T {
+ pub fn get(&self, k: &int) -> &T {
match self.find(k) {
Some(v) => { v }
None => { fail!("epic fail"); }
}
impl AddFlags {
- fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
+ fn check_flags(&self, exp: u64) -> &AddFlags {
check_flags(exp);
self
}
// compile-flags:--crate-name crate-name-attr-used -F unused-attribute
-#![crate_name = "test"]
+#![crate_name = "crate-name-attr-used"]
fn main() {}
}
}
-fn font<'r>(fontbuf: &'r Vec<u8> ) -> font<'r> {
+fn font(fontbuf: &Vec<u8> ) -> font {
font {
fontbuf: fontbuf
}
buf: &'a [u8],
}
-fn CMap<'r>(buf: &'r [u8]) -> CMap<'r> {
+fn CMap(buf: &[u8]) -> CMap {
CMap {
buf: buf
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn broken<'r>(v: &'r [u8], i: uint, j: uint) -> &'r [u8] { v.slice(i, j) }
+fn broken(v: &[u8], i: uint, j: uint) -> &[u8] { v.slice(i, j) }
pub fn main() {}
}
impl<'a> Outer<'a> {
- fn new<'r>(inner: &'r Inner) -> Outer<'r> {
+ fn new(inner: &Inner) -> Outer {
Outer {
inner: inner
}
impl FooBar for Bar {}
trait Test {
- fn get_immut<'r>(&'r self) -> &'r FooBar;
- fn get_mut<'r>(&'r mut self) -> &'r mut FooBar;
+ fn get_immut(&self) -> &FooBar;
+ fn get_mut(&mut self) -> &mut FooBar;
}
macro_rules! generate_test(($type_:path, $slf:ident, $field:expr) => (
impl Test for $type_ {
- fn get_immut<'r>(&'r $slf) -> &'r FooBar {
+ fn get_immut(&$slf) -> &FooBar {
&$field as &FooBar
}
- fn get_mut<'r>(&'r mut $slf) -> &'r mut FooBar {
+ fn get_mut(&mut $slf) -> &mut FooBar {
&mut $field as &mut FooBar
}
}
--- /dev/null
+// 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.
+
+#![feature(struct_variant)]
+
+struct NewBool(bool);
+
+enum Direction {
+ North,
+ East,
+ South,
+ West
+}
+struct Foo {
+ bar: Option<Direction>,
+ baz: NewBool
+}
+enum EnumWithStructVariants {
+ Variant1(bool),
+ Variant2 {
+ dir: Direction
+ }
+}
+
+static TRUE_TRUE: (bool, bool) = (true, true);
+static NONE: Option<Direction> = None;
+static EAST: Direction = East;
+static NEW_FALSE: NewBool = NewBool(false);
+static STATIC_FOO: Foo = Foo { bar: Some(South), baz: NEW_FALSE };
+static VARIANT2_NORTH: EnumWithStructVariants = Variant2 { dir: North };
+
+pub mod glfw {
+ pub struct InputState(uint);
+
+ pub static RELEASE : InputState = InputState(0);
+ pub static PRESS : InputState = InputState(1);
+ pub static REPEAT : InputState = InputState(2);
+}
+
+fn issue_6533() {
+ use glfw;
+
+ fn action_to_str(state: glfw::InputState) -> &'static str {
+ use glfw::{RELEASE, PRESS, REPEAT};
+ match state {
+ RELEASE => { "Released" }
+ PRESS => { "Pressed" }
+ REPEAT => { "Repeated" }
+ _ => { "Unknown" }
+ }
+ }
+
+ assert_eq!(action_to_str(glfw::RELEASE), "Released");
+ assert_eq!(action_to_str(glfw::PRESS), "Pressed");
+ assert_eq!(action_to_str(glfw::REPEAT), "Repeated");
+}
+
+fn issue_13626() {
+ static VAL: [u8, ..1] = [0];
+ match [1] {
+ VAL => unreachable!(),
+ _ => ()
+ }
+}
+
+fn issue_14576() {
+ type Foo = (i32, i32);
+ static ON: Foo = (1, 1);
+ static OFF: Foo = (0, 0);
+
+ match (1, 1) {
+ OFF => unreachable!(),
+ ON => (),
+ _ => unreachable!()
+ }
+
+ enum C { D = 3, E = 4 }
+ static F : C = D;
+
+ assert_eq!(match D { F => 1i, _ => 2, }, 1);
+}
+
+fn issue_13731() {
+ enum A { A(()) }
+ static B: A = A(());
+
+ match A(()) {
+ B => ()
+ }
+}
+
+fn issue_15393() {
+ #![allow(dead_code)]
+ struct Flags {
+ bits: uint
+ }
+
+ static FOO: Flags = Flags { bits: 0x01 };
+ static BAR: Flags = Flags { bits: 0x02 };
+ match (Flags { bits: 0x02 }) {
+ FOO => unreachable!(),
+ BAR => (),
+ _ => unreachable!()
+ }
+}
+
+fn main() {
+ assert_eq!(match (true, false) {
+ TRUE_TRUE => 1i,
+ (false, false) => 2,
+ (false, true) => 3,
+ (true, false) => 4
+ }, 4);
+
+ assert_eq!(match Some(Some(North)) {
+ Some(NONE) => 1i,
+ Some(Some(North)) => 2,
+ Some(Some(EAST)) => 3,
+ Some(Some(South)) => 4,
+ Some(Some(West)) => 5,
+ None => 6
+ }, 2);
+
+ assert_eq!(match (Foo { bar: Some(West), baz: NewBool(true) }) {
+ Foo { bar: None, baz: NewBool(true) } => 1i,
+ Foo { bar: NONE, baz: NEW_FALSE } => 2,
+ STATIC_FOO => 3,
+ Foo { bar: _, baz: NEW_FALSE } => 4,
+ Foo { bar: Some(West), baz: NewBool(true) } => 5,
+ Foo { bar: Some(South), baz: NewBool(true) } => 6,
+ Foo { bar: Some(EAST), .. } => 7,
+ Foo { bar: Some(North), baz: NewBool(true) } => 8
+ }, 5);
+
+ assert_eq!(match (Variant2 { dir: North }) {
+ Variant1(true) => 1i,
+ Variant1(false) => 2,
+ Variant2 { dir: West } => 3,
+ VARIANT2_NORTH => 4,
+ Variant2 { dir: South } => 5,
+ Variant2 { dir: East } => 6
+ }, 4);
+
+ issue_6533();
+ issue_13626();
+ issue_13731();
+ issue_14576();
+ issue_15393();
+}
Nothing(..) => true
}
}
- fn get_ref<'r>(&'r self) -> (int, &'r T) {
+ fn get_ref(&self) -> (int, &T) {
match *self {
Nothing(..) => fail!("E::get_ref(Nothing::<{}>)", stringify!(T)),
Thing(x, ref y) => (x, y)
}
impl ops::Index<bool,int> for Point {
- fn index<'a>(&'a self, x: &bool) -> &'a int {
+ fn index(&self, x: &bool) -> &int {
if *x {
&self.x
} else {
}
impl<T> Deref<T> for DerefCounter<T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
self.count_imm.set(self.count_imm.get() + 1);
&self.value
}
}
impl<T> DerefMut<T> for DerefCounter<T> {
- fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+ fn deref_mut(&mut self) -> &mut T {
self.count_mut += 1;
&mut self.value
}
}
impl<X, Y> Deref<Y> for DerefWrapper<X, Y> {
- fn deref<'a>(&'a self) -> &'a Y {
+ fn deref(&self) -> &Y {
&self.y
}
}
}
impl<X, Y> Deref<Y> for DerefWrapperHideX<X, Y> {
- fn deref<'a>(&'a self) -> &'a Y {
+ fn deref(&self) -> &Y {
&self.y
}
}
}
trait Helper<T> {
- fn helper_borrow<'a>(&'a self) -> &'a T;
+ fn helper_borrow(&self) -> &T;
}
impl<T> Helper<T> for Option<T> {
- fn helper_borrow<'a>(&'a self) -> &'a T {
+ fn helper_borrow(&self) -> &T {
self.as_ref().unwrap()
}
}
impl<T, H: Helper<T>> Deref<T> for DerefWithHelper<H, T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
self.helper.helper_borrow()
}
}
}
impl<T> Deref<T> for DerefCounter<T> {
- fn deref<'a>(&'a self) -> &'a T {
+ fn deref(&self) -> &T {
self.count_imm.set(self.count_imm.get() + 1);
&self.value
}
}
impl<T> DerefMut<T> for DerefCounter<T> {
- fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+ fn deref_mut(&mut self) -> &mut T {
self.count_mut += 1;
&mut self.value
}
}
impl Index<int,int> for Foo {
- fn index<'a>(&'a self, z: &int) -> &'a int {
+ fn index(&self, z: &int) -> &int {
if *z == 0 {
&self.x
} else {
}
impl IndexMut<int,int> for Foo {
- fn index_mut<'a>(&'a mut self, z: &int) -> &'a mut int {
+ fn index_mut(&mut self, z: &int) -> &mut int {
if *z == 0 {
&mut self.x
} else {
pos: Box<Point>,
}
-fn get_x<'r>(x: &'r Character) -> &'r int {
+fn get_x(x: &Character) -> &int {
// interesting case because the scope of this
// borrow of the unique pointer is in fact
// larger than the fn itself
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f<'a>(x : &'a int) -> &'a int {
+fn f(x: &int) -> &int {
return &*x;
}
cl: ||: 'a,
}
-fn box_it<'r>(x: ||: 'r) -> closure_box<'r> {
+fn box_it(x: ||) -> closure_box {
closure_box {cl: x}
}
f: int
}
-fn get_v1<'v>(a: &'v A) -> &'v int {
+fn get_v1(a: &A) -> &int {
// Region inferencer must deduce that &v < L2 < L1
let foo = &a.value; // L1
&foo.v1 // L2
}
-fn get_v2<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v2(a: &A, i: uint) -> &int {
let foo = &a.value;
&foo.v2[i]
}
-fn get_v3<'v>(a: &'v A, i: uint) -> &'v int {
+fn get_v3(a: &A, i: uint) -> &int {
let foo = &a.value;
foo.v3.get(i)
}
-fn get_v4<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v4(a: &A, _i: uint) -> &int {
let foo = &a.value;
&foo.v4.f
}
-fn get_v5<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v5(a: &A, _i: uint) -> &int {
let foo = &a.value;
&foo.v5.f
}
-fn get_v6_a<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v6_a(a: &A, _i: uint) -> &int {
match a.value.v6 {
Some(ref v) => &v.f,
None => fail!()
}
}
-fn get_v6_b<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v6_b(a: &A, _i: uint) -> &int {
match *a {
A { value: B { v6: Some(ref v), .. } } => &v.f,
_ => fail!()
}
}
-fn get_v6_c<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v6_c(a: &A, _i: uint) -> &int {
match a {
&A { value: B { v6: Some(ref v), .. } } => &v.f,
_ => fail!()
}
}
-fn get_v5_ref<'v>(a: &'v A, _i: uint) -> &'v int {
+fn get_v5_ref(a: &A, _i: uint) -> &int {
match &a.value {
&B {v5: box C {f: ref v}, ..} => v
}
// Test lifetimes are linked properly when we autoslice a vector.
// Issue #3148.
-fn subslice<'r>(v: ||: 'r) -> ||: 'r { v }
+fn subslice(v: ||) -> || { v }
-fn both<'r>(v: ||: 'r) -> ||: 'r {
+fn both(v: ||) -> || {
subslice(subslice(v))
}
use std::gc::GC;
-fn foo<'r>(x: &'r uint) -> &'r uint { x }
+fn foo(x: &uint) -> &uint { x }
fn bar(x: &uint) -> uint { *x }
pub fn main() {
// except according to those terms.
-fn view<'r, T>(x: &'r [T]) -> &'r [T] {x}
+fn view<T>(x: &[T]) -> &[T] {x}
pub fn main() {
let v = vec!(1i, 2, 3);
use std::gc::GC;
-fn borrow<'r, T>(x: &'r T) -> &'r T {x}
+fn borrow<T>(x: &T) -> &T {x}
pub fn main() {
let x = box(GC) 3i;
struct Point {x: int, y: int}
-fn x_coord<'r>(p: &'r Point) -> &'r int {
+fn x_coord(p: &Point) -> &int {
return &p.x;
}
a, b(&'a uint)
}
-fn mk<'r>(cond: bool, ptr: &'r uint) -> roption<'r> {
+fn mk(cond: bool, ptr: &uint) -> roption {
if cond {a} else {b(ptr)}
}
// except according to those terms.
-fn region_identity<'r>(x: &'r uint) -> &'r uint { x }
+fn region_identity(x: &uint) -> &uint { x }
fn apply<T>(t: T, f: |T| -> T) -> T { f(t) }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn get<'r, T>(opt: &'r Option<T>) -> &'r T {
+fn get<T>(opt: &Option<T>) -> &T {
match *opt {
Some(ref v) => v,
None => fail!("none")
cl: ||: 'a,
}
-fn box_it<'r>(x: ||: 'r) -> closure_box<'r> {
+fn box_it(x: ||) -> closure_box {
closure_box {cl: x}
}