diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3830d7fe29532..a8d6c3ff2b000 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -73,7 +73,6 @@ use core::prelude::*; use core::atomic; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; -use core::borrow::BorrowFrom; use core::fmt; use core::cmp::{Ordering}; use core::default::Default; @@ -244,12 +243,6 @@ impl Clone for Arc { } } -impl BorrowFrom> for T { - fn borrow_from(owned: &Arc) -> &T { - &**owned - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Arc { type Target = T; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index f361c36ec8fa7..3e52886280b8f 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -144,7 +144,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::borrow::BorrowFrom; use core::cell::Cell; use core::clone::Clone; use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; @@ -349,12 +348,6 @@ impl Rc { } } -impl BorrowFrom> for T { - fn borrow_from(owned: &Rc) -> &T { - &**owned - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Rc { type Target = T; diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs new file mode 100644 index 0000000000000..62e6f347df398 --- /dev/null +++ b/src/libcollections/borrow.rs @@ -0,0 +1,306 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A module for working with borrowed data. + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::clone::Clone; +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::hash::{Hash, Hasher}; +use core::marker::Sized; +use core::ops::Deref; +use core::option::Option; + +use fmt; +use alloc::{rc, arc}; + +use self::Cow::*; + +/// A trait for borrowing data. +/// +/// In general, there may be several ways to "borrow" a piece of data. The +/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` +/// (a mutable borrow). But types like `Vec` provide additional kinds of +/// borrows: the borrowed slices `&[T]` and `&mut [T]`. +/// +/// When writing generic code, it is often desirable to abstract over all ways +/// of borrowing data from a given type. That is the role of the `Borrow` +/// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given +/// type can be borrowed as multiple different types. In particular, `Vec: +/// Borrow>` and `Vec: Borrow<[T]>`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Borrow { + /// Immutably borrow from an owned value. + #[stable(feature = "rust1", since = "1.0.0")] + fn borrow(&self) -> &Borrowed; +} + +/// A trait for mutably borrowing data. +/// +/// Similar to `Borrow`, but for mutable borrows. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait BorrowMut : Borrow { + /// Mutably borrow from an owned value. + #[stable(feature = "rust1", since = "1.0.0")] + fn borrow_mut(&mut self) -> &mut Borrowed; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for T { + fn borrow(&self) -> &T { self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BorrowMut for T { + fn borrow_mut(&mut self) -> &mut T { self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Borrow for &'a T { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Borrow for &'a mut T { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> BorrowMut for &'a mut T { + fn borrow_mut(&mut self) -> &mut T { &mut **self } +} + +impl Borrow for rc::Rc { + fn borrow(&self) -> &T { &**self } +} + +impl Borrow for arc::Arc { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Borrow for Cow<'a, B> where B: ToOwned, ::Owned: 'a { + fn borrow(&self) -> &B { + &**self + } +} + +/// A generalization of Clone to borrowed data. +/// +/// Some types make it possible to go from borrowed to owned, usually by +/// implementing the `Clone` trait. But `Clone` works only for going from `&T` +/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data +/// from any borrow of a given type. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ToOwned { + #[stable(feature = "rust1", since = "1.0.0")] + type Owned: Borrow; + + /// Create owned data from borrowed data, usually by copying. + #[stable(feature = "rust1", since = "1.0.0")] + fn to_owned(&self) -> Self::Owned; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for T where T: Clone { + type Owned = T; + fn to_owned(&self) -> T { self.clone() } +} + +/// A clone-on-write smart pointer. +/// +/// The type `Cow` is a smart pointer providing clone-on-write functionality: it +/// can enclose and provide immutable access to borrowed data, and clone the +/// data lazily when mutation or ownership is required. The type is designed to +/// work with general borrowed data via the `Borrow` trait. +/// +/// `Cow` implements both `Deref`, which means that you can call +/// non-mutating methods directly on the data it encloses. If mutation +/// is desired, `to_mut` will obtain a mutable references to an owned +/// value, cloning if necessary. +/// +/// # Example +/// +/// ```rust +/// use std::borrow::Cow; +/// +/// fn abs_all(input: &mut Cow<[int]>) { +/// for i in 0..input.len() { +/// let v = input[i]; +/// if v < 0 { +/// // clones into a vector the first time (if not already owned) +/// input.to_mut()[i] = -v; +/// } +/// } +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned { + /// Borrowed data. + #[stable(feature = "rust1", since = "1.0.0")] + Borrowed(&'a B), + + /// Owned data. + #[stable(feature = "rust1", since = "1.0.0")] + Owned(::Owned) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned { + fn clone(&self) -> Cow<'a, B> { + match *self { + Borrowed(b) => Borrowed(b), + Owned(ref o) => { + let b: &B = o.borrow(); + Owned(b.to_owned()) + }, + } + } +} + +impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { + /// Acquire a mutable reference to the owned form of the data. + /// + /// Copies the data if it is not already owned. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_mut(&mut self) -> &mut ::Owned { + match *self { + Borrowed(borrowed) => { + *self = Owned(borrowed.to_owned()); + self.to_mut() + } + Owned(ref mut owned) => owned + } + } + + /// Extract the owned data. + /// + /// Copies the data if it is not already owned. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_owned(self) -> ::Owned { + match self { + Borrowed(borrowed) => borrowed.to_owned(), + Owned(owned) => owned + } + } + + /// Returns true if this `Cow` wraps a borrowed value + #[deprecated(since = "1.0.0", reason = "match on the enum instead")] + #[unstable(feature = "std_misc")] + pub fn is_borrowed(&self) -> bool { + match *self { + Borrowed(_) => true, + _ => false, + } + } + + /// Returns true if this `Cow` wraps an owned value + #[deprecated(since = "1.0.0", reason = "match on the enum instead")] + #[unstable(feature = "std_misc")] + pub fn is_owned(&self) -> bool { + match *self { + Owned(_) => true, + _ => false, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned { + type Target = B; + + fn deref(&self) -> &B { + match *self { + Borrowed(borrowed) => borrowed, + Owned(ref owned) => owned.borrow() + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Ord for Cow<'a, B> where B: Ord + ToOwned { + #[inline] + fn cmp(&self, other: &Cow<'a, B>) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for Cow<'a, B> where + B: PartialEq + ToOwned, C: ToOwned, +{ + #[inline] + fn eq(&self, other: &Cow<'b, C>) -> bool { + PartialEq::eq(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where B: PartialOrd + ToOwned, +{ + #[inline] + fn partial_cmp(&self, other: &Cow<'a, B>) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> where + B: fmt::Debug + ToOwned, + ::Owned: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Borrowed(ref b) => fmt::Debug::fmt(b, f), + Owned(ref o) => fmt::Debug::fmt(o, f), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> where + B: fmt::Display + ToOwned, + ::Owned: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Borrowed(ref b) => fmt::Display::fmt(b, f), + Owned(ref o) => fmt::Display::fmt(o, f), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized, S: Hasher> Hash for Cow<'a, B> where B: Hash + ToOwned +{ + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } +} + +/// Trait for moving into a `Cow` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { + /// Moves `self` into `Cow` + #[stable(feature = "rust1", since = "1.0.0")] + fn into_cow(self) -> Cow<'a, B>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { + fn into_cow(self) -> Cow<'a, B> { + self + } +} diff --git a/src/libcollections/borrow_stage0.rs b/src/libcollections/borrow_stage0.rs new file mode 100644 index 0000000000000..c1d74b16ce6bc --- /dev/null +++ b/src/libcollections/borrow_stage0.rs @@ -0,0 +1,313 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A module for working with borrowed data. + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::clone::Clone; +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::hash::{Hash, Hasher}; +use core::marker::Sized; +use core::ops::Deref; +use core::option::Option; + +use fmt; +use alloc::{rc, arc}; + +use self::Cow::*; + +/// A trait for borrowing data. +/// +/// In general, there may be several ways to "borrow" a piece of data. The +/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` +/// (a mutable borrow). But types like `Vec` provide additional kinds of +/// borrows: the borrowed slices `&[T]` and `&mut [T]`. +/// +/// When writing generic code, it is often desirable to abstract over all ways +/// of borrowing data from a given type. That is the role of the `Borrow` +/// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given +/// type can be borrowed as multiple different types. In particular, `Vec: +/// Borrow>` and `Vec: Borrow<[T]>`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Borrow { + /// Immutably borrow from an owned value. + #[stable(feature = "rust1", since = "1.0.0")] + fn borrow(&self) -> &Borrowed; +} + +/// A trait for mutably borrowing data. +/// +/// Similar to `Borrow`, but for mutable borrows. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait BorrowMut : Borrow { + /// Mutably borrow from an owned value. + #[stable(feature = "rust1", since = "1.0.0")] + fn borrow_mut(&mut self) -> &mut Borrowed; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for T { + fn borrow(&self) -> &T { self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BorrowMut for T { + fn borrow_mut(&mut self) -> &mut T { self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Borrow for &'a T { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Borrow for &'a mut T { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> BorrowMut for &'a mut T { + fn borrow_mut(&mut self) -> &mut T { &mut **self } +} + +impl Borrow for rc::Rc { + fn borrow(&self) -> &T { &**self } +} + +impl Borrow for arc::Arc { + fn borrow(&self) -> &T { &**self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Borrow for Cow<'a, B> where B: ToOwned, ::Owned: 'a { + fn borrow(&self) -> &B { + &**self + } +} + +/// A generalization of Clone to borrowed data. +/// +/// Some types make it possible to go from borrowed to owned, usually by +/// implementing the `Clone` trait. But `Clone` works only for going from `&T` +/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data +/// from any borrow of a given type. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ToOwned { + #[stable(feature = "rust1", since = "1.0.0")] + type Owned: Borrow; + + /// Create owned data from borrowed data, usually by copying. + #[stable(feature = "rust1", since = "1.0.0")] + fn to_owned(&self) -> Self::Owned; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for T where T: Clone { + type Owned = T; + fn to_owned(&self) -> T { self.clone() } +} + +/// A clone-on-write smart pointer. +/// +/// The type `Cow` is a smart pointer providing clone-on-write functionality: it +/// can enclose and provide immutable access to borrowed data, and clone the +/// data lazily when mutation or ownership is required. The type is designed to +/// work with general borrowed data via the `Borrow` trait. +/// +/// `Cow` implements both `Deref`, which means that you can call +/// non-mutating methods directly on the data it encloses. If mutation +/// is desired, `to_mut` will obtain a mutable references to an owned +/// value, cloning if necessary. +/// +/// # Example +/// +/// ```rust +/// use std::borrow::Cow; +/// +/// fn abs_all(input: &mut Cow<[int]>) { +/// for i in 0..input.len() { +/// let v = input[i]; +/// if v < 0 { +/// // clones into a vector the first time (if not already owned) +/// input.to_mut()[i] = -v; +/// } +/// } +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned { + /// Borrowed data. + #[stable(feature = "rust1", since = "1.0.0")] + Borrowed(&'a B), + + /// Owned data. + #[stable(feature = "rust1", since = "1.0.0")] + Owned(::Owned) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned { + fn clone(&self) -> Cow<'a, B> { + match *self { + Borrowed(b) => Borrowed(b), + Owned(ref o) => { + let b: &B = o.borrow(); + Owned(b.to_owned()) + }, + } + } +} + +impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned, ::Owned: 'a { + /// Acquire a mutable reference to the owned form of the data. + /// + /// Copies the data if it is not already owned. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_mut(&mut self) -> &mut ::Owned where ::Owned: 'a { + match *self { + Borrowed(borrowed) => { + *self = Owned(borrowed.to_owned()); + self.to_mut() + } + Owned(ref mut owned) => owned + } + } + + /// Extract the owned data. + /// + /// Copies the data if it is not already owned. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_owned(self) -> ::Owned { + match self { + Borrowed(borrowed) => borrowed.to_owned(), + Owned(owned) => owned + } + } + + /// Returns true if this `Cow` wraps a borrowed value + #[deprecated(since = "1.0.0", reason = "match on the enum instead")] + #[unstable(feature = "std_misc")] + pub fn is_borrowed(&self) -> bool { + match *self { + Borrowed(_) => true, + _ => false, + } + } + + /// Returns true if this `Cow` wraps an owned value + #[deprecated(since = "1.0.0", reason = "match on the enum instead")] + #[unstable(feature = "std_misc")] + pub fn is_owned(&self) -> bool { + match *self { + Owned(_) => true, + _ => false, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Deref for Cow<'a, B> where + B: ToOwned, ::Owned: 'a +{ + type Target = B; + + fn deref(&self) -> &B { + match *self { + Borrowed(borrowed) => borrowed, + Owned(ref owned) => owned.borrow() + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned, ::Owned: 'a {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> Ord for Cow<'a, B> where + B: Ord + ToOwned, ::Owned: 'a +{ + #[inline] + fn cmp(&self, other: &Cow<'a, B>) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for Cow<'a, B> where + B: PartialEq + ToOwned, C: ToOwned, + ::Owned: 'a, ::Owned: 'b, +{ + #[inline] + fn eq(&self, other: &Cow<'b, C>) -> bool { + PartialEq::eq(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where + B: PartialOrd + ToOwned, ::Owned: 'a +{ + #[inline] + fn partial_cmp(&self, other: &Cow<'a, B>) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> where + B: fmt::Debug + ToOwned, + ::Owned: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Borrowed(ref b) => fmt::Debug::fmt(b, f), + Owned(ref o) => fmt::Debug::fmt(o, f), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> where + B: fmt::Display + ToOwned, + ::Owned: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Borrowed(ref b) => fmt::Display::fmt(b, f), + Owned(ref o) => fmt::Display::fmt(o, f), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized, S: Hasher> Hash for Cow<'a, B> where + B: Hash + ToOwned, ::Owned: 'a +{ + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } +} + +/// Trait for moving into a `Cow` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { + /// Moves `self` into `Cow` + #[stable(feature = "rust1", since = "1.0.0")] + fn into_cow(self) -> Cow<'a, B>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { + fn into_cow(self) -> Cow<'a, B> { + self + } +} diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 747211e923859..6b980d473b590 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -19,7 +19,6 @@ use self::Entry::*; use core::prelude::*; -use core::borrow::BorrowFrom; use core::cmp::Ordering; use core::default::Default; use core::fmt::Debug; @@ -29,6 +28,7 @@ use core::ops::{Index, IndexMut}; use core::{iter, fmt, mem}; use Bound::{self, Included, Excluded, Unbounded}; +use borrow::Borrow; use ring_buf::RingBuf; use self::Continuation::{Continue, Finished}; @@ -208,7 +208,7 @@ impl BTreeMap { /// assert_eq!(map.get(&2), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, key: &Q) -> Option<&V> where Q: BorrowFrom + Ord { + pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow, Q: Ord { let mut cur_node = &self.root; loop { match Node::search(cur_node, key) { @@ -240,7 +240,7 @@ impl BTreeMap { /// assert_eq!(map.contains_key(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains_key(&self, key: &Q) -> bool where Q: BorrowFrom + Ord { + pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, Q: Ord { self.get(key).is_some() } @@ -264,7 +264,7 @@ impl BTreeMap { /// ``` // See `get` for implementation notes, this is basically a copy-paste with mut's added #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where Q: BorrowFrom + Ord { + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where K: Borrow, Q: Ord { // temp_node is a Borrowck hack for having a mutable value outlive a loop iteration let mut temp_node = &mut self.root; loop { @@ -434,7 +434,7 @@ impl BTreeMap { /// assert_eq!(map.remove(&1), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, key: &Q) -> Option where Q: BorrowFrom + Ord { + pub fn remove(&mut self, key: &Q) -> Option where K: Borrow, Q: Ord { // See `swap` for a more thorough description of the stuff going on in here let mut stack = stack::PartialSearchStack::new(self); loop { @@ -903,7 +903,7 @@ impl Debug for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Index for BTreeMap - where Q: BorrowFrom + Ord + where K: Borrow, Q: Ord { type Output = V; @@ -914,7 +914,7 @@ impl Index for BTreeMap #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for BTreeMap - where Q: BorrowFrom + Ord + where K: Borrow, Q: Ord { fn index_mut(&mut self, key: &Q) -> &mut V { self.get_mut(key).expect("no entry found for key") diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 24523d4dcc9d3..8f5ee35fcb265 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -18,7 +18,6 @@ pub use self::TraversalItem::*; use core::prelude::*; -use core::borrow::BorrowFrom; use core::cmp::Ordering::{Greater, Less, Equal}; use core::iter::Zip; use core::ops::{Deref, DerefMut, Index, IndexMut}; @@ -26,6 +25,8 @@ use core::ptr::Unique; use core::{slice, mem, ptr, cmp, num, raw}; use alloc::heap; +use borrow::Borrow; + /// Represents the result of an Insertion: either the item fit, or the node had to split pub enum InsertionResult { /// The inserted element fit @@ -543,7 +544,7 @@ impl Node { /// `Found` will be yielded with the matching index. If it doesn't find an exact match, /// `GoDown` will be yielded with the index of the subtree the key must lie in. pub fn search>>(node: NodeRef, key: &Q) - -> SearchResult where Q: BorrowFrom + Ord { + -> SearchResult where K: Borrow, Q: Ord { // FIXME(Gankro): Tune when to search linear or binary based on B (and maybe K/V). // For the B configured as of this writing (B = 6), binary search was *significantly* // worse for usizes. @@ -1491,9 +1492,9 @@ macro_rules! node_slice_impl { impl<'a, K: Ord + 'a, V: 'a> $NodeSlice<'a, K, V> { /// Performs linear search in a slice. Returns a tuple of (index, is_exact_match). fn search_linear(&self, key: &Q) -> (usize, bool) - where Q: BorrowFrom + Ord { + where K: Borrow, Q: Ord { for (i, k) in self.keys.iter().enumerate() { - match key.cmp(BorrowFrom::borrow_from(k)) { + match key.cmp(k.borrow()) { Greater => {}, Equal => return (i, true), Less => return (i, false), diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 7ef887b70cc6c..cf96ef49c7f59 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -13,7 +13,6 @@ use core::prelude::*; -use core::borrow::BorrowFrom; use core::cmp::Ordering::{self, Less, Greater, Equal}; use core::default::Default; use core::fmt::Debug; @@ -21,6 +20,7 @@ use core::fmt; use core::iter::{Peekable, Map, FromIterator, IntoIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub}; +use borrow::Borrow; use btree_map::{BTreeMap, Keys}; use Bound; @@ -336,7 +336,7 @@ impl BTreeSet { /// assert_eq!(set.contains(&4), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, value: &Q) -> bool where Q: BorrowFrom + Ord { + pub fn contains(&self, value: &Q) -> bool where T: Borrow, Q: Ord { self.map.contains_key(value) } @@ -466,7 +466,7 @@ impl BTreeSet { /// assert_eq!(set.remove(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, value: &Q) -> bool where Q: BorrowFrom + Ord { + pub fn remove(&mut self, value: &Q) -> bool where T: Borrow, Q: Ord { self.map.remove(value).is_some() } } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index cacbf3bce80f0..f5fbd10ceebfe 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -81,6 +81,13 @@ pub mod string; pub mod vec; pub mod vec_map; +#[cfg(stage0)] +#[path = "borrow_stage0.rs"] +pub mod borrow; + +#[cfg(not(stage0))] +pub mod borrow; + #[unstable(feature = "collections", reason = "RFC 509")] pub mod bitv { diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 06ae8127c00fb..a0cb98267fa77 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -88,7 +88,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use alloc::boxed::Box; -use core::borrow::{BorrowFrom, BorrowFromMut, ToOwned}; use core::clone::Clone; use core::cmp::Ordering::{self, Greater, Less}; use core::cmp::{self, Ord, PartialEq}; @@ -105,6 +104,7 @@ use core::result::Result; use core::slice as core_slice; use self::Direction::*; +use borrow::{Borrow, BorrowMut, ToOwned}; use vec::Vec; pub use core::slice::{Chunks, AsSlice, Windows}; @@ -1175,18 +1175,19 @@ impl ElementSwaps { // Standard trait implementations for slices //////////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "collections", reason = "trait is unstable")] -impl BorrowFrom> for [T] { - fn borrow_from(owned: &Vec) -> &[T] { &owned[] } +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow<[T]> for Vec { + fn borrow(&self) -> &[T] { &self[] } } -#[unstable(feature = "collections", reason = "trait is unstable")] -impl BorrowFromMut> for [T] { - fn borrow_from_mut(owned: &mut Vec) -> &mut [T] { &mut owned[] } +#[stable(feature = "rust1", since = "1.0.0")] +impl BorrowMut<[T]> for Vec { + fn borrow_mut(&mut self) -> &mut [T] { &mut self[] } } -#[unstable(feature = "collections", reason = "trait is unstable")] -impl ToOwned> for [T] { +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for [T] { + type Owned = Vec; fn to_owned(&self) -> Vec { self.to_vec() } } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 2d4dc2bcf30d3..95fd233dc97ec 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -55,7 +55,6 @@ use self::RecompositionState::*; use self::DecompositionType::*; -use core::borrow::{BorrowFrom, ToOwned}; use core::char::CharExt; use core::clone::Clone; use core::iter::AdditiveIterator; @@ -68,6 +67,7 @@ use core::slice::AsSlice; use core::str as core_str; use unicode::str::{UnicodeStr, Utf16Encoder}; +use borrow::{Borrow, ToOwned}; use ring_buf::RingBuf; use slice::SliceExt; use string::String; @@ -386,13 +386,14 @@ macro_rules! utf8_acc_cont_byte { ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32) } -#[unstable(feature = "collections", reason = "trait is unstable")] -impl BorrowFrom for str { - fn borrow_from(owned: &String) -> &str { &owned[] } +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for String { + fn borrow(&self) -> &str { &self[] } } -#[unstable(feature = "collections", reason = "trait is unstable")] -impl ToOwned for str { +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for str { + type Owned = String; fn to_owned(&self) -> String { unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 69fd28d172368..f03ee671ffa63 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -16,7 +16,6 @@ use core::prelude::*; -use core::borrow::{Cow, IntoCow}; use core::default::Default; use core::error::Error; use core::fmt; @@ -29,6 +28,7 @@ use core::raw::Slice as RawSlice; use unicode::str as unicode_str; use unicode::str::Utf16Item; +use borrow::{Cow, IntoCow}; use str::{self, CharRange, FromStr, Utf8Error}; use vec::{DerefVec, Vec, as_vec}; @@ -142,7 +142,7 @@ impl String { /// assert_eq!(output.as_slice(), "Hello \u{FFFD}World"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> CowString<'a> { + pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { let mut i = 0; match str::from_utf8(v) { Ok(s) => return Cow::Borrowed(s), @@ -780,10 +780,10 @@ macro_rules! impl_eq { } impl_eq! { String, &'a str } -impl_eq! { CowString<'a>, String } +impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> PartialEq<&'b str> for CowString<'a> { +impl<'a, 'b> PartialEq<&'b str> for Cow<'a, str> { #[inline] fn eq(&self, other: &&'b str) -> bool { PartialEq::eq(&**self, &**other) } #[inline] @@ -791,11 +791,11 @@ impl<'a, 'b> PartialEq<&'b str> for CowString<'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> PartialEq> for &'b str { +impl<'a, 'b> PartialEq> for &'b str { #[inline] - fn eq(&self, other: &CowString<'a>) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &Cow<'a, str>) -> bool { PartialEq::eq(&**self, &**other) } #[inline] - fn ne(&self, other: &CowString<'a>) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&**self, &**other) } } #[unstable(feature = "collections", reason = "waiting on Str stabilization")] @@ -958,31 +958,34 @@ impl ToString for T { } } -impl IntoCow<'static, String, str> for String { +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoCow<'static, str> for String { #[inline] - fn into_cow(self) -> CowString<'static> { + fn into_cow(self) -> Cow<'static, str> { Cow::Owned(self) } } -impl<'a> IntoCow<'a, String, str> for &'a str { +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> IntoCow<'a, str> for &'a str { #[inline] - fn into_cow(self) -> CowString<'a> { + fn into_cow(self) -> Cow<'a, str> { Cow::Borrowed(self) } } -/// A clone-on-write string -#[stable(feature = "rust1", since = "1.0.0")] -pub type CowString<'a> = Cow<'a, String, str>; - -impl<'a> Str for CowString<'a> { +impl<'a> Str for Cow<'a, str> { #[inline] fn as_slice<'b>(&'b self) -> &'b str { &**self } } +/// A clone-on-write string +#[deprecated(since = "1.0.0", reason = "use Cow<'a, str> instead")] +#[stable(feature = "rust1", since = "1.0.0")] +pub type CowString<'a> = Cow<'a, str>; + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index bde733644b5b5..df6aa560257b6 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -50,7 +50,6 @@ use core::prelude::*; use alloc::boxed::Box; use alloc::heap::{EMPTY, allocate, reallocate, deallocate}; -use core::borrow::{Cow, IntoCow}; use core::cmp::max; use core::cmp::{Ordering}; use core::default::Default; @@ -68,6 +67,8 @@ use core::raw::Slice as RawSlice; use core::slice; use core::usize; +use borrow::{Cow, IntoCow}; + /// A growable list type, written `Vec` but pronounced 'vector.' /// /// # Examples @@ -1517,34 +1518,34 @@ macro_rules! impl_eq { impl_eq! { Vec, &'b [B] } impl_eq! { Vec, &'b mut [B] } -impl<'a, A, B> PartialEq> for CowVec<'a, A> where A: PartialEq + Clone { +impl<'a, A, B> PartialEq> for Cow<'a, [A]> where A: PartialEq + Clone { #[inline] fn eq(&self, other: &Vec) -> bool { PartialEq::eq(&**self, &**other) } #[inline] fn ne(&self, other: &Vec) -> bool { PartialEq::ne(&**self, &**other) } } -impl<'a, A, B> PartialEq> for Vec where A: Clone, B: PartialEq { +impl<'a, A, B> PartialEq> for Vec where A: Clone, B: PartialEq { #[inline] - fn eq(&self, other: &CowVec<'a, A>) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) } #[inline] - fn ne(&self, other: &CowVec<'a, A>) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) } } macro_rules! impl_eq_for_cowvec { ($rhs:ty) => { - impl<'a, 'b, A, B> PartialEq<$rhs> for CowVec<'a, A> where A: PartialEq + Clone { + impl<'a, 'b, A, B> PartialEq<$rhs> for Cow<'a, [A]> where A: PartialEq + Clone { #[inline] fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) } #[inline] fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) } } - impl<'a, 'b, A, B> PartialEq> for $rhs where A: Clone, B: PartialEq { + impl<'a, 'b, A, B> PartialEq> for $rhs where A: Clone, B: PartialEq { #[inline] - fn eq(&self, other: &CowVec<'a, A>) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) } #[inline] - fn ne(&self, other: &CowVec<'a, A>) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) } } } } @@ -1552,8 +1553,7 @@ macro_rules! impl_eq_for_cowvec { impl_eq_for_cowvec! { &'b [B] } impl_eq_for_cowvec! { &'b mut [B] } -#[unstable(feature = "collections", - reason = "waiting on PartialOrd stability")] +#[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] fn partial_cmp(&self, other: &Vec) -> Option { @@ -1561,10 +1561,10 @@ impl PartialOrd for Vec { } } -#[unstable(feature = "collections", reason = "waiting on Eq stability")] +#[stable(feature = "rust1", since = "1.0.0")] impl Eq for Vec {} -#[unstable(feature = "collections", reason = "waiting on Ord stability")] +#[stable(feature = "rust1", since = "1.0.0")] impl Ord for Vec { #[inline] fn cmp(&self, other: &Vec) -> Ordering { @@ -1643,26 +1643,26 @@ impl fmt::Debug for Vec { // Clone-on-write //////////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "collections", - reason = "unclear how valuable this alias is")] /// A clone-on-write vector -pub type CowVec<'a, T> = Cow<'a, Vec, [T]>; +#[deprecated(since = "1.0.0", reason = "use Cow<'a, [T]> instead")] +#[unstable(feature = "collections")] +pub type CowVec<'a, T> = Cow<'a, [T]>; #[unstable(feature = "collections")] -impl<'a, T> FromIterator for CowVec<'a, T> where T: Clone { +impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { fn from_iter>(it: I) -> CowVec<'a, T> { Cow::Owned(FromIterator::from_iter(it)) } } -impl<'a, T: 'a> IntoCow<'a, Vec, [T]> for Vec where T: Clone { - fn into_cow(self) -> CowVec<'a, T> { +impl<'a, T: 'a> IntoCow<'a, [T]> for Vec where T: Clone { + fn into_cow(self) -> Cow<'a, [T]> { Cow::Owned(self) } } -impl<'a, T> IntoCow<'a, Vec, [T]> for &'a [T] where T: Clone { - fn into_cow(self) -> CowVec<'a, T> { +impl<'a, T> IntoCow<'a, [T]> for &'a [T] where T: Clone { + fn into_cow(self) -> Cow<'a, [T]> { Cow::Borrowed(self) } } diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs deleted file mode 100644 index 035443e9c3f35..0000000000000 --- a/src/libcore/borrow.rs +++ /dev/null @@ -1,265 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A module for working with borrowed data. -//! -//! # The `BorrowFrom` traits -//! -//! In general, there may be several ways to "borrow" a piece of data. The -//! typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` -//! (a mutable borrow). But types like `Vec` provide additional kinds of -//! borrows: the borrowed slices `&[T]` and `&mut [T]`. -//! -//! When writing generic code, it is often desirable to abstract over all ways -//! of borrowing data from a given type. That is the role of the `BorrowFrom` -//! trait: if `T: BorrowFrom`, then `&T` can be borrowed from `&U`. A given -//! type can be borrowed as multiple different types. In particular, `Vec: -//! BorrowFrom>` and `[T]: BorrowFrom>`. -//! -//! # The `ToOwned` trait -//! -//! Some types make it possible to go from borrowed to owned, usually by -//! implementing the `Clone` trait. But `Clone` works only for going from `&T` -//! to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data -//! from any borrow of a given type. -//! -//! # The `Cow` (clone-on-write) type -//! -//! The type `Cow` is a smart pointer providing clone-on-write functionality: it -//! can enclose and provide immutable access to borrowed data, and clone the -//! data lazily when mutation or ownership is required. The type is designed to -//! work with general borrowed data via the `BorrowFrom` trait. -//! -//! `Cow` implements both `Deref`, which means that you can call -//! non-mutating methods directly on the data it encloses. If mutation -//! is desired, `to_mut` will obtain a mutable references to an owned -//! value, cloning if necessary. - -#![unstable(feature = "core", - reason = "recently added as part of collections reform")] - -use clone::Clone; -use cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; -use fmt; -use marker::Sized; -use ops::Deref; -use option::Option; -use self::Cow::*; - -/// A trait for borrowing data. -#[old_orphan_check] -pub trait BorrowFrom { - /// Immutably borrow from an owned value. - fn borrow_from(owned: &Owned) -> &Self; -} - -/// A trait for mutably borrowing data. -#[old_orphan_check] -pub trait BorrowFromMut : BorrowFrom { - /// Mutably borrow from an owned value. - fn borrow_from_mut(owned: &mut Owned) -> &mut Self; -} - -impl BorrowFrom for T { - fn borrow_from(owned: &T) -> &T { owned } -} - -impl BorrowFromMut for T { - fn borrow_from_mut(owned: &mut T) -> &mut T { owned } -} - -impl<'a, T: ?Sized> BorrowFrom<&'a T> for T { - fn borrow_from<'b>(owned: &'b &'a T) -> &'b T { &**owned } -} - -impl<'a, T: ?Sized> BorrowFrom<&'a mut T> for T { - fn borrow_from<'b>(owned: &'b &'a mut T) -> &'b T { &**owned } -} - -impl<'a, T: ?Sized> BorrowFromMut<&'a mut T> for T { - fn borrow_from_mut<'b>(owned: &'b mut &'a mut T) -> &'b mut T { &mut **owned } -} - -impl<'a, T, B: ?Sized> BorrowFrom> for B where B: ToOwned { - fn borrow_from<'b>(owned: &'b Cow<'a, T, B>) -> &'b B { - &**owned - } -} - -/// Trait for moving into a `Cow` -#[old_orphan_check] -pub trait IntoCow<'a, T, B: ?Sized> { - /// Moves `self` into `Cow` - fn into_cow(self) -> Cow<'a, T, B>; -} - -impl<'a, T, B: ?Sized> IntoCow<'a, T, B> for Cow<'a, T, B> where B: ToOwned { - fn into_cow(self) -> Cow<'a, T, B> { - self - } -} - -/// A generalization of Clone to borrowed data. -#[old_orphan_check] -pub trait ToOwned: BorrowFrom { - /// Create owned data from borrowed data, usually by copying. - fn to_owned(&self) -> Owned; -} - -impl ToOwned for T where T: Clone { - fn to_owned(&self) -> T { self.clone() } -} - -/// A clone-on-write smart pointer. -/// -/// # Example -/// -/// ```rust -/// use std::borrow::Cow; -/// -/// fn abs_all(input: &mut Cow, [int]>) { -/// for i in 0..input.len() { -/// let v = input[i]; -/// if v < 0 { -/// // clones into a vector the first time (if not already owned) -/// input.to_mut()[i] = -v; -/// } -/// } -/// } -/// ``` -pub enum Cow<'a, T, B: ?Sized + 'a> where B: ToOwned { - /// Borrowed data. - Borrowed(&'a B), - - /// Owned data. - Owned(T) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> Clone for Cow<'a, T, B> where B: ToOwned { - fn clone(&self) -> Cow<'a, T, B> { - match *self { - Borrowed(b) => Borrowed(b), - Owned(ref o) => { - let b: &B = BorrowFrom::borrow_from(o); - Owned(b.to_owned()) - }, - } - } -} - -impl<'a, T, B: ?Sized> Cow<'a, T, B> where B: ToOwned { - /// Acquire a mutable reference to the owned form of the data. - /// - /// Copies the data if it is not already owned. - pub fn to_mut(&mut self) -> &mut T { - match *self { - Borrowed(borrowed) => { - *self = Owned(borrowed.to_owned()); - self.to_mut() - } - Owned(ref mut owned) => owned - } - } - - /// Extract the owned data. - /// - /// Copies the data if it is not already owned. - pub fn into_owned(self) -> T { - match self { - Borrowed(borrowed) => borrowed.to_owned(), - Owned(owned) => owned - } - } - - /// Returns true if this `Cow` wraps a borrowed value - pub fn is_borrowed(&self) -> bool { - match *self { - Borrowed(_) => true, - _ => false, - } - } - - /// Returns true if this `Cow` wraps an owned value - pub fn is_owned(&self) -> bool { - match *self { - Owned(_) => true, - _ => false, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> Deref for Cow<'a, T, B> where B: ToOwned { - type Target = B; - - fn deref(&self) -> &B { - match *self { - Borrowed(borrowed) => borrowed, - Owned(ref owned) => BorrowFrom::borrow_from(owned) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> Eq for Cow<'a, T, B> where B: Eq + ToOwned {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> Ord for Cow<'a, T, B> where B: Ord + ToOwned { - #[inline] - fn cmp(&self, other: &Cow<'a, T, B>) -> Ordering { - Ord::cmp(&**self, &**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T, U, B: ?Sized, C: ?Sized> PartialEq> for Cow<'a, T, B> where - B: PartialEq + ToOwned, - C: ToOwned, -{ - #[inline] - fn eq(&self, other: &Cow<'b, U, C>) -> bool { - PartialEq::eq(&**self, &**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> PartialOrd for Cow<'a, T, B> where B: PartialOrd + ToOwned { - #[inline] - fn partial_cmp(&self, other: &Cow<'a, T, B>) -> Option { - PartialOrd::partial_cmp(&**self, &**other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> fmt::Debug for Cow<'a, T, B> where - B: fmt::Debug + ToOwned, - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Borrowed(ref b) => fmt::Debug::fmt(b, f), - Owned(ref o) => fmt::Debug::fmt(o, f), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, B: ?Sized> fmt::Display for Cow<'a, T, B> where - B: fmt::Display + ToOwned, - T: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Borrowed(ref b) => fmt::Display::fmt(b, f), - Owned(ref o) => fmt::Display::fmt(o, f), - } - } -} diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index a5d2618eff948..28e14836a0492 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -61,7 +61,6 @@ use prelude::*; -use borrow::{Cow, ToOwned}; use default::Default; use mem; use num::Int; @@ -243,12 +242,3 @@ impl Hash for *mut T { (*self as uint).hash(state); } } - -impl<'a, T, B: ?Sized, S: Hasher> Hash for Cow<'a, T, B> - where B: Hash + ToOwned -{ - #[inline] - fn hash(&self, state: &mut S) { - Hash::hash(&**self, state) - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index f0c60ffe4bf66..3c58480ff0cfa 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -126,7 +126,6 @@ pub mod default; pub mod any; pub mod atomic; -pub mod borrow; pub mod cell; pub mod char; pub mod panicking; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 230deabee0034..f620a1ca90836 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -275,15 +275,12 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![feature(int_uint)] #![feature(collections)] -#![feature(core)] #![feature(old_io)] use self::LabelText::*; -use std::borrow::IntoCow; +use std::borrow::{Cow, IntoCow}; use std::old_io; -use std::string::CowString; -use std::vec::CowVec; /// The text for a graphviz label on a node or edge. pub enum LabelText<'a> { @@ -291,7 +288,7 @@ pub enum LabelText<'a> { /// /// Occurrences of backslashes (`\`) are escaped, and thus appear /// as backslashes in the rendered label. - LabelStr(CowString<'a>), + LabelStr(Cow<'a, str>), /// This kind of label uses the graphviz label escString type: /// http://www.graphviz.org/content/attrs#kescString @@ -303,7 +300,7 @@ pub enum LabelText<'a> { /// to break a line (centering the line preceding the `\n`), there /// are also the escape sequences `\l` which left-justifies the /// preceding line and `\r` which right-justifies it. - EscStr(CowString<'a>), + EscStr(Cow<'a, str>), } // There is a tension in the design of the labelling API. @@ -340,7 +337,7 @@ pub enum LabelText<'a> { /// `Id` is a Graphviz `ID`. pub struct Id<'a> { - name: CowString<'a>, + name: Cow<'a, str>, } impl<'a> Id<'a> { @@ -358,7 +355,7 @@ impl<'a> Id<'a> { /// /// Passing an invalid string (containing spaces, brackets, /// quotes, ...) will return an empty `Err` value. - pub fn new>(name: Name) -> Result, ()> { + pub fn new>(name: Name) -> Result, ()> { let name = name.into_cow(); { let mut chars = name.chars(); @@ -387,7 +384,7 @@ impl<'a> Id<'a> { &*self.name } - pub fn name(self) -> CowString<'a> { + pub fn name(self) -> Cow<'a, str> { self.name } } @@ -427,11 +424,11 @@ pub trait Labeller<'a,N,E> { } impl<'a> LabelText<'a> { - pub fn label>(s: S) -> LabelText<'a> { + pub fn label>(s: S) -> LabelText<'a> { LabelStr(s.into_cow()) } - pub fn escaped>(s: S) -> LabelText<'a> { + pub fn escaped>(s: S) -> LabelText<'a> { EscStr(s.into_cow()) } @@ -463,7 +460,7 @@ impl<'a> LabelText<'a> { /// yields same content as self. The result obeys the law /// render(`lt`) == render(`EscStr(lt.pre_escaped_content())`) for /// all `lt: LabelText`. - fn pre_escaped_content(self) -> CowString<'a> { + fn pre_escaped_content(self) -> Cow<'a, str> { match self { EscStr(s) => s, LabelStr(s) => if s.contains_char('\\') { @@ -489,8 +486,8 @@ impl<'a> LabelText<'a> { } } -pub type Nodes<'a,N> = CowVec<'a,N>; -pub type Edges<'a,E> = CowVec<'a,E>; +pub type Nodes<'a,N> = Cow<'a,[N]>; +pub type Edges<'a,E> = Cow<'a,[E]>; // (The type parameters in GraphWalk should be associated items, // when/if Rust supports such.) @@ -505,7 +502,7 @@ pub type Edges<'a,E> = CowVec<'a,E>; /// that is bound by the self lifetime `'a`. /// /// The `nodes` and `edges` method each return instantiations of -/// `CowVec` to leave implementers the freedom to create +/// `Cow<[_]>` to leave implementers the freedom to create /// entirely new vectors or to pass back slices into internally owned /// vectors. pub trait GraphWalk<'a, N, E> { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5cc7502b5128d..8dbac7f515ea8 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -838,7 +838,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // the method call infrastructure should have // replaced all late-bound regions with variables: let self_ty = ty::ty_fn_sig(method_ty).input(0); - let self_ty = ty::assert_no_late_bound_regions(self.tcx(), &self_ty); + let self_ty = ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap(); let (m, r) = match self_ty.sty { ty::ty_rptr(r, ref m) => (m.mutbl, r), diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 923f7d2d4ef35..235f3f994c65e 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -212,7 +212,7 @@ impl UnificationTable { } } -impl sv::SnapshotVecDelegate for Delegate { +impl sv::SnapshotVecDelegate for Delegate { type Value = VarValue; type Undo = (); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6c295142c9f32..4be7bb9c365a1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -281,7 +281,6 @@ pub type McResult = Result; /// know that no errors have occurred, so we simply consult the tcx and we /// can be sure that only `Ok` results will occur. pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; fn node_ty(&self, id: ast::NodeId) -> McResult>; fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult>; fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool; @@ -905,8 +904,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { let base_cmt = match method_ty { Some(method_ty) => { let ref_ty = - ty::assert_no_late_bound_regions( - self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap(); + ty::no_late_bound_regions( + self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); self.cat_rvalue_node(node.id(), node.span(), ref_ty) } None => base_cmt @@ -996,7 +995,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // FIXME(#20649) -- why are we using the `self_ty` as the element type...? let self_ty = ty::ty_fn_sig(method_ty).input(0); - ty::assert_no_late_bound_regions(self.tcx(), &self_ty) + ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap() } None => { match ty::array_element_ty(self.tcx(), base_cmt.ty) { @@ -1336,8 +1335,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // types are generated by method resolution and always have // all late-bound regions fully instantiated, so we just want // to skip past the binder. - ty::assert_no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty)) - .unwrap() // overloaded ops do not diverge, either + ty::no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty)) + .unwrap() + .unwrap() // overloaded ops do not diverge, either } } diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 07c7453783d95..a9cac4be3e368 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -9,7 +9,6 @@ // except according to those terms. use middle::infer::{InferCtxt}; -use middle::mem_categorization::Typer; use middle::ty::{self, RegionEscape, Ty}; use std::collections::HashSet; use std::collections::hash_map::Entry::{Occupied, Vacant}; diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 83090dd72aa94..57c9fa7a4d964 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -15,9 +15,9 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; -use middle::mem_categorization::Typer; use middle::subst; -use middle::ty::{self, Ty}; +use middle::ty::{self, HasProjectionTypes, Ty}; +use middle::ty_fold::TypeFoldable; use middle::infer::{self, InferCtxt}; use std::slice::Iter; use std::rc::Rc; @@ -432,18 +432,8 @@ pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx debug!("normalize_param_env(param_env={})", param_env.repr(tcx)); - let predicates: Vec> = { - let infcx = infer::new_infer_ctxt(tcx); - let mut selcx = &mut SelectionContext::new(&infcx, param_env); - let mut fulfill_cx = FulfillmentContext::new(); - let Normalized { value: predicates, obligations } = - project::normalize(selcx, cause, ¶m_env.caller_bounds); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); - } - try!(fulfill_cx.select_all_or_error(selcx.infcx(), param_env)); - predicates.iter().map(|p| infcx.resolve_type_vars_if_possible(p)).collect() - }; + let infcx = infer::new_infer_ctxt(tcx); + let predicates = try!(fully_normalize(&infcx, param_env, cause, ¶m_env.caller_bounds)); debug!("normalize_param_env: predicates={}", predicates.repr(tcx)); @@ -451,6 +441,35 @@ pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx Ok(param_env.with_caller_bounds(predicates)) } +pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + closure_typer: &ty::ClosureTyper<'tcx>, + cause: ObligationCause<'tcx>, + value: &T) + -> Result>> + where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx> +{ + let tcx = closure_typer.tcx(); + + debug!("normalize_param_env(value={})", + value.repr(tcx)); + + let mut selcx = &mut SelectionContext::new(infcx, closure_typer); + let mut fulfill_cx = FulfillmentContext::new(); + let Normalized { value: normalized_value, obligations } = + project::normalize(selcx, cause, value); + debug!("normalize_param_env: normalized_value={} obligations={}", + normalized_value.repr(tcx), + obligations.repr(tcx)); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); + } + try!(fulfill_cx.select_all_or_error(infcx, closure_typer)); + let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); + debug!("normalize_param_env: resolved_value={}", + resolved_value.repr(tcx)); + Ok(resolved_value) +} + impl<'tcx,O> Obligation<'tcx,O> { pub fn new(cause: ObligationCause<'tcx>, trait_ref: O) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 061557eb7dccd..027415de998df 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -32,7 +32,6 @@ use super::object_safety; use super::{util}; use middle::fast_reject; -use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace}; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; @@ -653,8 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let is_dup = (0..candidates.len()) .filter(|&j| i != j) - .any(|j| self.candidate_should_be_dropped_in_favor_of(stack, - &candidates[i], + .any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])); if is_dup { debug!("Dropping candidate #{}/{}: {}", @@ -1236,31 +1234,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_predicates_recursively(stack, selection.iter_nested()) } - /// Returns true if `candidate_i` should be dropped in favor of `candidate_j`. - /// - /// This is generally true if either: - /// - candidate i and candidate j are equivalent; or, - /// - candidate i is a concrete impl and candidate j is a where clause bound, - /// and the concrete impl is applicable to the types in the where clause bound. - /// - /// The last case refers to cases where there are blanket impls (often conditional - /// blanket impls) as well as a where clause. This can come down to one of two cases: - /// - /// - The impl is truly unconditional (it has no where clauses - /// of its own), in which case the where clause is - /// unnecessary, because coherence requires that we would - /// pick that particular impl anyhow (at least so long as we - /// don't have specialization). - /// - /// - The impl is conditional, in which case we may not have winnowed it out - /// because we don't know if the conditions apply, but the where clause is basically - /// telling us that there is some impl, though not necessarily the one we see. - /// - /// In both cases we prefer to take the where clause, which is - /// essentially harmless. See issue #18453 for more details of - /// a case where doing the opposite caused us harm. + /// Returns true if `candidate_i` should be dropped in favor of + /// `candidate_j`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. fn candidate_should_be_dropped_in_favor_of<'o>(&mut self, - stack: &TraitObligationStack<'o, 'tcx>, candidate_i: &SelectionCandidate<'tcx>, candidate_j: &SelectionCandidate<'tcx>) -> bool @@ -1270,37 +1247,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match (candidate_i, candidate_j) { - (&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => { - debug!("Considering whether to drop param {} in favor of impl {}", - candidate_i.repr(self.tcx()), - candidate_j.repr(self.tcx())); - - self.infcx.probe(|snapshot| { - let (skol_obligation_trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions( - &stack.obligation.predicate, snapshot); - let impl_substs = - self.rematch_impl(impl_def_id, stack.obligation, snapshot, - &skol_map, skol_obligation_trait_ref.trait_ref.clone()); - let impl_trait_ref = - ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); - let impl_trait_ref = - impl_trait_ref.subst(self.tcx(), &impl_substs.value); - let poly_impl_trait_ref = - ty::Binder(impl_trait_ref); - let origin = - infer::RelateOutputImplTypes(stack.obligation.cause.span); - self.infcx - .sub_poly_trait_refs(false, origin, poly_impl_trait_ref, bound.clone()) - .is_ok() - }) - } - (&BuiltinCandidate(_), &ParamCandidate(_)) => { - // If we have a where-clause like `Option : Send`, - // then we wind up in a situation where there is a - // default rule (`Option:Send if K:Send) and the - // where-clause that both seem applicable. Just take - // the where-clause in that case. + (&ImplCandidate(..), &ParamCandidate(..)) | + (&ClosureCandidate(..), &ParamCandidate(..)) | + (&FnPointerCandidate(..), &ParamCandidate(..)) | + (&BuiltinCandidate(..), &ParamCandidate(..)) => { + // We basically prefer always prefer to use a + // where-clause over another option. Where clauses + // impose the burden of finding the exact match onto + // the caller. Using an impl in preference of a where + // clause can also lead us to "overspecialize", as in + // #18453. true } (&ProjectionCandidate, &ParamCandidate(_)) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8618bde95fe6f..e546719841f5f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -68,7 +68,7 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FnvHashMap}; use arena::TypedArena; -use std::borrow::{BorrowFrom, Cow}; +use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt; @@ -76,7 +76,6 @@ use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; use std::rc::Rc; -use std::vec::CowVec; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; use syntax::abi; @@ -986,9 +985,9 @@ impl<'tcx, S: Writer + Hasher> Hash for InternedTy<'tcx> { } } -impl<'tcx> BorrowFrom> for sty<'tcx> { - fn borrow_from<'a>(ty: &'a InternedTy<'tcx>) -> &'a sty<'tcx> { - &ty.ty.sty +impl<'tcx> Borrow> for InternedTy<'tcx> { + fn borrow<'a>(&'a self) -> &'a sty<'tcx> { + &self.ty.sty } } @@ -2337,6 +2336,10 @@ impl ClosureKind { } pub trait ClosureTyper<'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.param_env().tcx + } + fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>; /// Is this a `Fn`, `FnMut` or `FnOnce` closure? During typeck, @@ -4384,8 +4387,8 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, // overloaded deref operators have all late-bound // regions fully instantiated and coverge let fn_ret = - ty::assert_no_late_bound_regions(cx, - &ty_fn_ret(method_ty)); + ty::no_late_bound_regions(cx, + &ty_fn_ret(method_ty)).unwrap(); adjusted_ty = fn_ret.unwrap(); } None => {} @@ -5186,7 +5189,7 @@ impl<'tcx> VariantInfo<'tcx> { let arg_tys = if args.len() > 0 { // the regions in the argument types come from the // enum def'n, and hence will all be early bound - ty::assert_no_late_bound_regions(cx, &ty_fn_args(ctor_ty)) + ty::no_late_bound_regions(cx, &ty_fn_args(ctor_ty)).unwrap() } else { Vec::new() }; @@ -5561,7 +5564,7 @@ pub fn predicates<'tcx>( /// Get the attributes of a definition. pub fn get_attrs<'tcx>(tcx: &'tcx ctxt, did: DefId) - -> CowVec<'tcx, ast::Attribute> { + -> Cow<'tcx, [ast::Attribute]> { if is_local(did) { let item = tcx.map.expect_item(did.node); Cow::Borrowed(&item.attrs[]) @@ -6463,10 +6466,6 @@ impl<'tcx> ctxt<'tcx> { } impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.tcx - } - fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { Ok(ty::node_id_to_type(self.tcx, id)) } @@ -6677,14 +6676,17 @@ pub fn binds_late_bound_regions<'tcx, T>( count_late_bound_regions(tcx, value) > 0 } -pub fn assert_no_late_bound_regions<'tcx, T>( +pub fn no_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, value: &Binder) - -> T + -> Option where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone { - assert!(!binds_late_bound_regions(tcx, value)); - value.0.clone() + if binds_late_bound_regions(tcx, value) { + None + } else { + Some(value.0.clone()) + } } /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index da53e9fac1187..d0f5aa8cf003b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -16,7 +16,6 @@ use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector}; use borrowck::move_data::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Typer; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::middle::ty; use rustc::util::ppaux::Repr; diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 10ffb89e728ff..da5c847a04607 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -10,7 +10,6 @@ use borrowck::BorrowckCtxt; use rustc::middle::mem_categorization as mc; -use rustc::middle::mem_categorization::Typer; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::middle::ty; use rustc::util::ppaux::UserString; diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d658003702dca..3709490d8dad7 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -637,10 +637,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { } impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { - self.tcx() - } - fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { Ok(node_id_type(self, id)) } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 480679f43cb76..7a05cc5527662 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -781,8 +781,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ix_datum = unpack_datum!(bcx, trans(bcx, idx)); let ref_ty = // invoked methods have LB regions instantiated: - ty::assert_no_late_bound_regions( - bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap(); + ty::no_late_bound_regions( + bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); let elt_ty = match ty::deref(ref_ty, true) { None => { bcx.tcx().sess.span_bug(index_expr.span, @@ -2214,8 +2214,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let ref_ty = // invoked methods have their LB regions instantiated - ty::assert_no_late_bound_regions( - ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap(); + ty::no_late_bound_regions( + ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 81868f3695c28..0d30741978a5a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -509,7 +509,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let ctor_scheme = ty::lookup_item_type(tcx, enum_def); let ctor_predicates = ty::lookup_predicates(tcx, enum_def); let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) { - let fn_ret = ty::assert_no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)); + let fn_ret = ty::no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)).unwrap(); ty::TypeScheme { ty: fn_ret.unwrap(), generics: ctor_scheme.generics, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 6a9d34d7637b2..7354ea7377c36 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -367,8 +367,8 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { // (This always bites me, should find a way to // refactor it.) let method_sig = - ty::assert_no_late_bound_regions(fcx.tcx(), - ty::ty_fn_sig(method_callee.ty)); + ty::no_late_bound_regions(fcx.tcx(), + ty::ty_fn_sig(method_callee.ty)).unwrap(); debug!("attempt_resolution: method_callee={}", method_callee.repr(fcx.tcx())); diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/implicator.rs similarity index 55% rename from src/librustc_typeck/check/regionmanip.rs rename to src/librustc_typeck/check/implicator.rs index 209570585d29d..da25719baaa4a 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/implicator.rs @@ -10,52 +10,74 @@ // #![warn(deprecated_mode)] -pub use self::WfConstraint::*; - use astconv::object_region_bounds; -use middle::infer::GenericKind; -use middle::subst::{ParamSpace, Subst, Substs}; -use middle::ty::{self, Ty}; -use middle::ty_fold::{TypeFolder}; +use middle::infer::{InferCtxt, GenericKind}; +use middle::subst::{Substs}; +use middle::traits; +use middle::ty::{self, ToPolyTraitRef, Ty}; +use middle::ty_fold::{TypeFoldable, TypeFolder}; +use std::rc::Rc; use syntax::ast; +use syntax::codemap::Span; +use util::common::ErrorReported; use util::ppaux::Repr; // Helper functions related to manipulating region types. -pub enum WfConstraint<'tcx> { - RegionSubRegionConstraint(Option>, ty::Region, ty::Region), - RegionSubGenericConstraint(Option>, ty::Region, GenericKind<'tcx>), +pub enum Implication<'tcx> { + RegionSubRegion(Option>, ty::Region, ty::Region), + RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), + Predicate(ast::DefId, ty::Predicate<'tcx>), } -struct Wf<'a, 'tcx: 'a> { - tcx: &'a ty::ctxt<'tcx>, +struct Implicator<'a, 'tcx: 'a> { + infcx: &'a InferCtxt<'a,'tcx>, + closure_typer: &'a (ty::ClosureTyper<'tcx>+'a), + body_id: ast::NodeId, stack: Vec<(ty::Region, Option>)>, - out: Vec>, + span: Span, + out: Vec>, } /// This routine computes the well-formedness constraints that must hold for the type `ty` to /// appear in a context with lifetime `outer_region` -pub fn region_wf_constraints<'tcx>( - tcx: &ty::ctxt<'tcx>, +pub fn implications<'a,'tcx>( + infcx: &'a InferCtxt<'a,'tcx>, + closure_typer: &ty::ClosureTyper<'tcx>, + body_id: ast::NodeId, ty: Ty<'tcx>, - outer_region: ty::Region) - -> Vec> + outer_region: ty::Region, + span: Span) + -> Vec> { + debug!("implications(body_id={}, ty={}, outer_region={})", + body_id, + ty.repr(closure_typer.tcx()), + outer_region.repr(closure_typer.tcx())); + let mut stack = Vec::new(); stack.push((outer_region, None)); - let mut wf = Wf { tcx: tcx, - stack: stack, - out: Vec::new() }; + let mut wf = Implicator { closure_typer: closure_typer, + infcx: infcx, + body_id: body_id, + span: span, + stack: stack, + out: Vec::new() }; wf.accumulate_from_ty(ty); + debug!("implications: out={}", wf.out.repr(closure_typer.tcx())); wf.out } -impl<'a, 'tcx> Wf<'a, 'tcx> { +impl<'a, 'tcx> Implicator<'a, 'tcx> { + fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.infcx.tcx + } + fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) { - debug!("Wf::accumulate_from_ty(ty={})", - ty.repr(self.tcx)); + debug!("accumulate_from_ty(ty={})", + ty.repr(self.tcx())); match ty.sty { ty::ty_bool | @@ -96,13 +118,13 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { ty::ty_trait(ref t) => { let required_region_bounds = - object_region_bounds(self.tcx, &t.principal, t.bounds.builtin_bounds); + object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds); self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) } ty::ty_enum(def_id, substs) | ty::ty_struct(def_id, substs) => { - let item_scheme = ty::lookup_item_type(self.tcx, def_id); + let item_scheme = ty::lookup_item_type(self.tcx(), def_id); self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs) } @@ -141,9 +163,9 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { } ty::ty_open(_) => { - self.tcx.sess.bug( + self.tcx().sess.bug( &format!("Unexpected type encountered while doing wf check: {}", - ty.repr(self.tcx))[]); + ty.repr(self.tcx()))[]); } } } @@ -197,7 +219,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { opt_ty: Option>, r_a: ty::Region, r_b: ty::Region) { - self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b)); + self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b)); } /// Pushes a constraint that `param_ty` must outlive the top region on the stack. @@ -211,7 +233,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { fn push_projection_constraint_from_top(&mut self, projection_ty: &ty::ProjectionTy<'tcx>) { let &(region, opt_ty) = self.stack.last().unwrap(); - self.out.push(RegionSubGenericConstraint( + self.out.push(Implication::RegionSubGeneric( opt_ty, region, GenericKind::Projection(projection_ty.clone()))); } @@ -220,110 +242,120 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { region: ty::Region, opt_ty: Option>, param_ty: ty::ParamTy) { - self.out.push(RegionSubGenericConstraint( + self.out.push(Implication::RegionSubGeneric( opt_ty, region, GenericKind::Param(param_ty))); } fn accumulate_from_adt(&mut self, ty: Ty<'tcx>, def_id: ast::DefId, - generics: &ty::Generics<'tcx>, + _generics: &ty::Generics<'tcx>, substs: &Substs<'tcx>) { - // The generic declarations from the type, appropriately - // substituted for the actual substitutions. - let generics = generics.subst(self.tcx, substs); - - // Variance of each type/region parameter. - let variances = ty::item_variances(self.tcx, def_id); - - for &space in &ParamSpace::all() { - let region_params = substs.regions().get_slice(space); - let region_variances = variances.regions.get_slice(space); - let region_param_defs = generics.regions.get_slice(space); - assert_eq!(region_params.len(), region_variances.len()); - for (®ion_param, (®ion_variance, region_param_def)) in - region_params.iter().zip( - region_variances.iter().zip( - region_param_defs.iter())) - { - match region_variance { - ty::Covariant | ty::Bivariant => { - // Ignore covariant or bivariant region - // parameters. To understand why, consider a - // struct `Foo<'a>`. If `Foo` contains any - // references with lifetime `'a`, then `'a` must - // be at least contravariant (and possibly - // invariant). The only way to have a covariant - // result is if `Foo` contains only a field with a - // type like `fn() -> &'a T`; i.e., a bare - // function that can produce a reference of - // lifetime `'a`. In this case, there is no - // *actual data* with lifetime `'a` that is - // reachable. (Presumably this bare function is - // really returning static data.) - } - - ty::Contravariant | ty::Invariant => { - // If the parameter is contravariant or - // invariant, there may indeed be reachable - // data with this lifetime. See other case for - // more details. - self.push_region_constraint_from_top(region_param); + let predicates = + ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs); + let predicates = match self.fully_normalize(&predicates) { + Ok(predicates) => predicates, + Err(ErrorReported) => { return; } + }; + + for predicate in predicates.predicates.as_slice() { + match *predicate { + ty::Predicate::Trait(ref data) => { + self.accumulate_from_assoc_types_transitive(data); + } + ty::Predicate::Equate(..) => { } + ty::Predicate::Projection(..) => { } + ty::Predicate::RegionOutlives(ref data) => { + match ty::no_late_bound_regions(self.tcx(), data) { + None => { } + Some(ty::OutlivesPredicate(r_a, r_b)) => { + self.push_sub_region_constraint(Some(ty), r_b, r_a); + } } } - - for ®ion_bound in ®ion_param_def.bounds { - // The type declared a constraint like - // - // 'b : 'a - // - // which means that `'a <= 'b` (after - // substitution). So take the region we - // substituted for `'a` (`region_bound`) and make - // it a subregion of the region we substituted - // `'b` (`region_param`). - self.push_sub_region_constraint( - Some(ty), region_bound, region_param); + ty::Predicate::TypeOutlives(ref data) => { + match ty::no_late_bound_regions(self.tcx(), data) { + None => { } + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + self.stack.push((r_b, Some(ty))); + self.accumulate_from_ty(ty_a); + self.stack.pop().unwrap(); + } + } } } + } - let types = substs.types.get_slice(space); - let type_variances = variances.types.get_slice(space); - let type_param_defs = generics.types.get_slice(space); - assert_eq!(types.len(), type_variances.len()); - for (&type_param_ty, (&variance, type_param_def)) in - types.iter().zip( - type_variances.iter().zip( - type_param_defs.iter())) - { - debug!("type_param_ty={} variance={}", - type_param_ty.repr(self.tcx), - variance.repr(self.tcx)); - - match variance { - ty::Contravariant | ty::Bivariant => { - // As above, except that in this it is a - // *contravariant* reference that indices that no - // actual data of type T is reachable. - } + let obligations = predicates.predicates + .into_iter() + .map(|pred| Implication::Predicate(def_id, pred)); + self.out.extend(obligations); - ty::Covariant | ty::Invariant => { - self.accumulate_from_ty(type_param_ty); - } + let variances = ty::item_variances(self.tcx(), def_id); + + for (®ion, &variance) in substs.regions().iter().zip(variances.regions.iter()) { + match variance { + ty::Contravariant | ty::Invariant => { + // If any data with this lifetime is reachable + // within, it must be at least contravariant. + self.push_region_constraint_from_top(region) } + ty::Covariant | ty::Bivariant => { } + } + } - // Inspect bounds on this type parameter for any - // region bounds. - for &r in &type_param_def.bounds.region_bounds { - self.stack.push((r, Some(ty))); - self.accumulate_from_ty(type_param_ty); - self.stack.pop().unwrap(); + for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) { + match variance { + ty::Covariant | ty::Invariant => { + // If any data of this type is reachable within, + // it must be at least covariant. + self.accumulate_from_ty(ty); } + ty::Contravariant | ty::Bivariant => { } + } + } + } + + /// Given that there is a requirement that `Foo : 'a`, where + /// `Foo` is declared like `struct Foo where T : SomeTrait`, + /// this code finds all the associated types defined in + /// `SomeTrait` (and supertraits) and adds a requirement that `::N : 'a` (where `N` is some associated type + /// defined in `SomeTrait`). This rule only applies to + /// trait-bounds that are not higher-ranked, because we cannot + /// project out of a HRTB. This rule helps code using associated + /// types to compile, see Issue #22246 for an example. + fn accumulate_from_assoc_types_transitive(&mut self, + data: &ty::PolyTraitPredicate<'tcx>) + { + for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) { + match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) { + Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); } + None => { } } } } + fn accumulate_from_assoc_types(&mut self, + trait_ref: Rc>) + { + let trait_def_id = trait_ref.def_id; + let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + let assoc_type_projections: Vec<_> = + trait_def.associated_type_names + .iter() + .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name)) + .collect(); + let tys = match self.fully_normalize(&assoc_type_projections) { + Ok(tys) => { tys } + Err(ErrorReported) => { return; } + }; + for ty in tys { + self.accumulate_from_ty(ty); + } + } + fn accumulate_from_object_ty(&mut self, ty: Ty<'tcx>, region_bound: ty::Region, @@ -372,25 +404,53 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { for &r_d in &required_region_bounds { // Each of these is an instance of the `'c <= 'b` // constraint above - self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c)); + self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c)); + } + } + + fn fully_normalize(&self, value: &T) -> Result + where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx> + { + let value = + traits::fully_normalize(self.infcx, + self.closure_typer, + traits::ObligationCause::misc(self.span, self.body_id), + value); + match value { + Ok(value) => Ok(value), + Err(errors) => { + // I don't like reporting these errors here, but I + // don't know where else to report them just now. And + // I don't really expect errors to arise here + // frequently. I guess the best option would be to + // propagate them out. + traits::report_fulfillment_errors(self.infcx, &errors); + Err(ErrorReported) + } } } } -impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> { +impl<'tcx> Repr<'tcx> for Implication<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { - RegionSubRegionConstraint(_, ref r_a, ref r_b) => { - format!("RegionSubRegionConstraint({}, {})", + Implication::RegionSubRegion(_, ref r_a, ref r_b) => { + format!("RegionSubRegion({}, {})", r_a.repr(tcx), r_b.repr(tcx)) } - RegionSubGenericConstraint(_, ref r, ref p) => { - format!("RegionSubGenericConstraint({}, {})", + Implication::RegionSubGeneric(_, ref r, ref p) => { + format!("RegionSubGeneric({}, {})", r.repr(tcx), p.repr(tcx)) } + + Implication::Predicate(ref def_id, ref p) => { + format!("Predicate({}, {})", + def_id.repr(tcx), + p.repr(tcx)) + } } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 30896c1607a88..3c2888e227803 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -131,7 +131,7 @@ pub mod dropck; pub mod _match; pub mod vtable; pub mod writeback; -pub mod regionmanip; +pub mod implicator; pub mod regionck; pub mod coercion; pub mod demand; @@ -309,9 +309,6 @@ pub struct FnCtxt<'a, 'tcx: 'a> { } impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } fn node_ty(&self, id: ast::NodeId) -> McResult> { let ty = self.node_ty(id); self.resolve_type_vars_or_error(&ty) @@ -484,7 +481,8 @@ pub fn check_item_types(ccx: &CrateCtxt) { fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &'tcx ast::FnDecl, body: &'tcx ast::Block, - id: ast::NodeId, + fn_id: ast::NodeId, + fn_span: Span, raw_fty: Ty<'tcx>, param_env: ty::ParameterEnvironment<'a, 'tcx>) { @@ -502,13 +500,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fn_sig = inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig); - let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig, - decl, id, body, &inh); + let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig, + decl, fn_id, body, &inh); vtable::select_all_fcx_obligations_and_apply_defaults(&fcx); - upvar::closure_analyze_fn(&fcx, id, decl, body); + upvar::closure_analyze_fn(&fcx, fn_id, decl, body); vtable::select_all_fcx_obligations_or_error(&fcx); - regionck::regionck_fn(&fcx, id, decl, body); + regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); } _ => ccx.tcx.sess.impossible_case(body.span, @@ -721,7 +719,7 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { ast::ItemFn(ref decl, _, _, _, ref body) => { let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); - check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env); + check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); } ast::ItemImpl(_, _, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); @@ -868,6 +866,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &*method.pe_fn_decl(), &*method.pe_body(), method.id, + method.span, fty, param_env); } @@ -2050,8 +2049,8 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match method { Some(method) => { let ref_ty = // invoked methods have all LB regions instantiated - ty::assert_no_late_bound_regions( - fcx.tcx(), &ty::ty_fn_ret(method.ty)); + ty::no_late_bound_regions( + fcx.tcx(), &ty::ty_fn_ret(method.ty)).unwrap(); match method_call { Some(method_call) => { fcx.inh.method_map.borrow_mut().insert(method_call, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 17c259e674e9f..4e5550a2106a9 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -85,7 +85,7 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; -use check::regionmanip; +use check::implicator; use check::vtable; use middle::def; use middle::mem_categorization as mc; @@ -97,12 +97,12 @@ use middle::infer::{self, GenericKind}; use middle::pat_util; use util::ppaux::{ty_to_string, Repr}; +use std::mem; use syntax::{ast, ast_util}; use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; -use self::RepeatingScope::Repeating; use self::SubjectNode::Subject; // a variation on try that just returns unit @@ -114,7 +114,7 @@ macro_rules! ignore_err { // PUBLIC ENTRY POINTS pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx::new(fcx, Repeating(e.id), Subject(e.id)); + let mut rcx = Rcx::new(fcx, RepeatingScope(e.id), e.id, Subject(e.id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e); @@ -124,22 +124,23 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { } pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, Repeating(item.id), Subject(item.id)); + let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id)); rcx.visit_region_obligations(item.id); rcx.resolve_regions_and_report_errors(); } -pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast::Block) { - let mut rcx = Rcx::new(fcx, Repeating(blk.id), Subject(id)); +pub fn regionck_fn(fcx: &FnCtxt, + fn_id: ast::NodeId, + fn_span: Span, + decl: &ast::FnDecl, + blk: &ast::Block) { + debug!("regionck_fn(id={})", fn_id); + let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded - rcx.visit_fn_body(id, decl, blk); + rcx.visit_fn_body(fn_id, decl, blk, fn_span); } - // Region checking a fn can introduce new trait obligations, - // particularly around closure bounds. - vtable::select_all_fcx_obligations_or_error(fcx); - rcx.resolve_regions_and_report_errors(); } @@ -148,7 +149,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast: pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, component_tys: &[Ty<'tcx>]) { - let mut rcx = Rcx::new(fcx, Repeating(0), SubjectNode::None); + let mut rcx = Rcx::new(fcx, RepeatingScope(0), 0, SubjectNode::None); for &component_ty in component_tys { // Check that each type outlives the empty region. Since the // empty region is a subregion of all others, this can't fail @@ -167,6 +168,9 @@ pub struct Rcx<'a, 'tcx: 'a> { region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>, + // id of innermost fn body id + body_id: ast::NodeId, + // id of innermost fn or loop repeating_scope: ast::NodeId, @@ -189,16 +193,18 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { } } -pub enum RepeatingScope { Repeating(ast::NodeId) } +struct RepeatingScope(ast::NodeId); pub enum SubjectNode { Subject(ast::NodeId), None } impl<'a, 'tcx> Rcx<'a, 'tcx> { pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, initial_repeating_scope: RepeatingScope, + initial_body_id: ast::NodeId, subject: SubjectNode) -> Rcx<'a, 'tcx> { - let Repeating(initial_repeating_scope) = initial_repeating_scope; + let RepeatingScope(initial_repeating_scope) = initial_repeating_scope; Rcx { fcx: fcx, repeating_scope: initial_repeating_scope, + body_id: initial_body_id, subject: subject, region_bound_pairs: Vec::new() } @@ -208,10 +214,12 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.fcx.ccx.tcx } - pub fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId { - let old_scope = self.repeating_scope; - self.repeating_scope = scope; - old_scope + fn set_body_id(&mut self, body_id: ast::NodeId) -> ast::NodeId { + mem::replace(&mut self.body_id, body_id) + } + + fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId { + mem::replace(&mut self.repeating_scope, scope) } /// Try to resolve the type for the given node, returning t_err if an error results. Note that @@ -269,9 +277,11 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { fn visit_fn_body(&mut self, id: ast::NodeId, fn_decl: &ast::FnDecl, - body: &ast::Block) + body: &ast::Block, + span: Span) { // When we enter a function, we can derive + debug!("visit_fn_body(id={})", id); let fn_sig_map = self.fcx.inh.fn_sig_map.borrow(); let fn_sig = match fn_sig_map.get(&id) { @@ -283,17 +293,24 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { }; let len = self.region_bound_pairs.len(); - self.relate_free_regions(&fn_sig[], body.id); + let old_body_id = self.set_body_id(body.id); + self.relate_free_regions(&fn_sig[], body.id, span); link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[]); self.visit_block(body); self.visit_region_obligations(body.id); self.region_bound_pairs.truncate(len); + self.set_body_id(old_body_id); } fn visit_region_obligations(&mut self, node_id: ast::NodeId) { debug!("visit_region_obligations: node_id={}", node_id); + // region checking can introduce new pending obligations + // which, when processed, might generate new region + // obligations. So make sure we process those. + vtable::select_all_fcx_obligations_or_error(self.fcx); + // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. let region_obligations = @@ -326,7 +343,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` fn relate_free_regions(&mut self, fn_sig_tys: &[Ty<'tcx>], - body_id: ast::NodeId) { + body_id: ast::NodeId, + span: Span) { debug!("relate_free_regions >>"); let tcx = self.tcx(); @@ -335,25 +353,22 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("relate_free_regions(t={})", ty.repr(tcx)); let body_scope = CodeExtent::from_node_id(body_id); let body_scope = ty::ReScope(body_scope); - let constraints = - regionmanip::region_wf_constraints( - tcx, - ty, - body_scope); - for constraint in &constraints { - debug!("constraint: {}", constraint.repr(tcx)); - match *constraint { - regionmanip::RegionSubRegionConstraint(_, - ty::ReFree(free_a), - ty::ReFree(free_b)) => { + let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id, + ty, body_scope, span); + for implication in implications { + debug!("implication: {}", implication.repr(tcx)); + match implication { + implicator::Implication::RegionSubRegion(_, + ty::ReFree(free_a), + ty::ReFree(free_b)) => { tcx.region_maps.relate_free_regions(free_a, free_b); } - regionmanip::RegionSubRegionConstraint(_, - ty::ReFree(free_a), - ty::ReInfer(ty::ReVar(vid_b))) => { + implicator::Implication::RegionSubRegion(_, + ty::ReFree(free_a), + ty::ReInfer(ty::ReVar(vid_b))) => { self.fcx.inh.infcx.add_given(free_a, vid_b); } - regionmanip::RegionSubRegionConstraint(..) => { + implicator::Implication::RegionSubRegion(..) => { // In principle, we could record (and take // advantage of) every relationship here, but // we are also free not to -- it simply means @@ -364,12 +379,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // relationship that arises here, but // presently we do not.) } - regionmanip::RegionSubGenericConstraint(_, r_a, ref generic_b) => { - debug!("RegionSubGenericConstraint: {} <= {}", + implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { + debug!("RegionSubGeneric: {} <= {}", r_a.repr(tcx), generic_b.repr(tcx)); self.region_bound_pairs.push((r_a, generic_b.clone())); } + implicator::Implication::Predicate(..) => { } } } } @@ -400,8 +416,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> { // regions, until regionck, as described in #3238. fn visit_fn(&mut self, _fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, - b: &'v ast::Block, _s: Span, id: ast::NodeId) { - self.visit_fn_body(id, fd, b) + b: &'v ast::Block, span: Span, id: ast::NodeId) { + self.visit_fn_body(id, fd, b, span) } fn visit_item(&mut self, i: &ast::Item) { visit_item(self, i); } @@ -628,7 +644,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { constrain_call(rcx, expr, Some(&**base), None::.iter(), true); let fn_ret = // late-bound regions in overloaded method calls are instantiated - ty::assert_no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method.ty)); + ty::no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method.ty)).unwrap(); fn_ret.unwrap() } None => rcx.resolve_node_type(base.id) @@ -975,7 +991,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // was applied on the base type, as that is always the case. let fn_sig = ty::ty_fn_sig(method.ty); let fn_sig = // late-bound regions should have been instantiated - ty::assert_no_late_bound_regions(rcx.tcx(), fn_sig); + ty::no_late_bound_regions(rcx.tcx(), fn_sig).unwrap(); let self_ty = fn_sig.inputs[0]; let (m, r) = match self_ty.sty { ty::ty_rptr(r, ref m) => (m.mutbl, r), @@ -1481,28 +1497,32 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, ty.repr(rcx.tcx()), region.repr(rcx.tcx())); - let constraints = - regionmanip::region_wf_constraints( - rcx.tcx(), - ty, - region); - for constraint in &constraints { - debug!("constraint: {}", constraint.repr(rcx.tcx())); - match *constraint { - regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => { + let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id, + ty, region, origin.span()); + for implication in implications { + debug!("implication: {}", implication.repr(rcx.tcx())); + match implication { + implicator::Implication::RegionSubRegion(None, r_a, r_b) => { rcx.fcx.mk_subr(origin.clone(), r_a, r_b); } - regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => { + implicator::Implication::RegionSubRegion(Some(ty), r_a, r_b) => { let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); rcx.fcx.mk_subr(o1, r_a, r_b); } - regionmanip::RegionSubGenericConstraint(None, r_a, ref generic_b) => { + implicator::Implication::RegionSubGeneric(None, r_a, ref generic_b) => { generic_must_outlive(rcx, origin.clone(), r_a, generic_b); } - regionmanip::RegionSubGenericConstraint(Some(ty), r_a, ref generic_b) => { + implicator::Implication::RegionSubGeneric(Some(ty), r_a, ref generic_b) => { let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); generic_must_outlive(rcx, o1, r_a, generic_b); } + implicator::Implication::Predicate(def_id, predicate) => { + let cause = traits::ObligationCause::new(origin.span(), + rcx.body_id, + traits::ItemObligation(def_id)); + let obligation = traits::Obligation::new(cause, predicate); + rcx.fcx.register_predicate(obligation); + } } } } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 94670305be755..d124282d39128 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -97,14 +97,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_item_type(item); } ast::ItemStruct(ref struct_def, _) => { - self.check_type_defn(item, |fcx| { - vec![struct_variant(fcx, &**struct_def)] - }); + self.check_type_defn(item, |fcx| vec![struct_variant(fcx, &**struct_def)]); } ast::ItemEnum(ref enum_def, _) => { - self.check_type_defn(item, |fcx| { - enum_variants(fcx, enum_def) - }); + self.check_type_defn(item, |fcx| enum_variants(fcx, enum_def)); } ast::ItemTrait(..) => { let trait_predicates = @@ -578,8 +574,8 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // the regions in the argument types come from the // enum def'n, and hence will all be early bound let arg_tys = - ty::assert_no_late_bound_regions( - fcx.tcx(), &ty::ty_fn_args(ctor_ty)); + ty::no_late_bound_regions( + fcx.tcx(), &ty::ty_fn_args(ctor_ty)).unwrap(); AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1b9f8b9901723..9d3ffb114c121 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -14,7 +14,7 @@ use self::Entry::*; use self::SearchResult::*; use self::VacantEntryState::*; -use borrow::BorrowFrom; +use borrow::Borrow; use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; @@ -453,18 +453,18 @@ impl HashMap /// If you already have the hash for the key lying around, use /// search_hashed. fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash + where K: Borrow, Q: Eq + Hash { let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&self.table, hash, |k| q.eq(k.borrow())) .into_option() } fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash + where K: Borrow, Q: Eq + Hash { let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) + search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) .into_option() } @@ -1037,7 +1037,7 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, k: &Q) -> Option<&V> - where Q: Hash + Eq + BorrowFrom + where K: Borrow, Q: Hash + Eq { self.search(k).map(|bucket| bucket.into_refs().1) } @@ -1060,7 +1060,7 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains_key(&self, k: &Q) -> bool - where Q: Hash + Eq + BorrowFrom + where K: Borrow, Q: Hash + Eq { self.search(k).is_some() } @@ -1086,7 +1086,7 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash + Eq + BorrowFrom + where K: Borrow, Q: Hash + Eq { self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } @@ -1138,7 +1138,7 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, k: &Q) -> Option - where Q: Hash + Eq + BorrowFrom + where K: Borrow, Q: Hash + Eq { if self.table.size() == 0 { return None @@ -1247,8 +1247,8 @@ impl Default for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl Index for HashMap - where K: Eq + Hash, - Q: Eq + Hash + BorrowFrom, + where K: Eq + Hash + Borrow, + Q: Eq + Hash, S: HashState, H: hash::Hasher { @@ -1262,8 +1262,8 @@ impl Index for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for HashMap - where K: Eq + Hash, - Q: Eq + Hash + BorrowFrom, + where K: Eq + Hash + Borrow, + Q: Eq + Hash, S: HashState, H: hash::Hasher { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 5fbbcb3b347af..7befaa8c368c6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -10,7 +10,7 @@ // // ignore-lexer-test FIXME #15883 -use borrow::BorrowFrom; +use borrow::Borrow; use clone::Clone; use cmp::{Eq, PartialEq}; use core::marker::Sized; @@ -462,7 +462,7 @@ impl HashSet /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains(&self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where T: Borrow, Q: Hash + Eq { self.map.contains_key(value) } @@ -572,7 +572,7 @@ impl HashSet /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where T: Borrow, Q: Hash + Eq { self.map.remove(value).is_some() } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 1d14b141778f0..8c29b11cb99f9 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -34,7 +34,7 @@ use core::prelude::*; -use core::borrow::{BorrowFrom, ToOwned}; +use borrow::{Borrow, ToOwned}; use fmt::{self, Debug}; use mem; use string::{String, CowString}; @@ -266,11 +266,12 @@ impl Debug for OsStr { } } -impl BorrowFrom for OsStr { - fn borrow_from(owned: &OsString) -> &OsStr { &owned[] } +impl Borrow for OsString { + fn borrow(&self) -> &OsStr { &self[] } } -impl ToOwned for OsStr { +impl ToOwned for OsStr { + type Owned = OsString; fn to_owned(&self) -> OsString { self.to_os_string() } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7c9a8a7b4b5ad..fbd403ea593b8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -161,7 +161,6 @@ extern crate libc; // NB: These reexports are in the order they should be listed in rustdoc pub use core::any; -pub use core::borrow; pub use core::cell; pub use core::clone; #[cfg(not(test))] pub use core::cmp; @@ -184,6 +183,7 @@ pub use core::error; #[cfg(not(test))] pub use alloc::boxed; pub use alloc::rc; +pub use core_collections::borrow; pub use core_collections::fmt; pub use core_collections::slice; pub use core_collections::str; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1d992668900f0..1f7129bf361e2 100755 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -108,12 +108,11 @@ use core::prelude::*; use ascii::*; -use borrow::BorrowFrom; +use borrow::{Borrow, ToOwned, Cow}; use cmp; use iter; use mem; use ops::{self, Deref}; -use string::CowString; use vec::Vec; use fmt; @@ -982,12 +981,17 @@ impl ops::Deref for PathBuf { } } -impl BorrowFrom for Path { - fn borrow_from(owned: &PathBuf) -> &Path { - owned.deref() +impl Borrow for PathBuf { + fn borrow(&self) -> &Path { + self.deref() } } +impl ToOwned for Path { + type Owned = PathBuf; + fn to_owned(&self) -> PathBuf { self.to_path_buf() } +} + impl cmp::PartialEq for PathBuf { fn eq(&self, other: &PathBuf) -> bool { self.components() == other.components() @@ -1066,10 +1070,10 @@ impl Path { self.inner.to_str() } - /// Convert a `Path` to a `CowString`. + /// Convert a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. - pub fn to_string_lossy(&self) -> CowString { + pub fn to_string_lossy(&self) -> Cow { self.inner.to_string_lossy() } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 38ba0b38df5a7..0768b60ef5050 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -16,14 +16,13 @@ use ext::tt::transcribe::tt_next_token; use parse::token; use parse::token::{str_to_ident}; -use std::borrow::IntoCow; +use std::borrow::{Cow, IntoCow}; use std::char; use std::fmt; use std::mem::replace; use std::num; use std::rc::Rc; use std::str; -use std::string::CowString; pub use ext::tt::transcribe::{TtReader, new_tt_reader, new_tt_reader_with_doc_flag}; @@ -278,7 +277,7 @@ impl<'a> StringReader<'a> { /// Converts CRLF to LF in the given string, raising an error on bare CR. fn translate_crlf<'b>(&self, start: BytePos, - s: &'b str, errmsg: &'b str) -> CowString<'b> { + s: &'b str, errmsg: &'b str) -> Cow<'b, str> { let mut i = 0; while i < s.len() { let str::CharRange { ch, next } = s.char_range_at(i); diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 511442675194e..5236122f585e1 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -14,7 +14,7 @@ use ast::Name; -use std::borrow::BorrowFrom; +use std::borrow::Borrow; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; @@ -79,7 +79,7 @@ impl + Clone + 'static> Interner { } pub fn find(&self, val: &Q) -> Option - where Q: BorrowFrom + Eq + Hash { + where T: Borrow, Q: Eq + Hash { let map = self.map.borrow(); match (*map).get(val) { Some(v) => Some(*v), @@ -128,9 +128,9 @@ impl fmt::Display for RcStr { } } -impl BorrowFrom for str { - fn borrow_from(owned: &RcStr) -> &str { - &owned.string[] +impl Borrow for RcStr { + fn borrow(&self) -> &str { + &self.string[] } } @@ -211,7 +211,7 @@ impl StrInterner { } pub fn find(&self, val: &Q) -> Option - where Q: BorrowFrom + Eq + Hash { + where RcStr: Borrow, Q: Eq + Hash { match (*self.map.borrow()).get(val) { Some(v) => Some(*v), None => None, diff --git a/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs new file mode 100644 index 0000000000000..fa26c9c54c8f4 --- /dev/null +++ b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs @@ -0,0 +1,59 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears, even when the +// associted type is in a supertype. Issue #22246. + +#![allow(dead_code)] + +use std::mem::transmute; +use std::ops::Deref; + +/////////////////////////////////////////////////////////////////////////// + +pub trait TheTrait { + type TheAssocType; + + fn dummy(&self) { } +} + +pub trait TheSubTrait : TheTrait { +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +impl<'b> TheSubTrait for TheType<'b> { +} + +/////////////////////////////////////////////////////////////////////////// + +pub struct WithAssoc { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs b/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs new file mode 100644 index 0000000000000..7d955065ff455 --- /dev/null +++ b/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs @@ -0,0 +1,70 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that structs with higher-ranked where clauses don't generate +// "outlives" requirements. Issue #22246. + +#![allow(dead_code)] +#![feature(rustc_attrs)] + +/////////////////////////////////////////////////////////////////////////// + +pub trait TheTrait<'b> { + type TheAssocType; + + fn dummy(&'b self) { } +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'a,'b> TheTrait<'a> for TheType<'b> { + type TheAssocType = &'b (); +} + +/////////////////////////////////////////////////////////////////////////// + +pub struct WithHrAssoc + where for<'a> T : TheTrait<'a> +{ + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // We get no error here because the where clause has a higher-ranked assoc type, + // which could not be projected from. + + let _: &'a WithHrAssoc> = loop { }; +} + +/////////////////////////////////////////////////////////////////////////// + +pub trait TheSubTrait : for<'a> TheTrait<'a> { +} + +impl<'b> TheSubTrait for TheType<'b> { } + +pub struct WithHrAssocSub + where T : TheSubTrait +{ + m: [T; 0] +} + +fn with_assoc_sub<'a,'b>() { + // Same here, because although the where clause is not HR, it + // extends a trait in a HR way. + + let _: &'a WithHrAssocSub> = loop { }; +} + +#[rustc_error] +fn main() { //~ ERROR compilation successful +} diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs b/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs new file mode 100644 index 0000000000000..6ee65fbdf919b --- /dev/null +++ b/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs @@ -0,0 +1,53 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears, even when the +// constraint is in a where clause not a bound. Issue #22246. + +#![allow(dead_code)] + +use std::mem::transmute; +use std::ops::Deref; + +/////////////////////////////////////////////////////////////////////////// + +pub trait TheTrait { + type TheAssocType; + + fn dummy(&self) { } +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +/////////////////////////////////////////////////////////////////////////// + +pub struct WithAssoc where T : TheTrait { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container.rs b/src/test/compile-fail/regions-assoc-type-outlives-container.rs new file mode 100644 index 0000000000000..49a0726fa3b7b --- /dev/null +++ b/src/test/compile-fail/regions-assoc-type-outlives-container.rs @@ -0,0 +1,91 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are imposing the requirement that every associated +// type of a bound that appears in the where clause on a struct must +// outlive the location in which the type appears. Issue #22246. + +#![allow(dead_code)] + +use std::mem::transmute; +use std::ops::Deref; + +/////////////////////////////////////////////////////////////////////////// + +pub trait TheTrait { + type TheAssocType; + + fn dummy(&self) { } +} + +pub struct TheType<'b> { + m: [fn(&'b()); 0] +} + +impl<'b> TheTrait for TheType<'b> { + type TheAssocType = &'b (); +} + +/////////////////////////////////////////////////////////////////////////// + +pub struct WithAssoc { + m: [T; 0] +} + +pub struct WithoutAssoc { + m: [T; 0] +} + +fn with_assoc<'a,'b>() { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a. + + let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer +} + +fn with_assoc1<'a,'b>() where 'b : 'a { + // For this type to be valid, the rules require that all + // associated types of traits that appear in `WithAssoc` must + // outlive 'a. In this case, that means TheType<'b>::TheAssocType, + // which is &'b (), must outlive 'a, so 'b : 'a must hold, and + // that is in the where clauses, so we're fine. + + let _: &'a WithAssoc> = loop { }; +} + +fn without_assoc<'a,'b>() { + // Here there are no associated types and the `'b` appearing in + // `TheType<'b>` is purely covariant, so there is no requirement + // that `'b:'a` holds. + + let _: &'a WithoutAssoc> = loop { }; +} + +fn call_with_assoc<'a,'b>() { + // As `with_assoc`, but just checking that we impose the same rule + // on the value supplied for the type argument, even when there is + // no data. + + call::<&'a WithAssoc>>(); + //~^ ERROR cannot infer +} + +fn call_without_assoc<'a,'b>() { + // As `without_assoc`, but in a distinct scenario. + + call::<&'a WithoutAssoc>>(); +} + +fn call() { } + +fn main() { +} diff --git a/src/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs index 5fa66eb98e1af..f4e18265fd990 100644 --- a/src/test/compile-fail/ufcs-qpath-missing-params.rs +++ b/src/test/compile-fail/ufcs-qpath-missing-params.rs @@ -12,6 +12,5 @@ use std::borrow::IntoCow; fn main() { ::into_cow("foo".to_string()); - //~^ ERROR wrong number of type arguments: expected 2, found 0 + //~^ ERROR wrong number of type arguments: expected 1, found 0 } - diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index d90219b4221eb..b393afeef39ad 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -34,7 +34,7 @@ use std::mem::size_of; static uni: &'static str = "Les Miséééééééérables"; static yy: usize = 25us; -static bob: Option> = None; +static bob: Option> = None; // buglink test - see issue #1337. diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs index f8f92a56adb1a..be4c3272a5b66 100644 --- a/src/test/run-pass/const-polymorphic-paths.rs +++ b/src/test/run-pass/const-polymorphic-paths.rs @@ -100,8 +100,8 @@ tests! { Add::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); - >::into_cow, fn(String) -> Cow<'static, String, str>, + >::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); - >::into_cow, fn(String) -> Cow<'static, String, str>, + >::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); } diff --git a/src/test/run-pass/regions-issue-22246.rs b/src/test/run-pass/regions-issue-22246.rs new file mode 100644 index 0000000000000..f5c34d6b34e9d --- /dev/null +++ b/src/test/run-pass/regions-issue-22246.rs @@ -0,0 +1,35 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for issue #22246 -- we should be able to deduce +// that `&'a B::Owned` implies that `B::Owned : 'a`. + +#![allow(dead_code)] + +use std::ops::Deref; + +pub trait ToOwned { + type Owned: Borrow; + fn to_owned(&self) -> Self::Owned; +} + +pub trait Borrow { + fn borrow(&self) -> &Borrowed; +} + +pub struct Foo { + owned: B::Owned +} + +fn foo(this: &Foo) -> &B { + this.owned.borrow() +} + +fn main() { } diff --git a/src/test/run-pass/send_str_hashmap.rs b/src/test/run-pass/send_str_hashmap.rs index c58654670d1a3..33e4fa85bcb81 100644 --- a/src/test/run-pass/send_str_hashmap.rs +++ b/src/test/run-pass/send_str_hashmap.rs @@ -13,7 +13,7 @@ extern crate collections; use std::collections::HashMap; use std::borrow::{Cow, IntoCow}; -type SendStr = Cow<'static, String, str>; +type SendStr = Cow<'static, str>; pub fn main() { let mut map: HashMap = HashMap::new(); diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index 438724a2b06bf..3390369242d13 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -13,7 +13,7 @@ extern crate collections; use self::collections::BTreeMap; use std::borrow::{Cow, IntoCow}; -type SendStr = Cow<'static, String, str>; +type SendStr = Cow<'static, str>; pub fn main() { let mut map: BTreeMap = BTreeMap::new(); diff --git a/src/test/run-pass/traits-issue-22019.rs b/src/test/run-pass/traits-issue-22019.rs index 5d3195e193708..7e0f60d55a827 100644 --- a/src/test/run-pass/traits-issue-22019.rs +++ b/src/test/run-pass/traits-issue-22019.rs @@ -23,18 +23,18 @@ pub type Node<'a> = &'a CFGNode; pub trait GraphWalk<'c, N> { /// Returns all the nodes in this graph. - fn nodes(&'c self) where [N]:ToOwned>; + fn nodes(&'c self) where [N]:ToOwned>; } impl<'g> GraphWalk<'g, Node<'g>> for u32 { - fn nodes(&'g self) where [Node<'g>]:ToOwned>> + fn nodes(&'g self) where [Node<'g>]:ToOwned>> { loop { } } } impl<'h> GraphWalk<'h, Node<'h>> for u64 { - fn nodes(&'h self) where [Node<'h>]:ToOwned>> + fn nodes(&'h self) where [Node<'h>]:ToOwned>> { loop { } } } diff --git a/src/test/run-pass/traits-issue-22110.rs b/src/test/run-pass/traits-issue-22110.rs new file mode 100644 index 0000000000000..9cdcf4945d8ba --- /dev/null +++ b/src/test/run-pass/traits-issue-22110.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test an issue where we reported ambiguity between the where-clause +// and the blanket impl. The only important thing is that compilation +// succeeds here. Issue #22110. + +#![allow(dead_code)] + +trait Foo { + fn foo(&self, a: A); +} + +impl Foo for F { + fn foo(&self, _: A) { } +} + +fn baz Foo<(&'a A,)>>(_: F) { } + +fn components(t: fn(&A)) + where fn(&A) : for<'a> Foo<(&'a A,)>, +{ + baz(t) +} + +fn main() { +}