mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 04:26:48 +00:00
Implement generalized object and type parameter bounds (Fixes #16462)
This commit is contained in:
parent
3ee047ae1f
commit
1b487a8906
@ -105,9 +105,9 @@ pub trait BoxAny {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl BoxAny for Box<Any> {
|
||||
impl BoxAny for Box<Any+'static> {
|
||||
#[inline]
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any+'static>> {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
@ -132,7 +132,7 @@ impl<T: fmt::Show> fmt::Show for Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for Box<Any> {
|
||||
impl fmt::Show for Box<Any+'static> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("Box<Any>")
|
||||
}
|
||||
|
@ -49,19 +49,29 @@ struct Node<T> {
|
||||
value: T,
|
||||
}
|
||||
|
||||
/// An iterator over references to the items of a `DList`.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Items<'a, T> {
|
||||
head: &'a Link<T>,
|
||||
tail: Rawlink<Node<T>>,
|
||||
nelem: uint,
|
||||
}
|
||||
|
||||
/// An iterator over references to the items of a `DList`.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Items<'a, T:'a> {
|
||||
head: &'a Link<T>,
|
||||
tail: Rawlink<Node<T>>,
|
||||
nelem: uint,
|
||||
}
|
||||
|
||||
// FIXME #11820: the &'a Option<> of the Link stops clone working.
|
||||
impl<'a, T> Clone for Items<'a, T> {
|
||||
fn clone(&self) -> Items<'a, T> { *self }
|
||||
}
|
||||
|
||||
/// An iterator over mutable references to the items of a `DList`.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutItems<'a, T> {
|
||||
list: &'a mut DList<T>,
|
||||
head: Rawlink<Node<T>>,
|
||||
@ -69,7 +79,16 @@ pub struct MutItems<'a, T> {
|
||||
nelem: uint,
|
||||
}
|
||||
|
||||
/// A consuming iterator over the items of a `DList`.
|
||||
/// An iterator over mutable references to the items of a `DList`.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutItems<'a, T:'a> {
|
||||
list: &'a mut DList<T>,
|
||||
head: Rawlink<Node<T>>,
|
||||
tail: Rawlink<Node<T>>,
|
||||
nelem: uint,
|
||||
}
|
||||
|
||||
/// An iterator over mutable references to the items of a `DList`.
|
||||
#[deriving(Clone)]
|
||||
pub struct MoveItems<T> {
|
||||
list: DList<T>
|
||||
|
@ -515,11 +515,18 @@ impl<T: Ord> PriorityQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `PriorityQueue` iterator.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Items <'a, T> {
|
||||
iter: slice::Items<'a, T>,
|
||||
}
|
||||
|
||||
/// `PriorityQueue` iterator.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Items <'a, T:'a> {
|
||||
iter: slice::Items<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(&'a T)> { self.iter.next() }
|
||||
|
@ -293,7 +293,8 @@ impl<T> RingBuf<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `RingBuf` iterator.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Items<'a, T> {
|
||||
lo: uint,
|
||||
index: uint,
|
||||
@ -301,6 +302,15 @@ pub struct Items<'a, T> {
|
||||
elts: &'a [Option<T>],
|
||||
}
|
||||
|
||||
/// `RingBuf` iterator.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Items<'a, T:'a> {
|
||||
lo: uint,
|
||||
index: uint,
|
||||
rindex: uint,
|
||||
elts: &'a [Option<T>],
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
@ -348,13 +358,22 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `RingBuf` mutable iterator.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutItems<'a, T> {
|
||||
remaining1: &'a mut [Option<T>],
|
||||
remaining2: &'a mut [Option<T>],
|
||||
nelts: uint,
|
||||
}
|
||||
|
||||
/// `RingBuf` mutable iterator.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutItems<'a, T:'a> {
|
||||
remaining1: &'a mut [Option<T>],
|
||||
remaining2: &'a mut [Option<T>],
|
||||
nelts: uint,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> {
|
||||
#[inline]
|
||||
#[allow(deprecated)] // mut_shift_ref
|
||||
|
@ -489,19 +489,37 @@ macro_rules! double_ended_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Forward iterator over a map.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Entries<'a, T> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::Items<'a, Option<T>>
|
||||
}
|
||||
|
||||
/// Forward iterator over a map.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Entries<'a, T:'a> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::Items<'a, Option<T>>
|
||||
}
|
||||
|
||||
iterator!(impl Entries -> (uint, &'a T), get_ref)
|
||||
double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref)
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutEntries<'a, T> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::MutItems<'a, Option<T>>
|
||||
}
|
||||
|
||||
/// Forward iterator over the key-value pairs of a map, with the
|
||||
/// values being mutable.
|
||||
pub struct MutEntries<'a, T> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutEntries<'a, T:'a> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::MutItems<'a, Option<T>>
|
||||
|
@ -668,7 +668,8 @@ impl<K: Ord, V> TreeMap<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a map.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Entries<'a, K, V> {
|
||||
stack: Vec<&'a TreeNode<K, V>>,
|
||||
// See the comment on MutEntries; this is just to allow
|
||||
@ -679,13 +680,32 @@ pub struct Entries<'a, K, V> {
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// Lazy backward iterator over a map.
|
||||
/// Lazy forward iterator over a map
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Entries<'a, K:'a, V:'a> {
|
||||
stack: Vec<&'a TreeNode<K, V>>,
|
||||
// See the comment on MutEntries; this is just to allow
|
||||
// code-sharing (for this immutable-values iterator it *could* very
|
||||
// well be Option<&'a TreeNode<K,V>>).
|
||||
node: *const TreeNode<K, V>,
|
||||
remaining_min: uint,
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct RevEntries<'a, K, V> {
|
||||
iter: Entries<'a, K, V>,
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a map that allows for the mutation of
|
||||
/// the values.
|
||||
/// Lazy backward iterator over a map
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RevEntries<'a, K:'a, V:'a> {
|
||||
iter: Entries<'a, K, V>,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutEntries<'a, K, V> {
|
||||
stack: Vec<&'a mut TreeNode<K, V>>,
|
||||
// Unfortunately, we require some unsafe-ness to get around the
|
||||
@ -712,11 +732,46 @@ pub struct MutEntries<'a, K, V> {
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// Lazy backward iterator over a map.
|
||||
/// Lazy forward iterator over a map that allows for the mutation of
|
||||
/// the values.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutEntries<'a, K:'a, V:'a> {
|
||||
stack: Vec<&'a mut TreeNode<K, V>>,
|
||||
// Unfortunately, we require some unsafe-ness to get around the
|
||||
// fact that we would be storing a reference *into* one of the
|
||||
// nodes in the stack.
|
||||
//
|
||||
// As far as the compiler knows, this would let us invalidate the
|
||||
// reference by assigning a new value to this node's position in
|
||||
// its parent, which would cause this current one to be
|
||||
// deallocated so this reference would be invalid. (i.e. the
|
||||
// compilers complaints are 100% correct.)
|
||||
//
|
||||
// However, as far as you humans reading this code know (or are
|
||||
// about to know, if you haven't read far enough down yet), we are
|
||||
// only reading from the TreeNode.{left,right} fields. the only
|
||||
// thing that is ever mutated is the .value field (although any
|
||||
// actual mutation that happens is done externally, by the
|
||||
// iterator consumer). So, don't be so concerned, rustc, we've got
|
||||
// it under control.
|
||||
//
|
||||
// (This field can legitimately be null.)
|
||||
node: *mut TreeNode<K, V>,
|
||||
remaining_min: uint,
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct RevMutEntries<'a, K, V> {
|
||||
iter: MutEntries<'a, K, V>,
|
||||
}
|
||||
|
||||
/// Lazy backward iterator over a map
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RevMutEntries<'a, K:'a, V:'a> {
|
||||
iter: MutEntries<'a, K, V>,
|
||||
}
|
||||
|
||||
/// TreeMap keys iterator.
|
||||
pub type Keys<'a, K, V> =
|
||||
@ -885,9 +940,7 @@ fn mut_deref<K, V>(x: &mut Option<Box<TreeNode<K, V>>>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// A lazy forward iterator over a map that consumes the map while iterating.
|
||||
/// Lazy forward iterator over a map that consumes the map while iterating
|
||||
pub struct MoveEntries<K, V> {
|
||||
stack: Vec<TreeNode<K, V>>,
|
||||
remaining: uint
|
||||
@ -1322,45 +1375,90 @@ impl<T: Ord> TreeSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a set.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct SetItems<'a, T> {
|
||||
iter: Entries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// Lazy backward iterator over a set.
|
||||
/// A lazy forward iterator over a set.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct SetItems<'a, T:'a> {
|
||||
iter: Entries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct RevSetItems<'a, T> {
|
||||
iter: RevEntries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// A lazy backward iterator over a set.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RevSetItems<'a, T:'a> {
|
||||
iter: RevEntries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a set that consumes the set while iterating.
|
||||
pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
|
||||
|
||||
/// A lazy iterator producing elements in the set difference (in-order).
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct DifferenceItems<'a, T> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set symmetric difference (in-order).
|
||||
/// A lazy iterator producing elements in the set difference (in-order).
|
||||
#[cfg(not(stage0))]
|
||||
pub struct DifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct SymDifferenceItems<'a, T> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set intersection (in-order).
|
||||
/// A lazy iterator producing elements in the set symmetric difference (in-order).
|
||||
#[cfg(not(stage0))]
|
||||
pub struct SymDifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct IntersectionItems<'a, T> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set union (in-order).
|
||||
/// A lazy iterator producing elements in the set intersection (in-order).
|
||||
#[cfg(not(stage0))]
|
||||
pub struct IntersectionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct UnionItems<'a, T> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is
|
||||
/// `None`.
|
||||
/// A lazy iterator producing elements in the set union (in-order).
|
||||
#[cfg(not(stage0))]
|
||||
pub struct UnionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
|
||||
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
|
||||
short: Ordering, long: Ordering) -> Ordering {
|
||||
match (x, y) {
|
||||
|
@ -857,7 +857,8 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// A forward iterator over a map.
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Entries<'a, T> {
|
||||
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
|
||||
length: uint,
|
||||
@ -865,9 +866,28 @@ pub struct Entries<'a, T> {
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// A forward iterator over a map.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Entries<'a, T:'a> {
|
||||
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
|
||||
length: uint,
|
||||
remaining_min: uint,
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutEntries<'a, T> {
|
||||
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
|
||||
length: uint,
|
||||
remaining_min: uint,
|
||||
remaining_max: uint
|
||||
}
|
||||
|
||||
/// A forward iterator over the key-value pairs of a map, with the
|
||||
/// values being mutable.
|
||||
pub struct MutEntries<'a, T> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutEntries<'a, T:'a> {
|
||||
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
|
||||
length: uint,
|
||||
remaining_min: uint,
|
||||
|
@ -1620,9 +1620,13 @@ pub struct MoveItems<T> {
|
||||
|
||||
impl<T> Iterator<T> for MoveItems<T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
fn next<'a>(&'a mut self) -> Option<T> {
|
||||
unsafe {
|
||||
self.iter.next().map(|x| ptr::read(x))
|
||||
// Unsafely transmute from Items<'static, T> to Items<'a,
|
||||
// T> because otherwise the type checker requires that T
|
||||
// be bounded by 'static.
|
||||
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
|
||||
iter.next().map(|x| ptr::read(x))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1634,9 +1638,13 @@ impl<T> Iterator<T> for MoveItems<T> {
|
||||
|
||||
impl<T> DoubleEndedIterator<T> for MoveItems<T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
fn next_back<'a>(&'a mut self) -> Option<T> {
|
||||
unsafe {
|
||||
self.iter.next_back().map(|x| ptr::read(x))
|
||||
// Unsafely transmute from Items<'static, T> to Items<'a,
|
||||
// T> because otherwise the type checker requires that T
|
||||
// be bounded by 'static.
|
||||
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
|
||||
iter.next_back().map(|x| ptr::read(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub trait AnyRefExt<'a> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<'a> AnyRefExt<'a> for &'a Any {
|
||||
impl<'a> AnyRefExt<'a> for &'a Any+'a {
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn is<T: 'static>(self) -> bool {
|
||||
@ -181,7 +181,7 @@ pub trait AnyMutRefExt<'a> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<'a> AnyMutRefExt<'a> for &'a mut Any {
|
||||
impl<'a> AnyMutRefExt<'a> for &'a mut Any+'a {
|
||||
#[inline]
|
||||
#[unstable = "naming conventions around acquiring references may change"]
|
||||
fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
|
||||
|
@ -324,6 +324,16 @@ impl<T: PartialEq> PartialEq for RefCell<T> {
|
||||
|
||||
/// Wraps a borrowed reference to a value in a `RefCell` box.
|
||||
#[unstable]
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Ref<'b, T:'b> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_parent: &'b RefCell<T>
|
||||
}
|
||||
|
||||
/// Dox.
|
||||
#[unstable]
|
||||
#[cfg(stage0)]
|
||||
pub struct Ref<'b, T> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
@ -369,6 +379,16 @@ pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
|
||||
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
|
||||
#[unstable]
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RefMut<'b, T:'b> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_parent: &'b RefCell<T>
|
||||
}
|
||||
|
||||
/// Dox.
|
||||
#[unstable]
|
||||
#[cfg(stage0)]
|
||||
pub struct RefMut<'b, T> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
|
@ -102,6 +102,13 @@ pub fn try_finally<T,U,R>(mutate: &mut T,
|
||||
try_fn(&mut *f.mutate, drop)
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
struct Finallyalizer<'a,A:'a> {
|
||||
mutate: &'a mut A,
|
||||
dtor: |&mut A|: 'a
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct Finallyalizer<'a,A> {
|
||||
mutate: &'a mut A,
|
||||
dtor: |&mut A|: 'a
|
||||
|
@ -92,7 +92,7 @@ pub struct Formatter<'a> {
|
||||
/// Optionally specified precision for numeric types
|
||||
pub precision: Option<uint>,
|
||||
|
||||
buf: &'a mut FormatWriter,
|
||||
buf: &'a mut FormatWriter+'a,
|
||||
curarg: slice::Items<'a, Argument<'a>>,
|
||||
args: &'a [Argument<'a>],
|
||||
}
|
||||
@ -524,7 +524,7 @@ impl<'a, T: Show> Show for &'a T {
|
||||
impl<'a, T: Show> Show for &'a mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
|
||||
}
|
||||
impl<'a> Show for &'a Show {
|
||||
impl<'a> Show for &'a Show+'a {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) }
|
||||
}
|
||||
|
||||
@ -692,7 +692,7 @@ macro_rules! tuple (
|
||||
|
||||
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
|
||||
|
||||
impl<'a> Show for &'a any::Any {
|
||||
impl<'a> Show for &'a any::Any+'a {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
|
||||
}
|
||||
|
||||
|
@ -673,7 +673,7 @@ pub trait MutableDoubleEndedIterator {
|
||||
fn reverse_(&mut self);
|
||||
}
|
||||
|
||||
impl<'a, A, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
|
||||
impl<'a, A:'a, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
|
||||
// FIXME: #5898: should be called `reverse`
|
||||
/// Use an iterator to reverse a container in-place
|
||||
fn reverse_(&mut self) {
|
||||
@ -777,18 +777,26 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
|
||||
|
||||
/// A mutable reference to an iterator
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[cfg(not(stage0))]
|
||||
pub struct ByRef<'a, T:'a> {
|
||||
iter: &'a mut T
|
||||
}
|
||||
|
||||
/// Dox
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[cfg(stage0)]
|
||||
pub struct ByRef<'a, T> {
|
||||
iter: &'a mut T
|
||||
}
|
||||
|
||||
impl<'a, A, T: Iterator<A>> Iterator<A> for ByRef<'a, T> {
|
||||
impl<'a, A, T: Iterator<A>+'a> Iterator<A> for ByRef<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> { self.iter.next() }
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl<'a, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'a, T> {
|
||||
impl<'a, A, T: DoubleEndedIterator<A>+'a> DoubleEndedIterator<A> for ByRef<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
#![no_std]
|
||||
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
|
||||
#![feature(simd, unsafe_destructor)]
|
||||
#![feature(simd, unsafe_destructor, issue_5723_bootstrap)]
|
||||
#![deny(missing_doc)]
|
||||
|
||||
mod macros;
|
||||
|
@ -369,7 +369,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
#[inline]
|
||||
#[unstable = "this function may be removed in the future due to its \
|
||||
questionable utility"]
|
||||
pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
|
||||
pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
@ -377,7 +377,7 @@ pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
|
||||
#[inline]
|
||||
#[unstable = "this function may be removed in the future due to its \
|
||||
questionable utility"]
|
||||
pub unsafe fn copy_mut_lifetime<'a, S, T>(_ptr: &'a mut S,
|
||||
pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S,
|
||||
ptr: &mut T) -> &'a mut T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
@ -996,9 +996,6 @@ impl<'a, T> Default for &'a [T] {
|
||||
fn default() -> &'a [T] { &[] }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Iterators
|
||||
//
|
||||
@ -1128,7 +1125,16 @@ impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
|
||||
|
||||
/// An iterator over the slices of a vector separated by elements that
|
||||
/// match a predicate function.
|
||||
#[cfg(not(stage0))]
|
||||
#[experimental = "needs review"]
|
||||
pub struct Splits<'a, T:'a> {
|
||||
v: &'a [T],
|
||||
pred: |t: &T|: 'a -> bool,
|
||||
finished: bool
|
||||
}
|
||||
|
||||
/// Dox.
|
||||
#[cfg(stage0)]
|
||||
pub struct Splits<'a, T> {
|
||||
v: &'a [T],
|
||||
pred: |t: &T|: 'a -> bool,
|
||||
@ -1186,7 +1192,16 @@ impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
|
||||
|
||||
/// An iterator over the subslices of the vector which are separated
|
||||
/// by elements that match `pred`.
|
||||
#[cfg(not(stage0))]
|
||||
#[experimental = "needs review"]
|
||||
pub struct MutSplits<'a, T:'a> {
|
||||
v: &'a mut [T],
|
||||
pred: |t: &T|: 'a -> bool,
|
||||
finished: bool
|
||||
}
|
||||
|
||||
/// Dox
|
||||
#[cfg(stage0)]
|
||||
pub struct MutSplits<'a, T> {
|
||||
v: &'a mut [T],
|
||||
pred: |t: &T|: 'a -> bool,
|
||||
@ -1255,7 +1270,16 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
|
||||
|
||||
/// An iterator over the slices of a vector separated by elements that
|
||||
/// match a predicate function, splitting at most a fixed number of times.
|
||||
#[cfg(not(stage0))]
|
||||
#[experimental = "needs review"]
|
||||
pub struct SplitsN<'a, T:'a> {
|
||||
iter: Splits<'a, T>,
|
||||
count: uint,
|
||||
invert: bool
|
||||
}
|
||||
|
||||
/// Dox.
|
||||
#[cfg(stage0)]
|
||||
pub struct SplitsN<'a, T> {
|
||||
iter: Splits<'a, T>,
|
||||
count: uint,
|
||||
@ -1291,6 +1315,7 @@ impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
|
||||
|
||||
/// An iterator over the (overlapping) slices of length `size` within
|
||||
/// a vector.
|
||||
#[cfg(stage0)]
|
||||
#[deriving(Clone)]
|
||||
#[experimental = "needs review"]
|
||||
pub struct Windows<'a, T> {
|
||||
@ -1298,7 +1323,16 @@ pub struct Windows<'a, T> {
|
||||
size: uint
|
||||
}
|
||||
|
||||
/// An iterator over the (overlapping) slices of length `size` within
|
||||
/// a vector.
|
||||
#[cfg(not(stage0))]
|
||||
#[deriving(Clone)]
|
||||
#[experimental = "needs review"]
|
||||
pub struct Windows<'a, T:'a> {
|
||||
v: &'a [T],
|
||||
size: uint
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a [T]> {
|
||||
@ -1327,6 +1361,7 @@ impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
|
||||
///
|
||||
/// When the vector len is not evenly divided by the chunk size,
|
||||
/// the last slice of the iteration will be the remainder.
|
||||
#[cfg(stage0)]
|
||||
#[deriving(Clone)]
|
||||
#[experimental = "needs review"]
|
||||
pub struct Chunks<'a, T> {
|
||||
@ -1334,6 +1369,18 @@ pub struct Chunks<'a, T> {
|
||||
size: uint
|
||||
}
|
||||
|
||||
/// An iterator over a vector in (non-overlapping) chunks (`size`
|
||||
/// elements at a time).
|
||||
///
|
||||
/// When the vector len is not evenly divided by the chunk size,
|
||||
/// the last slice of the iteration will be the remainder.
|
||||
#[cfg(not(stage0))]
|
||||
#[deriving(Clone)]
|
||||
pub struct Chunks<'a, T:'a> {
|
||||
v: &'a [T],
|
||||
size: uint
|
||||
}
|
||||
|
||||
#[experimental = "needs review"]
|
||||
impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
|
||||
#[inline]
|
||||
@ -1400,7 +1447,15 @@ impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
|
||||
/// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When
|
||||
/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
|
||||
/// the remainder.
|
||||
#[cfg(not(stage0))]
|
||||
#[experimental = "needs review"]
|
||||
pub struct MutChunks<'a, T:'a> {
|
||||
v: &'a mut [T],
|
||||
chunk_size: uint
|
||||
}
|
||||
|
||||
/// Dox.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutChunks<'a, T> {
|
||||
v: &'a mut [T],
|
||||
chunk_size: uint
|
||||
|
@ -25,7 +25,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||
#![experimental]
|
||||
#![feature(managed_boxes, macro_rules)]
|
||||
#![feature(managed_boxes, macro_rules, issue_5723_bootstrap)]
|
||||
#![allow(experimental)]
|
||||
|
||||
pub mod fmt;
|
||||
|
@ -95,7 +95,7 @@ pub struct ReprVisitor<'a> {
|
||||
ptr: *const u8,
|
||||
ptr_stk: Vec<*const u8>,
|
||||
var_stk: Vec<VariantState>,
|
||||
writer: &'a mut io::Writer,
|
||||
writer: &'a mut io::Writer+'a,
|
||||
last_err: Option<io::IoError>,
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.register_macro("fourcc", expand_syntax_ext);
|
||||
}
|
||||
|
||||
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult> {
|
||||
pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult+'cx> {
|
||||
let (expr, endian) = parse_tts(cx, tts);
|
||||
|
||||
let little = match endian {
|
||||
|
@ -271,6 +271,7 @@ pub fn main() {
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![license = "MIT/ASL2"]
|
||||
#![feature(issue_5723_bootstrap)]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||
@ -499,7 +500,7 @@ pub trait GraphWalk<'a, N, E> {
|
||||
|
||||
/// Renders directed graph `g` into the writer `w` in DOT syntax.
|
||||
/// (Main entry point for the library.)
|
||||
pub fn render<'a, N, E, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>(
|
||||
pub fn render<'a, N:'a, E:'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>(
|
||||
g: &'a G,
|
||||
w: &mut W) -> io::IoResult<()>
|
||||
{
|
||||
|
@ -34,6 +34,14 @@ use std::slice;
|
||||
/// Some clients will have a pre-allocated vector ready to hand off in
|
||||
/// a slice; others will want to create the set on the fly and hand
|
||||
/// off ownership, via `Growable`.
|
||||
#[cfg(not(stage0))]
|
||||
pub enum MaybeOwnedVector<'a,T:'a> {
|
||||
Growable(Vec<T>),
|
||||
Borrowed(&'a [T]),
|
||||
}
|
||||
|
||||
/// Stage0 only.
|
||||
#[cfg(stage0)]
|
||||
pub enum MaybeOwnedVector<'a,T> {
|
||||
Growable(Vec<T>),
|
||||
Borrowed(&'a [T]),
|
||||
@ -45,7 +53,7 @@ pub trait IntoMaybeOwnedVector<'a,T> {
|
||||
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T>;
|
||||
}
|
||||
|
||||
impl<'a,T> IntoMaybeOwnedVector<'a,T> for Vec<T> {
|
||||
impl<'a,T:'a> IntoMaybeOwnedVector<'a,T> for Vec<T> {
|
||||
#[inline]
|
||||
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ impl Runtime for SimpleTask {
|
||||
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
|
||||
fn stack_bounds(&self) -> (uint, uint) { fail!() }
|
||||
fn can_block(&self) -> bool { true }
|
||||
fn wrap(self: Box<SimpleTask>) -> Box<Any> { fail!() }
|
||||
fn wrap(self: Box<SimpleTask>) -> Box<Any+'static> { fail!() }
|
||||
}
|
||||
|
||||
pub fn task() -> Box<Task> {
|
||||
|
@ -488,7 +488,9 @@ impl Runtime for GreenTask {
|
||||
|
||||
fn can_block(&self) -> bool { false }
|
||||
|
||||
fn wrap(self: Box<GreenTask>) -> Box<Any> { self as Box<Any> }
|
||||
fn wrap(self: Box<GreenTask>) -> Box<Any+'static> {
|
||||
self as Box<Any+'static>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -105,7 +105,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
|
||||
}
|
||||
|
||||
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult> {
|
||||
-> Box<base::MacResult+'static> {
|
||||
let (expr, ty_lit) = parse_tts(cx, tts);
|
||||
|
||||
let ty = match ty_lit {
|
||||
|
@ -145,8 +145,8 @@ impl rt::Runtime for Ops {
|
||||
Local::put(cur_task);
|
||||
}
|
||||
|
||||
fn wrap(self: Box<Ops>) -> Box<Any> {
|
||||
self as Box<Any>
|
||||
fn wrap(self: Box<Ops>) -> Box<Any+'static> {
|
||||
self as Box<Any+'static>
|
||||
}
|
||||
|
||||
fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }
|
||||
|
@ -79,6 +79,13 @@ pub struct Weighted<T> {
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct WeightedChoice<'a, T> {
|
||||
items: &'a mut [Weighted<T>],
|
||||
weight_range: Range<uint>
|
||||
}
|
||||
|
||||
/// A distribution that selects from a finite collection of weighted items.
|
||||
///
|
||||
/// Each item has an associated weight that influences how likely it
|
||||
@ -105,7 +112,8 @@ pub struct Weighted<T> {
|
||||
/// println!("{}", wc.ind_sample(&mut rng));
|
||||
/// }
|
||||
/// ```
|
||||
pub struct WeightedChoice<'a, T> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct WeightedChoice<'a, T:'a> {
|
||||
items: &'a mut [Weighted<T>],
|
||||
weight_range: Range<uint>
|
||||
}
|
||||
|
@ -269,10 +269,17 @@ pub trait Rng {
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct Generator<'a, T, R> {
|
||||
rng: &'a mut R,
|
||||
}
|
||||
|
||||
/// Iterator which will generate a stream of random items.
|
||||
///
|
||||
/// This iterator is created via the `gen_iter` method on `Rng`.
|
||||
pub struct Generator<'a, T, R> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Generator<'a, T, R:'a> {
|
||||
rng: &'a mut R,
|
||||
}
|
||||
|
||||
@ -282,10 +289,17 @@ impl<'a, T: Rand, R: Rng> Iterator<T> for Generator<'a, T, R> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version.
|
||||
#[cfg(stage0)]
|
||||
pub struct AsciiGenerator<'a, R> {
|
||||
rng: &'a mut R,
|
||||
}
|
||||
|
||||
/// Iterator which will continuously generate random ascii characters.
|
||||
///
|
||||
/// This iterator is created via the `gen_ascii_chars` method on `Rng`.
|
||||
pub struct AsciiGenerator<'a, R> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct AsciiGenerator<'a, R:'a> {
|
||||
rng: &'a mut R,
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![feature(macro_rules, phase)]
|
||||
#![feature(macro_rules, phase, issue_5723_bootstrap)]
|
||||
#![allow(missing_doc)]
|
||||
|
||||
extern crate serialize;
|
||||
@ -662,11 +662,19 @@ pub mod writer {
|
||||
pub type EncodeResult = io::IoResult<()>;
|
||||
|
||||
// rbml writing
|
||||
#[cfg(stage0)]
|
||||
pub struct Encoder<'a, W> {
|
||||
pub writer: &'a mut W,
|
||||
size_positions: Vec<uint>,
|
||||
}
|
||||
|
||||
// rbml writing
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Encoder<'a, W:'a> {
|
||||
pub writer: &'a mut W,
|
||||
size_positions: Vec<uint>,
|
||||
}
|
||||
|
||||
fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
|
||||
match size {
|
||||
1u => w.write(&[0x80u8 | (n as u8)]),
|
||||
|
@ -77,7 +77,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||
/// strategy is identical and vm.rs has comments and will be easier to follow.
|
||||
#[allow(experimental)]
|
||||
fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
|
||||
-> Box<MacResult> {
|
||||
-> Box<MacResult+'static> {
|
||||
let regex = match parse(cx, tts) {
|
||||
Some(r) => r,
|
||||
// error is logged in 'parse' with cx.span_err
|
||||
|
@ -958,11 +958,11 @@ pub fn pretty_print_input(sess: Session,
|
||||
let mut rdr = MemReader::new(src);
|
||||
|
||||
let out = match ofile {
|
||||
None => box io::stdout() as Box<Writer>,
|
||||
None => box io::stdout() as Box<Writer+'static>,
|
||||
Some(p) => {
|
||||
let r = io::File::create(&p);
|
||||
match r {
|
||||
Ok(w) => box w as Box<Writer>,
|
||||
Ok(w) => box w as Box<Writer+'static>,
|
||||
Err(e) => fail!("print-print failed to open {} due to {}",
|
||||
p.display(), e),
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
|
||||
// A temporary feature gate used to enable parser extensions needed
|
||||
// to bootstrap fix for #5723.
|
||||
("issue_5723_bootstrap", Active),
|
||||
("issue_5723_bootstrap", Accepted),
|
||||
|
||||
// These are used to test this portion of the compiler, they don't actually
|
||||
// mean anything
|
||||
@ -97,7 +97,6 @@ enum Status {
|
||||
/// A set of features to be used by later passes.
|
||||
pub struct Features {
|
||||
pub default_type_params: Cell<bool>,
|
||||
pub issue_5723_bootstrap: Cell<bool>,
|
||||
pub overloaded_calls: Cell<bool>,
|
||||
pub rustc_diagnostic_macros: Cell<bool>,
|
||||
pub import_shadowing: Cell<bool>,
|
||||
@ -107,7 +106,6 @@ impl Features {
|
||||
pub fn new() -> Features {
|
||||
Features {
|
||||
default_type_params: Cell::new(false),
|
||||
issue_5723_bootstrap: Cell::new(false),
|
||||
overloaded_calls: Cell::new(false),
|
||||
rustc_diagnostic_macros: Cell::new(false),
|
||||
import_shadowing: Cell::new(false),
|
||||
@ -310,7 +308,7 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||
|
||||
fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
|
||||
match t.node {
|
||||
ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
|
||||
ast::TyClosure(closure) if closure.onceness == ast::Once => {
|
||||
self.gate_feature("once_fns", t.span,
|
||||
"once functions are \
|
||||
experimental and likely to be removed");
|
||||
@ -439,7 +437,6 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
|
||||
sess.abort_if_errors();
|
||||
|
||||
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
|
||||
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
|
||||
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
|
||||
sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
|
||||
sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));
|
||||
|
@ -31,6 +31,7 @@ This API is completely unstable and subject to change.
|
||||
#![allow(deprecated)]
|
||||
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
|
||||
#![feature(default_type_params, phase, unsafe_destructor)]
|
||||
#![feature(issue_5723_bootstrap)]
|
||||
|
||||
#![allow(unknown_features)] // NOTE: Remove after next snapshot
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
|
@ -27,8 +27,6 @@ pub static tag_items_data_item: uint = 0x04;
|
||||
|
||||
pub static tag_items_data_item_family: uint = 0x05;
|
||||
|
||||
pub static tag_items_data_item_ty_param_bounds: uint = 0x06;
|
||||
|
||||
pub static tag_items_data_item_type: uint = 0x07;
|
||||
|
||||
pub static tag_items_data_item_symbol: uint = 0x08;
|
||||
@ -179,7 +177,6 @@ pub static tag_lang_items_missing: uint = 0x74;
|
||||
|
||||
pub static tag_item_unnamed_field: uint = 0x75;
|
||||
pub static tag_items_data_item_visibility: uint = 0x76;
|
||||
pub static tag_items_data_item_sized: uint = 0x77;
|
||||
|
||||
pub static tag_item_method_tps: uint = 0x79;
|
||||
pub static tag_item_method_fty: uint = 0x7a;
|
||||
@ -222,12 +219,6 @@ pub struct LinkMeta {
|
||||
pub crate_hash: Svh,
|
||||
}
|
||||
|
||||
pub static tag_region_param_def: uint = 0x90;
|
||||
pub static tag_region_param_def_ident: uint = 0x91;
|
||||
pub static tag_region_param_def_def_id: uint = 0x92;
|
||||
pub static tag_region_param_def_space: uint = 0x93;
|
||||
pub static tag_region_param_def_index: uint = 0x94;
|
||||
|
||||
pub static tag_unboxed_closures: uint = 0x95;
|
||||
pub static tag_unboxed_closure: uint = 0x96;
|
||||
pub static tag_unboxed_closure_type: uint = 0x97;
|
||||
@ -239,3 +230,18 @@ pub static tag_struct_field_id: uint = 0x9b;
|
||||
|
||||
pub static tag_attribute_is_sugared_doc: uint = 0x9c;
|
||||
|
||||
pub static tag_trait_def_bounds: uint = 0x9d;
|
||||
|
||||
pub static tag_items_data_region: uint = 0x9e;
|
||||
|
||||
pub static tag_region_param_def: uint = 0xa0;
|
||||
pub static tag_region_param_def_ident: uint = 0xa1;
|
||||
pub static tag_region_param_def_def_id: uint = 0xa2;
|
||||
pub static tag_region_param_def_space: uint = 0xa3;
|
||||
pub static tag_region_param_def_index: uint = 0xa4;
|
||||
|
||||
pub static tag_type_param_def: uint = 0xa5;
|
||||
|
||||
pub static tag_item_generics: uint = 0xa6;
|
||||
pub static tag_method_ty_generics: uint = 0xa7;
|
||||
|
||||
|
@ -18,9 +18,9 @@ use metadata::common::*;
|
||||
use metadata::csearch::StaticMethodInfo;
|
||||
use metadata::csearch;
|
||||
use metadata::cstore;
|
||||
use metadata::tydecode::{parse_ty_data, parse_def_id};
|
||||
use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data};
|
||||
use metadata::tydecode::{parse_trait_ref_data};
|
||||
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
|
||||
parse_type_param_def_data, parse_bounds_data,
|
||||
parse_bare_fn_ty_data, parse_trait_ref_data};
|
||||
use middle::def;
|
||||
use middle::lang_items;
|
||||
use middle::resolve::TraitItemKind;
|
||||
@ -242,48 +242,14 @@ fn item_trait_ref(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef {
|
||||
doc_trait_ref(tp, tcx, cdata)
|
||||
}
|
||||
|
||||
fn item_ty_param_defs(item: rbml::Doc,
|
||||
tcx: &ty::ctxt,
|
||||
cdata: Cmd,
|
||||
tag: uint)
|
||||
-> subst::VecPerParamSpace<ty::TypeParameterDef> {
|
||||
let mut bounds = subst::VecPerParamSpace::empty();
|
||||
reader::tagged_docs(item, tag, |p| {
|
||||
let bd = parse_type_param_def_data(
|
||||
p.data, p.start, cdata.cnum, tcx,
|
||||
|_, did| translate_def_id(cdata, did));
|
||||
bounds.push(bd.space, bd);
|
||||
true
|
||||
});
|
||||
bounds
|
||||
fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
|
||||
parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
|
||||
|_, did| translate_def_id(cdata, did))
|
||||
}
|
||||
|
||||
fn item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd)
|
||||
-> subst::VecPerParamSpace<ty::RegionParameterDef>
|
||||
{
|
||||
let mut v = subst::VecPerParamSpace::empty();
|
||||
reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
|
||||
let ident_str_doc = reader::get_doc(rp_doc,
|
||||
tag_region_param_def_ident);
|
||||
let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
|
||||
let def_id_doc = reader::get_doc(rp_doc,
|
||||
tag_region_param_def_def_id);
|
||||
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
|
||||
let def_id = translate_def_id(cdata, def_id);
|
||||
|
||||
let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
|
||||
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
|
||||
|
||||
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
|
||||
let index = reader::doc_as_u64(doc) as uint;
|
||||
|
||||
v.push(space, ty::RegionParameterDef { name: ident.name,
|
||||
def_id: def_id,
|
||||
space: space,
|
||||
index: index });
|
||||
true
|
||||
});
|
||||
v
|
||||
fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
|
||||
let d = reader::get_doc(doc, tag_trait_def_bounds);
|
||||
doc_bounds(d, tcx, cdata)
|
||||
}
|
||||
|
||||
fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
|
||||
@ -382,24 +348,11 @@ pub fn get_trait_def(cdata: Cmd,
|
||||
tcx: &ty::ctxt) -> ty::TraitDef
|
||||
{
|
||||
let item_doc = lookup_item(item_id, cdata.data());
|
||||
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
|
||||
tag_items_data_item_ty_param_bounds);
|
||||
let rp_defs = item_region_param_defs(item_doc, cdata);
|
||||
let mut bounds = ty::empty_builtin_bounds();
|
||||
// Collect the builtin bounds from the encoded supertraits.
|
||||
// FIXME(#8559): They should be encoded directly.
|
||||
reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
|
||||
// NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
|
||||
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
|
||||
tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| {
|
||||
bounds.add(bound);
|
||||
});
|
||||
true
|
||||
});
|
||||
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
|
||||
let bounds = trait_def_bounds(item_doc, tcx, cdata);
|
||||
|
||||
ty::TraitDef {
|
||||
generics: ty::Generics {types: tp_defs,
|
||||
regions: rp_defs},
|
||||
generics: generics,
|
||||
bounds: bounds,
|
||||
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
|
||||
}
|
||||
@ -413,12 +366,10 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
|
||||
let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
|
||||
cdata);
|
||||
|
||||
let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
|
||||
let rp_defs = item_region_param_defs(item, cdata);
|
||||
let generics = doc_generics(item, tcx, cdata, tag_item_generics);
|
||||
|
||||
ty::Polytype {
|
||||
generics: ty::Generics {types: tp_defs,
|
||||
regions: rp_defs},
|
||||
generics: generics,
|
||||
ty: t
|
||||
}
|
||||
}
|
||||
@ -794,6 +745,7 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
|
||||
tcx: &ty::ctxt)
|
||||
-> ty::ImplOrTraitItem {
|
||||
let method_doc = lookup_item(id, cdata.data());
|
||||
|
||||
let def_id = item_def_id(method_doc, cdata);
|
||||
|
||||
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
|
||||
@ -808,18 +760,13 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
|
||||
|
||||
match item_sort(method_doc) {
|
||||
'r' | 'p' => {
|
||||
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
|
||||
tag_item_method_tps);
|
||||
let rp_defs = item_region_param_defs(method_doc, cdata);
|
||||
let generics = doc_generics(method_doc, tcx, cdata,
|
||||
tag_method_ty_generics);
|
||||
let fty = doc_method_fty(method_doc, tcx, cdata);
|
||||
let vis = item_visibility(method_doc);
|
||||
let explicit_self = get_explicit_self(method_doc);
|
||||
let provided_source = get_provided_source(method_doc, cdata);
|
||||
|
||||
let generics = ty::Generics {
|
||||
types: type_param_defs,
|
||||
regions: rp_defs,
|
||||
};
|
||||
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
|
||||
generics,
|
||||
fty,
|
||||
@ -1392,3 +1339,57 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_generics(base_doc: rbml::Doc,
|
||||
tcx: &ty::ctxt,
|
||||
cdata: Cmd,
|
||||
tag: uint)
|
||||
-> ty::Generics
|
||||
{
|
||||
let doc = reader::get_doc(base_doc, tag);
|
||||
|
||||
let mut types = subst::VecPerParamSpace::empty();
|
||||
reader::tagged_docs(doc, tag_type_param_def, |p| {
|
||||
let bd = parse_type_param_def_data(
|
||||
p.data, p.start, cdata.cnum, tcx,
|
||||
|_, did| translate_def_id(cdata, did));
|
||||
types.push(bd.space, bd);
|
||||
true
|
||||
});
|
||||
|
||||
let mut regions = subst::VecPerParamSpace::empty();
|
||||
reader::tagged_docs(doc, tag_region_param_def, |rp_doc| {
|
||||
let ident_str_doc = reader::get_doc(rp_doc,
|
||||
tag_region_param_def_ident);
|
||||
let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
|
||||
let def_id_doc = reader::get_doc(rp_doc,
|
||||
tag_region_param_def_def_id);
|
||||
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
|
||||
let def_id = translate_def_id(cdata, def_id);
|
||||
|
||||
let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
|
||||
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
|
||||
|
||||
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
|
||||
let index = reader::doc_as_u64(doc) as uint;
|
||||
|
||||
let mut bounds = Vec::new();
|
||||
reader::tagged_docs(rp_doc, tag_items_data_region, |p| {
|
||||
bounds.push(
|
||||
parse_region_data(
|
||||
p.data, cdata.cnum, p.start, tcx,
|
||||
|_, did| translate_def_id(cdata, did)));
|
||||
true
|
||||
});
|
||||
|
||||
regions.push(space, ty::RegionParameterDef { name: ident.name,
|
||||
def_id: def_id,
|
||||
space: space,
|
||||
index: index,
|
||||
bounds: bounds });
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
ty::Generics { types: types, regions: regions }
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ use metadata::common::*;
|
||||
use metadata::cstore;
|
||||
use metadata::decoder;
|
||||
use metadata::tyencode;
|
||||
use middle::subst::VecPerParamSpace;
|
||||
use middle::ty::{node_id_to_type, lookup_item_type};
|
||||
use middle::ty::{lookup_item_type};
|
||||
use middle::astencode;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
@ -150,45 +149,6 @@ pub fn def_to_string(did: DefId) -> String {
|
||||
format!("{}:{}", did.krate, did.node)
|
||||
}
|
||||
|
||||
fn encode_ty_type_param_defs(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext,
|
||||
params: &VecPerParamSpace<ty::TypeParameterDef>,
|
||||
tag: uint) {
|
||||
let ty_str_ctxt = &tyencode::ctxt {
|
||||
diag: ecx.diag,
|
||||
ds: def_to_string,
|
||||
tcx: ecx.tcx,
|
||||
abbrevs: &ecx.type_abbrevs
|
||||
};
|
||||
for param in params.iter() {
|
||||
rbml_w.start_tag(tag);
|
||||
tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_region_param_defs(rbml_w: &mut Encoder,
|
||||
params: &VecPerParamSpace<ty::RegionParameterDef>) {
|
||||
for param in params.iter() {
|
||||
rbml_w.start_tag(tag_region_param_def);
|
||||
|
||||
rbml_w.start_tag(tag_region_param_def_ident);
|
||||
encode_name(rbml_w, param.name);
|
||||
rbml_w.end_tag();
|
||||
|
||||
rbml_w.wr_tagged_str(tag_region_param_def_def_id,
|
||||
def_to_string(param.def_id).as_slice());
|
||||
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_space,
|
||||
param.space.to_uint() as u64);
|
||||
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_index,
|
||||
param.index as u64);
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_item_variances(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext,
|
||||
id: ast::NodeId) {
|
||||
@ -201,9 +161,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
|
||||
fn encode_bounds_and_type(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext,
|
||||
pty: &ty::Polytype) {
|
||||
encode_ty_type_param_defs(rbml_w, ecx, &pty.generics.types,
|
||||
tag_items_data_item_ty_param_bounds);
|
||||
encode_region_param_defs(rbml_w, &pty.generics.regions);
|
||||
encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
|
||||
encode_type(ecx, rbml_w, pty.ty);
|
||||
}
|
||||
|
||||
@ -238,6 +196,33 @@ pub fn write_type(ecx: &EncodeContext,
|
||||
tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ);
|
||||
}
|
||||
|
||||
pub fn write_region(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
r: ty::Region) {
|
||||
let ty_str_ctxt = &tyencode::ctxt {
|
||||
diag: ecx.diag,
|
||||
ds: def_to_string,
|
||||
tcx: ecx.tcx,
|
||||
abbrevs: &ecx.type_abbrevs
|
||||
};
|
||||
tyencode::enc_region(rbml_w.writer, ty_str_ctxt, r);
|
||||
}
|
||||
|
||||
fn encode_bounds(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext,
|
||||
bounds: &ty::ParamBounds,
|
||||
tag: uint) {
|
||||
rbml_w.start_tag(tag);
|
||||
|
||||
let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag,
|
||||
ds: def_to_string,
|
||||
tcx: ecx.tcx,
|
||||
abbrevs: &ecx.type_abbrevs };
|
||||
tyencode::enc_bounds(rbml_w.writer, ty_str_ctxt, bounds);
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_type(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
typ: ty::t) {
|
||||
@ -246,6 +231,14 @@ fn encode_type(ecx: &EncodeContext,
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_region(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
r: ty::Region) {
|
||||
rbml_w.start_tag(tag_items_data_region);
|
||||
write_region(ecx, rbml_w, r);
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_method_fty(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
typ: &ty::BareFnTy) {
|
||||
@ -728,7 +721,6 @@ fn encode_info_for_struct(ecx: &EncodeContext,
|
||||
/* Each class has its own index, since different classes
|
||||
may have fields with the same name */
|
||||
let mut index = Vec::new();
|
||||
let tcx = ecx.tcx;
|
||||
/* We encode both private and public fields -- need to include
|
||||
private fields to get the offsets right */
|
||||
for field in fields.iter() {
|
||||
@ -745,7 +737,8 @@ fn encode_info_for_struct(ecx: &EncodeContext,
|
||||
token::get_name(nm), id);
|
||||
encode_struct_field_family(rbml_w, field.vis);
|
||||
encode_name(rbml_w, nm);
|
||||
encode_type(ecx, rbml_w, node_id_to_type(tcx, id));
|
||||
encode_bounds_and_type(rbml_w, ecx,
|
||||
&lookup_item_type(ecx.tcx, local_def(id)));
|
||||
encode_def_id(rbml_w, local_def(id));
|
||||
|
||||
let stab = stability::lookup(ecx.tcx, field.id);
|
||||
@ -773,7 +766,6 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
|
||||
encode_bounds_and_type(rbml_w, ecx,
|
||||
&lookup_item_type(ecx.tcx, local_def(ctor_id)));
|
||||
encode_name(rbml_w, name.name);
|
||||
encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, ctor_id));
|
||||
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
|
||||
encode_parent_item(rbml_w, local_def(struct_id));
|
||||
|
||||
@ -793,13 +785,60 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_generics(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext,
|
||||
generics: &ty::Generics,
|
||||
tag: uint)
|
||||
{
|
||||
rbml_w.start_tag(tag);
|
||||
|
||||
// Type parameters
|
||||
let ty_str_ctxt = &tyencode::ctxt {
|
||||
diag: ecx.diag,
|
||||
ds: def_to_string,
|
||||
tcx: ecx.tcx,
|
||||
abbrevs: &ecx.type_abbrevs
|
||||
};
|
||||
for param in generics.types.iter() {
|
||||
rbml_w.start_tag(tag_type_param_def);
|
||||
tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
// Region parameters
|
||||
for param in generics.regions.iter() {
|
||||
rbml_w.start_tag(tag_region_param_def);
|
||||
|
||||
rbml_w.start_tag(tag_region_param_def_ident);
|
||||
encode_name(rbml_w, param.name);
|
||||
rbml_w.end_tag();
|
||||
|
||||
rbml_w.wr_tagged_str(tag_region_param_def_def_id,
|
||||
def_to_string(param.def_id).as_slice());
|
||||
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_space,
|
||||
param.space.to_uint() as u64);
|
||||
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_index,
|
||||
param.index as u64);
|
||||
|
||||
for &bound_region in param.bounds.iter() {
|
||||
encode_region(ecx, rbml_w, bound_region);
|
||||
}
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_method_ty_fields(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
method_ty: &ty::Method) {
|
||||
encode_def_id(rbml_w, method_ty.def_id);
|
||||
encode_name(rbml_w, method_ty.ident.name);
|
||||
encode_ty_type_param_defs(rbml_w, ecx, &method_ty.generics.types,
|
||||
tag_item_method_tps);
|
||||
encode_generics(rbml_w, ecx, &method_ty.generics,
|
||||
tag_method_ty_generics);
|
||||
encode_method_fty(ecx, rbml_w, &method_ty.fty);
|
||||
encode_visibility(rbml_w, method_ty.vis);
|
||||
encode_explicit_self(rbml_w, &method_ty.explicit_self);
|
||||
@ -982,7 +1021,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
} else {
|
||||
encode_family(rbml_w, 'c');
|
||||
}
|
||||
encode_type(ecx, rbml_w, node_id_to_type(tcx, item.id));
|
||||
encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
|
||||
encode_symbol(ecx, rbml_w, item.id);
|
||||
encode_name(rbml_w, item.ident.name);
|
||||
encode_path(rbml_w, path);
|
||||
@ -1222,17 +1261,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemTrait(_, _, ref super_traits, ref ms) => {
|
||||
ItemTrait(_, _, _, ref ms) => {
|
||||
add_to_index(item, rbml_w, index);
|
||||
rbml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(rbml_w, def_id);
|
||||
encode_family(rbml_w, 'I');
|
||||
encode_item_variances(rbml_w, ecx, item.id);
|
||||
let trait_def = ty::lookup_trait_def(tcx, def_id);
|
||||
encode_ty_type_param_defs(rbml_w, ecx,
|
||||
&trait_def.generics.types,
|
||||
tag_items_data_item_ty_param_bounds);
|
||||
encode_region_param_defs(rbml_w, &trait_def.generics.regions);
|
||||
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
|
||||
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||
encode_name(rbml_w, item.ident.name);
|
||||
encode_attributes(rbml_w, item.attrs.as_slice());
|
||||
@ -1253,13 +1289,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
encode_path(rbml_w, path.clone());
|
||||
// FIXME(#8559): This should use the tcx's supertrait cache instead of
|
||||
// reading the AST's list, because the former has already filtered out
|
||||
// the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
|
||||
for ast_trait_ref in super_traits.iter() {
|
||||
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
|
||||
encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_super_trait_ref);
|
||||
}
|
||||
|
||||
encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
|
||||
|
||||
// Encode the implementations of this trait.
|
||||
encode_extension_implementations(ecx, rbml_w, def_id);
|
||||
@ -1390,7 +1421,8 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
|
||||
} else {
|
||||
encode_family(rbml_w, 'c');
|
||||
}
|
||||
encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, nitem.id));
|
||||
encode_bounds_and_type(rbml_w, ecx,
|
||||
&lookup_item_type(ecx.tcx,local_def(nitem.id)));
|
||||
encode_symbol(ecx, rbml_w, nitem.id);
|
||||
encode_name(rbml_w, nitem.ident.name);
|
||||
}
|
||||
@ -1434,7 +1466,7 @@ fn my_visit_foreign_item(ni: &ForeignItem,
|
||||
});
|
||||
}
|
||||
|
||||
struct EncodeVisitor<'a,'b> {
|
||||
struct EncodeVisitor<'a,'b:'a> {
|
||||
rbml_w_for_visit_item: &'a mut Encoder<'b>,
|
||||
ecx_ptr:*const int,
|
||||
index: &'a mut Vec<entry<i64>>,
|
||||
@ -1738,7 +1770,7 @@ fn encode_unboxed_closures<'a>(
|
||||
}
|
||||
|
||||
fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
|
||||
struct StructFieldVisitor<'a, 'b> {
|
||||
struct StructFieldVisitor<'a, 'b:'a> {
|
||||
rbml_w: &'a mut Encoder<'b>,
|
||||
}
|
||||
|
||||
@ -1760,7 +1792,7 @@ fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
|
||||
|
||||
|
||||
|
||||
struct ImplVisitor<'a,'b,'c> {
|
||||
struct ImplVisitor<'a,'b:'a,'c:'a> {
|
||||
ecx: &'a EncodeContext<'b>,
|
||||
rbml_w: &'a mut Encoder<'c>,
|
||||
}
|
||||
|
@ -147,6 +147,13 @@ pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty:
|
||||
parse_ty(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
|
||||
conv: conv_did) -> ty::Region {
|
||||
debug!("parse_region_data {}", data_log_string(data, pos));
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_region(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
|
||||
conv: conv_did) -> ty::BareFnTy {
|
||||
debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
|
||||
@ -168,6 +175,27 @@ pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx:
|
||||
parse_substs(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_bounds_data(data: &[u8], crate_num: ast::CrateNum,
|
||||
pos: uint, tcx: &ty::ctxt, conv: conv_did)
|
||||
-> ty::ParamBounds {
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_bounds(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum,
|
||||
pos: uint, tcx: &ty::ctxt, conv: conv_did)
|
||||
-> ty::ExistentialBounds {
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_existential_bounds(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum,
|
||||
pos: uint, tcx: &ty::ctxt, conv: conv_did)
|
||||
-> ty::BuiltinBounds {
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_builtin_bounds(&mut st, conv)
|
||||
}
|
||||
|
||||
fn parse_size(st: &mut PState) -> Option<uint> {
|
||||
assert_eq!(next(st), '/');
|
||||
|
||||
@ -355,9 +383,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
assert_eq!(next(st), '[');
|
||||
let def = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||
let substs = parse_substs(st, |x,y| conv(x,y));
|
||||
let bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
|
||||
assert_eq!(next(st), ']');
|
||||
return ty::mk_trait(st.tcx, def, substs, bounds.builtin_bounds);
|
||||
return ty::mk_trait(st.tcx, def, substs, bounds);
|
||||
}
|
||||
'p' => {
|
||||
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
|
||||
@ -515,14 +543,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
|
||||
let fn_style = parse_fn_style(next(st));
|
||||
let onceness = parse_onceness(next(st));
|
||||
let store = parse_trait_store(st, |x,y| conv(x,y));
|
||||
let bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
|
||||
let sig = parse_sig(st, |x,y| conv(x,y));
|
||||
let abi = parse_abi_set(st);
|
||||
ty::ClosureTy {
|
||||
fn_style: fn_style,
|
||||
onceness: onceness,
|
||||
store: store,
|
||||
bounds: bounds.builtin_bounds,
|
||||
bounds: bounds,
|
||||
sig: sig,
|
||||
abi: abi,
|
||||
}
|
||||
@ -601,7 +629,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
|
||||
assert_eq!(next(st), '|');
|
||||
let index = parse_uint(st);
|
||||
assert_eq!(next(st), '|');
|
||||
let bounds = Rc::new(parse_bounds(st, |x,y| conv(x,y)));
|
||||
let bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
|
||||
|
||||
ty::TypeParameterDef {
|
||||
@ -614,27 +642,51 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds {
|
||||
let r = parse_region(st, |x,y| conv(x,y));
|
||||
let bb = parse_builtin_bounds(st, conv);
|
||||
return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb };
|
||||
}
|
||||
|
||||
fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds {
|
||||
let mut builtin_bounds = ty::empty_builtin_bounds();
|
||||
|
||||
loop {
|
||||
match next(st) {
|
||||
'S' => {
|
||||
builtin_bounds.add(ty::BoundSend);
|
||||
}
|
||||
'Z' => {
|
||||
builtin_bounds.add(ty::BoundSized);
|
||||
}
|
||||
'P' => {
|
||||
builtin_bounds.add(ty::BoundCopy);
|
||||
}
|
||||
'T' => {
|
||||
builtin_bounds.add(ty::BoundSync);
|
||||
}
|
||||
'.' => {
|
||||
return builtin_bounds;
|
||||
}
|
||||
c => {
|
||||
fail!("parse_bounds: bad builtin bounds ('{}')", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
|
||||
let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));
|
||||
|
||||
let mut param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
opt_region_bound: None,
|
||||
builtin_bounds: builtin_bounds,
|
||||
trait_bounds: Vec::new()
|
||||
};
|
||||
loop {
|
||||
match next(st) {
|
||||
'S' => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundSend);
|
||||
}
|
||||
'O' => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
'Z' => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundSized);
|
||||
}
|
||||
'P' => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundCopy);
|
||||
}
|
||||
'T' => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundSync);
|
||||
'R' => {
|
||||
param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
|
||||
}
|
||||
'I' => {
|
||||
param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));
|
||||
|
@ -127,7 +127,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
|
||||
pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
|
||||
match r {
|
||||
ty::ReLateBound(id, br) => {
|
||||
mywrite!(w, "b[{}|", id);
|
||||
@ -232,13 +232,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
def_id,
|
||||
ref substs,
|
||||
bounds
|
||||
ref bounds
|
||||
}) => {
|
||||
mywrite!(w, "x[{}|", (cx.ds)(def_id));
|
||||
enc_substs(w, cx, substs);
|
||||
let bounds = ty::ParamBounds {builtin_bounds: bounds,
|
||||
trait_bounds: Vec::new()};
|
||||
enc_bounds(w, cx, &bounds);
|
||||
enc_existential_bounds(w, cx, bounds);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_tup(ref ts) => {
|
||||
@ -328,9 +326,7 @@ pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy)
|
||||
enc_fn_style(w, ft.fn_style);
|
||||
enc_onceness(w, ft.onceness);
|
||||
enc_trait_store(w, cx, ft.store);
|
||||
let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
|
||||
trait_bounds: Vec::new()};
|
||||
enc_bounds(w, cx, &bounds);
|
||||
enc_existential_bounds(w, cx, &ft.bounds);
|
||||
enc_fn_sig(w, cx, &ft.sig);
|
||||
enc_abi(w, ft.abi);
|
||||
}
|
||||
@ -349,17 +345,32 @@ fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
|
||||
enc_ty(w, cx, fsig.output);
|
||||
}
|
||||
|
||||
fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
|
||||
for bound in bs.builtin_bounds.iter() {
|
||||
pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
|
||||
for bound in bs.iter() {
|
||||
match bound {
|
||||
ty::BoundSend => mywrite!(w, "S"),
|
||||
ty::BoundStatic => mywrite!(w, "O"),
|
||||
ty::BoundSized => mywrite!(w, "Z"),
|
||||
ty::BoundCopy => mywrite!(w, "P"),
|
||||
ty::BoundSync => mywrite!(w, "T"),
|
||||
}
|
||||
}
|
||||
|
||||
mywrite!(w, ".");
|
||||
}
|
||||
|
||||
pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) {
|
||||
enc_region(w, cx, bs.region_bound);
|
||||
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
|
||||
}
|
||||
|
||||
pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
|
||||
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
|
||||
|
||||
for &r in bs.opt_region_bound.iter() {
|
||||
mywrite!(w, "R");
|
||||
enc_region(w, cx, r);
|
||||
}
|
||||
|
||||
for tp in bs.trait_bounds.iter() {
|
||||
mywrite!(w, "I");
|
||||
enc_trait_ref(w, cx, &**tp);
|
||||
@ -372,6 +383,6 @@ pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypePara
|
||||
mywrite!(w, "{}:{}|{}|{}|",
|
||||
token::get_ident(v.ident), (cx.ds)(v.def_id),
|
||||
v.space.to_uint(), v.index);
|
||||
enc_bounds(w, cx, &*v.bounds);
|
||||
enc_bounds(w, cx, &v.bounds);
|
||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||
}
|
||||
|
@ -942,6 +942,8 @@ trait rbml_writer_helpers {
|
||||
ecx: &e::EncodeContext,
|
||||
pty: ty::Polytype);
|
||||
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs);
|
||||
fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds);
|
||||
fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
|
||||
fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment);
|
||||
fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef);
|
||||
fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef);
|
||||
@ -1001,6 +1003,18 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds) {
|
||||
self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer,
|
||||
&ecx.ty_str_ctxt(),
|
||||
bounds)));
|
||||
}
|
||||
|
||||
fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) {
|
||||
self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this.writer,
|
||||
&ecx.ty_str_ctxt(),
|
||||
bounds)));
|
||||
}
|
||||
|
||||
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs) {
|
||||
self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer,
|
||||
&ecx.ty_str_ctxt(),
|
||||
@ -1100,9 +1114,10 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
|
||||
this.emit_enum_variant_arg(1, |this| idx.encode(this))
|
||||
})
|
||||
}
|
||||
ty::UnsizeVtable(b, def_id, ref substs) => {
|
||||
ty::UnsizeVtable(ref b, def_id, ref substs) => {
|
||||
this.emit_enum_variant("UnsizeVtable", 2, 3, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| b.encode(this));
|
||||
this.emit_enum_variant_arg(
|
||||
0, |this| Ok(this.emit_existential_bounds(ecx, b)));
|
||||
this.emit_enum_variant_arg(1, |this| def_id.encode(this));
|
||||
this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs)))
|
||||
})
|
||||
@ -1131,7 +1146,7 @@ impl<'a> write_tag_and_id for Encoder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
struct SideTableEncodingIdVisitor<'a,'b> {
|
||||
struct SideTableEncodingIdVisitor<'a,'b:'a> {
|
||||
ecx_ptr: *const libc::c_void,
|
||||
new_rbml_w: &'a mut Encoder<'b>,
|
||||
}
|
||||
@ -1380,6 +1395,7 @@ trait rbml_decoder_decoder_helpers {
|
||||
-> ty::TypeParameterDef;
|
||||
fn read_polytype(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> ty::Polytype;
|
||||
fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds;
|
||||
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
|
||||
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
|
||||
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
||||
@ -1514,6 +1530,17 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds
|
||||
{
|
||||
self.read_opaque(|this, doc| {
|
||||
Ok(tydecode::parse_existential_bounds_data(doc.data,
|
||||
xcx.dcx.cdata.cnum,
|
||||
doc.start,
|
||||
xcx.dcx.tcx,
|
||||
|s, a| this.convert_def_id(xcx, s, a)))
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs {
|
||||
self.read_opaque(|this, doc| {
|
||||
Ok(tydecode::parse_substs_data(doc.data,
|
||||
@ -1638,8 +1665,9 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
ty::UnsizeStruct(box uk, idx)
|
||||
}
|
||||
2 => {
|
||||
let b: ty::BuiltinBounds =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
let b =
|
||||
this.read_enum_variant_arg(
|
||||
0, |this| Ok(this.read_existential_bounds(xcx))).unwrap();
|
||||
let def_id: ast::DefId =
|
||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||
let substs = this.read_enum_variant_arg(2,
|
||||
|
@ -79,12 +79,14 @@ impl<'a> CFGBuilder<'a> {
|
||||
|
||||
fn stmt(&mut self, stmt: Gc<ast::Stmt>, pred: CFGIndex) -> CFGIndex {
|
||||
match stmt.node {
|
||||
ast::StmtDecl(ref decl, _) => {
|
||||
self.decl(&**decl, pred)
|
||||
ast::StmtDecl(ref decl, id) => {
|
||||
let exit = self.decl(&**decl, pred);
|
||||
self.add_node(id, [exit])
|
||||
}
|
||||
|
||||
ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => {
|
||||
self.expr(expr.clone(), pred)
|
||||
ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
|
||||
let exit = self.expr(expr.clone(), pred);
|
||||
self.add_node(id, [exit])
|
||||
}
|
||||
|
||||
ast::StmtMac(..) => {
|
||||
|
@ -1018,7 +1018,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) {
|
||||
visitor.visit_pat(pat, true);
|
||||
}
|
||||
|
||||
struct AtBindingPatternVisitor<'a,'b> {
|
||||
struct AtBindingPatternVisitor<'a,'b:'a> {
|
||||
cx: &'a MatchCheckCtxt<'b>,
|
||||
}
|
||||
|
||||
|
@ -80,11 +80,18 @@ pub trait DataFlowOperator : BitwiseOperator {
|
||||
fn initial_value(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct PropagationContext<'a, 'b, O> {
|
||||
dfcx: &'a mut DataFlowContext<'b, O>,
|
||||
changed: bool
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
struct PropagationContext<'a, 'b:'a, O:'a> {
|
||||
dfcx: &'a mut DataFlowContext<'b, O>,
|
||||
changed: bool
|
||||
}
|
||||
|
||||
fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
|
||||
let opt_cfgindex = index.find(&id).map(|&i|i);
|
||||
opt_cfgindex.unwrap_or_else(|| {
|
||||
@ -458,7 +465,7 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> {
|
||||
});
|
||||
}
|
||||
|
||||
fn pretty_print_to(&self, wr: Box<io::Writer>,
|
||||
fn pretty_print_to(&self, wr: Box<io::Writer+'static>,
|
||||
blk: &ast::Block) -> io::IoResult<()> {
|
||||
let mut ps = pprust::rust_printer_annotated(wr, self);
|
||||
try!(ps.cbox(pprust::indent_unit));
|
||||
|
@ -192,10 +192,18 @@ impl OverloadedCallType {
|
||||
// supplies types from the tree. After type checking is complete, you
|
||||
// can just use the tcx as the typer.
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub struct ExprUseVisitor<'d,'t,TYPER> {
|
||||
typer: &'t TYPER,
|
||||
mc: mc::MemCategorizationContext<'t,TYPER>,
|
||||
delegate: &'d mut Delegate,
|
||||
delegate: &'d mut Delegate+'d,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub struct ExprUseVisitor<'d,'t,TYPER:'t> {
|
||||
typer: &'t TYPER,
|
||||
mc: mc::MemCategorizationContext<'t,TYPER>,
|
||||
delegate: &'d mut Delegate+'d,
|
||||
}
|
||||
|
||||
// If the TYPER results in an error, it's because the type check
|
||||
|
@ -64,6 +64,7 @@ pub struct EdgeIndex(pub uint);
|
||||
pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
|
||||
|
||||
// Use a private field here to guarantee no more instances are created:
|
||||
#[deriving(Show)]
|
||||
pub struct Direction { repr: uint }
|
||||
pub static Outgoing: Direction = Direction { repr: 0 };
|
||||
pub static Incoming: Direction = Direction { repr: 1 };
|
||||
|
@ -144,14 +144,17 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
|
||||
// If this trait has builtin-kind supertraits, meet them.
|
||||
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
|
||||
debug!("checking impl with self type {}", ty::get(self_ty).sty);
|
||||
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
|
||||
span_err!(cx.tcx.sess, self_type.span, E0142,
|
||||
"the type `{}', which does not fulfill `{}`, cannot implement this trait",
|
||||
ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
|
||||
span_note!(cx.tcx.sess, self_type.span,
|
||||
"types implementing this trait must fulfill `{}`",
|
||||
trait_def.bounds.user_string(cx.tcx));
|
||||
});
|
||||
check_builtin_bounds(
|
||||
cx, self_ty, trait_def.bounds.builtin_bounds,
|
||||
|missing| {
|
||||
span_err!(cx.tcx.sess, self_type.span, E0142,
|
||||
"the type `{}', which does not fulfill `{}`, \
|
||||
cannot implement this trait",
|
||||
ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
|
||||
span_note!(cx.tcx.sess, self_type.span,
|
||||
"types implementing this trait must fulfill `{}`",
|
||||
trait_def.bounds.user_string(cx.tcx));
|
||||
});
|
||||
|
||||
// If this is a destructor, check kinds.
|
||||
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
|
||||
@ -297,17 +300,15 @@ fn with_appropriate_checker(cx: &Context,
|
||||
match ty::get(fty).sty {
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::UniqTraitStore,
|
||||
bounds: mut bounds, ..
|
||||
bounds: bounds,
|
||||
..
|
||||
}) => {
|
||||
// Procs can't close over non-static references!
|
||||
bounds.add(ty::BoundStatic);
|
||||
|
||||
b(|cx, fv| check_for_uniq(cx, fv, bounds))
|
||||
b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds))
|
||||
}
|
||||
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(region, _), bounds, ..
|
||||
}) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
|
||||
}) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)),
|
||||
|
||||
ty::ty_bare_fn(_) => {
|
||||
b(check_for_bare)
|
||||
@ -377,13 +378,6 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
expression_type);
|
||||
|
||||
match e.node {
|
||||
ExprBox(ref loc, ref interior) => {
|
||||
let def = ty::resolve_expr(cx.tcx, &**loc);
|
||||
if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
|
||||
let interior_type = ty::expr_ty(cx.tcx, &**interior);
|
||||
let _ = check_static(cx.tcx, interior_type, interior.span);
|
||||
}
|
||||
}
|
||||
ExprCast(ref source, _) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
||||
let target_ty = ty::expr_ty(cx.tcx, e);
|
||||
@ -562,7 +556,6 @@ fn check_trait_cast(cx: &mut Context,
|
||||
target_ty: ty::t,
|
||||
span: Span,
|
||||
method_call: MethodCall) {
|
||||
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
|
||||
match ty::get(ty).sty {
|
||||
@ -580,7 +573,8 @@ fn check_trait_cast(cx: &mut Context,
|
||||
vtable_res)
|
||||
}
|
||||
};
|
||||
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
||||
check_trait_cast_bounds(cx, span, source_ty,
|
||||
bounds.builtin_bounds);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -620,7 +614,7 @@ pub fn check_builtin_bounds(cx: &Context,
|
||||
let kind = ty::type_contents(cx.tcx, ty);
|
||||
let mut missing = ty::empty_builtin_bounds();
|
||||
for bound in bounds.iter() {
|
||||
if !kind.meets_bound(cx.tcx, bound) {
|
||||
if !kind.meets_builtin_bound(cx.tcx, bound) {
|
||||
missing.add(bound);
|
||||
}
|
||||
}
|
||||
@ -764,132 +758,6 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
|
||||
if !ty::type_is_static(tcx, ty) {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_param(..) => {
|
||||
span_err!(tcx.sess, sp, E0149,
|
||||
"value may contain references; \
|
||||
add `'static` bound to `{}`",
|
||||
ty_to_string(tcx, ty));
|
||||
}
|
||||
_ => {
|
||||
span_err!(tcx.sess, sp, E0150,
|
||||
"value may contain references");
|
||||
}
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// This is rather subtle. When we are casting a value to an instantiated
|
||||
/// trait like `a as trait<'r>`, regionck already ensures that any references
|
||||
/// that appear in the type of `a` are bounded by `'r` (ed.: rem
|
||||
/// FIXME(#5723)). However, it is possible that there are *type parameters*
|
||||
/// in the type of `a`, and those *type parameters* may have references
|
||||
/// within them. We have to guarantee that the regions which appear in those
|
||||
/// type parameters are not obscured.
|
||||
///
|
||||
/// Therefore, we ensure that one of three conditions holds:
|
||||
///
|
||||
/// (1) The trait instance cannot escape the current fn. This is
|
||||
/// guaranteed if the region bound `&r` is some scope within the fn
|
||||
/// itself. This case is safe because whatever references are
|
||||
/// found within the type parameter, they must enclose the fn body
|
||||
/// itself.
|
||||
///
|
||||
/// (2) The type parameter appears in the type of the trait. For
|
||||
/// example, if the type parameter is `T` and the trait type is
|
||||
/// `deque<T>`, then whatever references may appear in `T` also
|
||||
/// appear in `deque<T>`.
|
||||
///
|
||||
/// (3) The type parameter is sendable (and therefore does not contain
|
||||
/// references).
|
||||
///
|
||||
/// FIXME(#5723)---This code should probably move into regionck.
|
||||
pub fn check_cast_for_escaping_regions(
|
||||
cx: &Context,
|
||||
source_ty: ty::t,
|
||||
target_ty: ty::t,
|
||||
source_span: Span)
|
||||
{
|
||||
// Determine what type we are casting to; if it is not a trait, then no
|
||||
// worries.
|
||||
if !ty::type_is_trait(target_ty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect up the regions that appear in the target type. We want to
|
||||
// ensure that these lifetimes are shorter than all lifetimes that are in
|
||||
// the source type. See test `src/test/compile-fail/regions-trait-2.rs`
|
||||
let mut target_regions = Vec::new();
|
||||
ty::walk_regions_and_ty(
|
||||
cx.tcx,
|
||||
target_ty,
|
||||
|r| {
|
||||
if !r.is_bound() {
|
||||
target_regions.push(r);
|
||||
}
|
||||
},
|
||||
|_| ());
|
||||
|
||||
// Check, based on the region associated with the trait, whether it can
|
||||
// possibly escape the enclosing fn item (note that all type parameters
|
||||
// must have been declared on the enclosing fn item).
|
||||
if target_regions.iter().any(|r| is_ReScope(*r)) {
|
||||
return; /* case (1) */
|
||||
}
|
||||
|
||||
// Assuming the trait instance can escape, then ensure that each parameter
|
||||
// either appears in the trait type or is sendable.
|
||||
let target_params = ty::param_tys_in_type(target_ty);
|
||||
ty::walk_regions_and_ty(
|
||||
cx.tcx,
|
||||
source_ty,
|
||||
|
||||
|_r| {
|
||||
// FIXME(#5723) --- turn this check on once &Objects are usable
|
||||
//
|
||||
// if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
|
||||
// cx.tcx.sess.span_err(
|
||||
// source_span,
|
||||
// format!("source contains reference with lifetime \
|
||||
// not found in the target type `{}`",
|
||||
// ty_to_string(cx.tcx, target_ty)));
|
||||
// note_and_explain_region(
|
||||
// cx.tcx, "source data is only valid for ", r, "");
|
||||
// }
|
||||
},
|
||||
|
||||
|ty| {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_param(source_param) => {
|
||||
if source_param.space == subst::SelfSpace {
|
||||
// FIXME (#5723) -- there is no reason that
|
||||
// Self should be exempt from this check,
|
||||
// except for historical accident. Bottom
|
||||
// line, we need proper region bounding.
|
||||
} else if target_params.iter().any(|x| x == &source_param) {
|
||||
/* case (2) */
|
||||
} else {
|
||||
check_static(cx.tcx, ty, source_span); /* case (3) */
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
#[allow(non_snake_case_functions)]
|
||||
fn is_ReScope(r: ty::Region) -> bool {
|
||||
match r {
|
||||
ty::ReScope(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
|
||||
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
|
||||
if !ty::type_is_sized(tcx, ty) {
|
||||
|
@ -240,10 +240,16 @@ impl ast_node for ast::Pat {
|
||||
fn span(&self) -> Span { self.span }
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub struct MemCategorizationContext<'t,TYPER> {
|
||||
typer: &'t TYPER
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MemCategorizationContext<'t,TYPER:'t> {
|
||||
typer: &'t TYPER
|
||||
}
|
||||
|
||||
pub type McResult<T> = Result<T, ()>;
|
||||
|
||||
/**
|
||||
|
@ -1221,8 +1221,8 @@ struct VisiblePrivateTypesVisitor<'a> {
|
||||
public_items: &'a PublicItems,
|
||||
}
|
||||
|
||||
struct CheckTypeForPrivatenessVisitor<'a, 'b> {
|
||||
inner: &'b VisiblePrivateTypesVisitor<'a>,
|
||||
struct CheckTypeForPrivatenessVisitor<'a, 'b:'a> {
|
||||
inner: &'a VisiblePrivateTypesVisitor<'b>,
|
||||
/// whether the type refers to private types.
|
||||
contains_private: bool,
|
||||
/// whether we've recurred at all (i.e. if we're pointing at the
|
||||
|
@ -25,6 +25,7 @@ use driver::session::Session;
|
||||
use middle::ty::{FreeRegion};
|
||||
use middle::ty;
|
||||
use util::nodemap::NodeMap;
|
||||
use util::common::can_reach;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -78,7 +79,7 @@ The region maps encode information about region relationships.
|
||||
pub struct RegionMaps {
|
||||
scope_map: RefCell<NodeMap<ast::NodeId>>,
|
||||
var_map: RefCell<NodeMap<ast::NodeId>>,
|
||||
free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion> >>,
|
||||
free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion>>>,
|
||||
rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
|
||||
terminating_scopes: RefCell<HashSet<ast::NodeId>>,
|
||||
}
|
||||
@ -255,34 +256,7 @@ impl RegionMaps {
|
||||
* (that is, the user can give two different names to the same lifetime).
|
||||
*/
|
||||
|
||||
if sub == sup {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do a little breadth-first-search here. The `queue` list
|
||||
// doubles as a way to detect if we've seen a particular FR
|
||||
// before. Note that we expect this graph to be an *extremely
|
||||
// shallow* tree.
|
||||
let mut queue = vec!(sub);
|
||||
let mut i = 0;
|
||||
while i < queue.len() {
|
||||
match self.free_region_map.borrow().find(queue.get(i)) {
|
||||
Some(parents) => {
|
||||
for parent in parents.iter() {
|
||||
if *parent == sup {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !queue.iter().any(|x| x == parent) {
|
||||
queue.push(*parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return false;
|
||||
can_reach(&*self.free_region_map.borrow(), sub, sup)
|
||||
}
|
||||
|
||||
pub fn is_subregion_of(&self,
|
||||
@ -300,6 +274,7 @@ impl RegionMaps {
|
||||
|
||||
sub_region == super_region || {
|
||||
match (sub_region, super_region) {
|
||||
(ty::ReEmpty, _) |
|
||||
(_, ty::ReStatic) => {
|
||||
true
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
|
||||
use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
|
||||
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method};
|
||||
use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
|
||||
use syntax::ast::{OtherRegionTyParamBound, P, Pat, PatEnum, PatIdent, PatLit};
|
||||
use syntax::ast::{P, Pat, PatEnum, PatIdent, PatLit};
|
||||
use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
|
||||
use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic};
|
||||
use syntax::ast::{StaticRegionTyParamBound, StmtDecl, StructField};
|
||||
use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
|
||||
use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
|
||||
use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
|
||||
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
|
||||
@ -901,7 +901,7 @@ struct Resolver<'a> {
|
||||
used_imports: HashSet<(NodeId, Namespace)>,
|
||||
}
|
||||
|
||||
struct BuildReducedGraphVisitor<'a, 'b> {
|
||||
struct BuildReducedGraphVisitor<'a, 'b:'a> {
|
||||
resolver: &'a mut Resolver<'b>,
|
||||
}
|
||||
|
||||
@ -933,7 +933,9 @@ impl<'a, 'b> Visitor<ReducedGraphParent> for BuildReducedGraphVisitor<'a, 'b> {
|
||||
|
||||
}
|
||||
|
||||
struct UnusedImportCheckVisitor<'a, 'b> { resolver: &'a mut Resolver<'b> }
|
||||
struct UnusedImportCheckVisitor<'a, 'b:'a> {
|
||||
resolver: &'a mut Resolver<'b>
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> {
|
||||
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
|
||||
@ -3946,7 +3948,7 @@ impl<'a> Resolver<'a> {
|
||||
impl_items.as_slice());
|
||||
}
|
||||
|
||||
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
|
||||
ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
|
||||
// Create a new rib for the self type.
|
||||
let self_type_rib = Rib::new(ItemRibKind);
|
||||
|
||||
@ -3965,10 +3967,9 @@ impl<'a> Resolver<'a> {
|
||||
this.resolve_type_parameters(&generics.ty_params);
|
||||
this.resolve_where_clause(&generics.where_clause);
|
||||
|
||||
// Resolve derived traits.
|
||||
for trt in traits.iter() {
|
||||
this.resolve_trait_reference(item.id, trt, TraitDerivation);
|
||||
}
|
||||
this.resolve_type_parameter_bounds(item.id, bounds,
|
||||
TraitDerivation);
|
||||
|
||||
match unbound {
|
||||
&Some(ast::TraitTyParamBound(ref tpb)) => {
|
||||
this.resolve_trait_reference(item.id, tpb, TraitDerivation);
|
||||
@ -4199,10 +4200,13 @@ impl<'a> Resolver<'a> {
|
||||
type_parameters: &OwnedSlice<TyParam>) {
|
||||
for type_parameter in type_parameters.iter() {
|
||||
for bound in type_parameter.bounds.iter() {
|
||||
self.resolve_type_parameter_bound(type_parameter.id, bound);
|
||||
self.resolve_type_parameter_bound(type_parameter.id, bound,
|
||||
TraitBoundingTypeParameter);
|
||||
}
|
||||
match &type_parameter.unbound {
|
||||
&Some(ref unbound) => self.resolve_type_parameter_bound(type_parameter.id, unbound),
|
||||
&Some(ref unbound) =>
|
||||
self.resolve_type_parameter_bound(
|
||||
type_parameter.id, unbound, TraitBoundingTypeParameter),
|
||||
&None => {}
|
||||
}
|
||||
match type_parameter.default {
|
||||
@ -4212,12 +4216,23 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_type_parameter_bounds(&mut self,
|
||||
id: NodeId,
|
||||
type_parameter_bounds: &OwnedSlice<TyParamBound>,
|
||||
reference_type: TraitReferenceType) {
|
||||
for type_parameter_bound in type_parameter_bounds.iter() {
|
||||
self.resolve_type_parameter_bound(id, type_parameter_bound,
|
||||
reference_type);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_type_parameter_bound(&mut self,
|
||||
id: NodeId,
|
||||
type_parameter_bound: &TyParamBound) {
|
||||
type_parameter_bound: &TyParamBound,
|
||||
reference_type: TraitReferenceType) {
|
||||
match *type_parameter_bound {
|
||||
TraitTyParamBound(ref tref) => {
|
||||
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
|
||||
self.resolve_trait_reference(id, tref, reference_type)
|
||||
}
|
||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||
for argument in unboxed_function.decl.inputs.iter() {
|
||||
@ -4226,7 +4241,7 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
self.resolve_type(&*unboxed_function.decl.output);
|
||||
}
|
||||
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
|
||||
RegionTyParamBound(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4240,7 +4255,7 @@ impl<'a> Resolver<'a> {
|
||||
let usage_str = match reference_type {
|
||||
TraitBoundingTypeParameter => "bound type parameter with",
|
||||
TraitImplementation => "implement",
|
||||
TraitDerivation => "derive"
|
||||
TraitDerivation => "derive",
|
||||
};
|
||||
|
||||
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
|
||||
@ -4295,7 +4310,8 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
for bound in predicate.bounds.iter() {
|
||||
self.resolve_type_parameter_bound(predicate.id, bound);
|
||||
self.resolve_type_parameter_bound(predicate.id, bound,
|
||||
TraitBoundingTypeParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4679,18 +4695,14 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
bounds.as_ref().map(|bound_vec| {
|
||||
for bound in bound_vec.iter() {
|
||||
self.resolve_type_parameter_bound(ty.id, bound);
|
||||
}
|
||||
self.resolve_type_parameter_bounds(ty.id, bound_vec,
|
||||
TraitBoundingTypeParameter);
|
||||
});
|
||||
}
|
||||
|
||||
TyClosure(c, _) | TyProc(c) => {
|
||||
c.bounds.as_ref().map(|bounds| {
|
||||
for bound in bounds.iter() {
|
||||
self.resolve_type_parameter_bound(ty.id, bound);
|
||||
}
|
||||
});
|
||||
TyClosure(c) | TyProc(c) => {
|
||||
self.resolve_type_parameter_bounds(ty.id, &c.bounds,
|
||||
TraitBoundingTypeParameter);
|
||||
visit::walk_ty(self, ty, ());
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ use driver::session::Session;
|
||||
use middle::subst;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust::{lifetime_to_string};
|
||||
@ -99,8 +98,10 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
|
||||
ast::ItemStruct(_, ref generics) |
|
||||
ast::ItemImpl(ref generics, _, _, _) |
|
||||
ast::ItemTrait(ref generics, _, _, _) => {
|
||||
self.check_lifetime_names(&generics.lifetimes);
|
||||
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root)
|
||||
let scope: ScopeChain =
|
||||
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root);
|
||||
self.check_lifetime_defs(&generics.lifetimes, &scope);
|
||||
scope
|
||||
}
|
||||
};
|
||||
debug!("entering scope {:?}", scope);
|
||||
@ -126,7 +127,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
|
||||
|
||||
fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) {
|
||||
match ty.node {
|
||||
ast::TyClosure(c, _) | ast::TyProc(c) => {
|
||||
ast::TyClosure(c) | ast::TyProc(c) => {
|
||||
push_fn_scope(self, ty, scope, &c.lifetimes);
|
||||
}
|
||||
ast::TyBareFn(c) => push_fn_scope(self, ty, scope, &c.lifetimes),
|
||||
@ -137,8 +138,8 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
|
||||
ty: &ast::Ty,
|
||||
scope: Scope,
|
||||
lifetimes: &Vec<ast::LifetimeDef>) {
|
||||
let scope1 = LateScope(ty.id, lifetimes, scope);
|
||||
this.check_lifetime_names(lifetimes);
|
||||
let scope1: ScopeChain = LateScope(ty.id, lifetimes, scope);
|
||||
this.check_lifetime_defs(lifetimes, &scope1);
|
||||
debug!("pushing fn scope id={} due to type", ty.id);
|
||||
visit::walk_ty(this, ty, &scope1);
|
||||
debug!("popping fn scope id={} due to type", ty.id);
|
||||
@ -204,24 +205,22 @@ impl<'a> LifetimeContext<'a> {
|
||||
* the ordering is not important there.
|
||||
*/
|
||||
|
||||
self.check_lifetime_names(&generics.lifetimes);
|
||||
|
||||
let referenced_idents = free_lifetimes(&generics.ty_params,
|
||||
&generics.where_clause);
|
||||
let referenced_idents = early_bound_lifetime_names(generics);
|
||||
debug!("pushing fn scope id={} due to fn item/method\
|
||||
referenced_idents={:?}",
|
||||
n,
|
||||
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
|
||||
if referenced_idents.is_empty() {
|
||||
let scope1 = LateScope(n, &generics.lifetimes, scope);
|
||||
walk(self, &scope1)
|
||||
let scope1: ScopeChain = LateScope(n, &generics.lifetimes, scope);
|
||||
self.check_lifetime_defs(&generics.lifetimes, &scope1);
|
||||
walk(self, &scope1);
|
||||
} else {
|
||||
let (early, late) = generics.lifetimes.clone().partition(
|
||||
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
||||
|
||||
let scope1 = EarlyScope(subst::FnSpace, &early, scope);
|
||||
let scope2 = LateScope(n, &late, &scope1);
|
||||
|
||||
let scope2: ScopeChain = LateScope(n, &late, &scope1);
|
||||
self.check_lifetime_defs(&generics.lifetimes, &scope2);
|
||||
walk(self, &scope2);
|
||||
}
|
||||
debug!("popping fn scope id={} due to fn item/method", n);
|
||||
@ -335,7 +334,9 @@ impl<'a> LifetimeContext<'a> {
|
||||
token::get_name(lifetime_ref.name)).as_slice());
|
||||
}
|
||||
|
||||
fn check_lifetime_names(&self, lifetimes: &Vec<ast::LifetimeDef>) {
|
||||
fn check_lifetime_defs<'b>(&mut self,
|
||||
lifetimes: &Vec<ast::LifetimeDef>,
|
||||
scope: Scope<'b>) {
|
||||
for i in range(0, lifetimes.len()) {
|
||||
let lifetime_i = lifetimes.get(i);
|
||||
|
||||
@ -364,11 +365,7 @@ impl<'a> LifetimeContext<'a> {
|
||||
}
|
||||
|
||||
for bound in lifetime_i.bounds.iter() {
|
||||
if !self.sess.features.issue_5723_bootstrap.get() {
|
||||
self.sess.span_err(
|
||||
bound.span,
|
||||
"region bounds require `issue_5723_bootstrap`");
|
||||
}
|
||||
self.resolve_lifetime_ref(bound, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -404,8 +401,7 @@ fn search_lifetimes(lifetimes: &Vec<ast::LifetimeDef>,
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
|
||||
let referenced_idents = free_lifetimes(&generics.ty_params,
|
||||
&generics.where_clause);
|
||||
let referenced_idents = early_bound_lifetime_names(generics);
|
||||
if referenced_idents.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
@ -416,34 +412,72 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::Lifeti
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn free_lifetimes(ty_params: &OwnedSlice<ast::TyParam>,
|
||||
where_clause: &ast::WhereClause)
|
||||
-> Vec<ast::Name> {
|
||||
fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
|
||||
/*!
|
||||
* Gathers up and returns the names of any lifetimes that appear
|
||||
* free in `ty_params`. Of course, right now, all lifetimes appear
|
||||
* free, since we don't currently have any binders in type parameter
|
||||
* declarations; just being forwards compatible with future extensions.
|
||||
* Given a set of generic declarations, returns a list of names
|
||||
* containing all early bound lifetime names for those
|
||||
* generics. (In fact, this list may also contain other names.)
|
||||
*/
|
||||
|
||||
let mut collector = FreeLifetimeCollector { names: vec!() };
|
||||
for ty_param in ty_params.iter() {
|
||||
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
|
||||
}
|
||||
for predicate in where_clause.predicates.iter() {
|
||||
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
|
||||
}
|
||||
return collector.names;
|
||||
// Create two lists, dividing the lifetimes into early/late bound.
|
||||
// Initially, all of them are considered late, but we will move
|
||||
// things from late into early as we go if we find references to
|
||||
// them.
|
||||
let mut early_bound = Vec::new();
|
||||
let mut late_bound = generics.lifetimes.iter()
|
||||
.map(|l| l.lifetime.name)
|
||||
.collect();
|
||||
|
||||
struct FreeLifetimeCollector {
|
||||
names: Vec<ast::Name>,
|
||||
// Any lifetime that appears in a type bound is early.
|
||||
{
|
||||
let mut collector =
|
||||
FreeLifetimeCollector { early_bound: &mut early_bound,
|
||||
late_bound: &mut late_bound };
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
|
||||
}
|
||||
for predicate in generics.where_clause.predicates.iter() {
|
||||
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<()> for FreeLifetimeCollector {
|
||||
// Any lifetime that either has a bound or is referenced by a
|
||||
// bound is early.
|
||||
for lifetime_def in generics.lifetimes.iter() {
|
||||
if !lifetime_def.bounds.is_empty() {
|
||||
shuffle(&mut early_bound, &mut late_bound,
|
||||
lifetime_def.lifetime.name);
|
||||
for bound in lifetime_def.bounds.iter() {
|
||||
shuffle(&mut early_bound, &mut late_bound,
|
||||
bound.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return early_bound;
|
||||
|
||||
struct FreeLifetimeCollector<'a> {
|
||||
early_bound: &'a mut Vec<ast::Name>,
|
||||
late_bound: &'a mut Vec<ast::Name>,
|
||||
}
|
||||
|
||||
impl<'a> Visitor<()> for FreeLifetimeCollector<'a> {
|
||||
fn visit_lifetime_ref(&mut self,
|
||||
lifetime_ref: &ast::Lifetime,
|
||||
_: ()) {
|
||||
self.names.push(lifetime_ref.name);
|
||||
shuffle(self.early_bound, self.late_bound,
|
||||
lifetime_ref.name);
|
||||
}
|
||||
}
|
||||
|
||||
fn shuffle(early_bound: &mut Vec<ast::Name>,
|
||||
late_bound: &mut Vec<ast::Name>,
|
||||
name: ast::Name) {
|
||||
match late_bound.iter().position(|n| *n == name) {
|
||||
Some(index) => {
|
||||
late_bound.swap_remove(index);
|
||||
early_bound.push(name);
|
||||
}
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ use syntax::attr;
|
||||
use syntax::codemap::*;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::{get_ident,keywords};
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::print::pprust::{path_to_string,ty_to_string};
|
||||
@ -653,7 +654,7 @@ impl <'l> DxrVisitor<'l> {
|
||||
item: &ast::Item,
|
||||
e: DxrVisitorEnv,
|
||||
generics: &ast::Generics,
|
||||
trait_refs: &Vec<ast::TraitRef>,
|
||||
trait_refs: &OwnedSlice<ast::TyParamBound>,
|
||||
methods: &Vec<ast::TraitItem>) {
|
||||
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
||||
|
||||
@ -665,7 +666,16 @@ impl <'l> DxrVisitor<'l> {
|
||||
e.cur_scope);
|
||||
|
||||
// super-traits
|
||||
for trait_ref in trait_refs.iter() {
|
||||
for super_bound in trait_refs.iter() {
|
||||
let trait_ref = match *super_bound {
|
||||
ast::TraitTyParamBound(ref trait_ref) => {
|
||||
trait_ref
|
||||
}
|
||||
ast::UnboxedFnTyParamBound(..) | ast::RegionTyParamBound(..) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match self.lookup_type_ref(trait_ref.ref_id) {
|
||||
Some(id) => {
|
||||
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
|
||||
@ -1499,7 +1509,7 @@ pub fn process_crate(sess: &Session,
|
||||
collected_paths: vec!(),
|
||||
collecting: false,
|
||||
fmt: FmtStrs::new(box Recorder {
|
||||
out: output_file as Box<Writer>,
|
||||
out: output_file as Box<Writer+'static>,
|
||||
dump_spans: false,
|
||||
},
|
||||
SpanUtils {
|
||||
|
@ -19,7 +19,7 @@ use syntax::codemap::*;
|
||||
|
||||
pub struct Recorder {
|
||||
// output file
|
||||
pub out: Box<Writer>,
|
||||
pub out: Box<Writer+'static>,
|
||||
pub dump_spans: bool,
|
||||
}
|
||||
|
||||
|
@ -611,7 +611,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||
|
||||
let t1 = match ty::get(t).sty {
|
||||
ty::ty_param(p) => {
|
||||
check(self, t, self.substs.types.opt_get(p.space, p.idx))
|
||||
check(self, p, t, self.substs.types.opt_get(p.space, p.idx))
|
||||
}
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, t)
|
||||
@ -627,6 +627,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||
return t1;
|
||||
|
||||
fn check(this: &SubstFolder,
|
||||
p: ty::ParamTy,
|
||||
source_ty: ty::t,
|
||||
opt_ty: Option<&ty::t>)
|
||||
-> ty::t {
|
||||
@ -636,8 +637,9 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||
let span = this.span.unwrap_or(DUMMY_SP);
|
||||
this.tcx().sess.span_bug(
|
||||
span,
|
||||
format!("Type parameter {} out of range \
|
||||
format!("Type parameter `{}` ({}) out of range \
|
||||
when substituting (root type={})",
|
||||
p.repr(this.tcx()),
|
||||
source_ty.repr(this.tcx()),
|
||||
this.root_ty.repr(this.tcx())).as_slice());
|
||||
}
|
||||
|
@ -340,6 +340,15 @@ struct ArmData<'a, 'b> {
|
||||
* As we proceed `bound_ptrs` are filled with pointers to values to be bound,
|
||||
* these pointers are stored in llmatch variables just before executing `data` arm.
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
struct Match<'a, 'b:'a> {
|
||||
pats: Vec<Gc<ast::Pat>>,
|
||||
data: &'a ArmData<'a, 'b>,
|
||||
bound_ptrs: Vec<(Ident, ValueRef)>
|
||||
}
|
||||
|
||||
///Dox
|
||||
#[cfg(stage0)]
|
||||
struct Match<'a, 'b> {
|
||||
pats: Vec<Gc<ast::Pat>>,
|
||||
data: &'a ArmData<'a, 'b>,
|
||||
|
@ -25,7 +25,6 @@ use middle::ty;
|
||||
use syntax::ast;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
|
||||
pub struct CleanupScope<'a> {
|
||||
// The id of this cleanup scope. If the id is None,
|
||||
// this is a *temporary scope* that is pushed during trans to
|
||||
@ -35,7 +34,7 @@ pub struct CleanupScope<'a> {
|
||||
kind: CleanupScopeKind<'a>,
|
||||
|
||||
// Cleanups to run upon scope exit.
|
||||
cleanups: Vec<Box<Cleanup>>,
|
||||
cleanups: Vec<CleanupObj>,
|
||||
|
||||
cached_early_exits: Vec<CachedEarlyExit>,
|
||||
cached_landing_pad: Option<BasicBlockRef>,
|
||||
@ -73,6 +72,8 @@ pub trait Cleanup {
|
||||
fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>;
|
||||
}
|
||||
|
||||
pub type CleanupObj = Box<Cleanup+'static>;
|
||||
|
||||
pub enum ScopeId {
|
||||
AstScope(ast::NodeId),
|
||||
CustomScope(CustomScopeIndex)
|
||||
@ -238,7 +239,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
cleanup_scope,
|
||||
self.ccx.tn.val_to_string(val));
|
||||
|
||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
||||
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||
}
|
||||
|
||||
fn schedule_drop_mem(&self,
|
||||
@ -264,7 +265,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
self.ccx.tn.val_to_string(val),
|
||||
ty.repr(self.ccx.tcx()));
|
||||
|
||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
||||
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||
}
|
||||
|
||||
fn schedule_drop_and_zero_mem(&self,
|
||||
@ -291,7 +292,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
ty.repr(self.ccx.tcx()),
|
||||
true);
|
||||
|
||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
||||
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||
}
|
||||
|
||||
fn schedule_drop_immediate(&self,
|
||||
@ -316,7 +317,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
self.ccx.tn.val_to_string(val),
|
||||
ty.repr(self.ccx.tcx()));
|
||||
|
||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
||||
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||
}
|
||||
|
||||
fn schedule_free_value(&self,
|
||||
@ -336,12 +337,12 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
self.ccx.tn.val_to_string(val),
|
||||
heap);
|
||||
|
||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
||||
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||
}
|
||||
|
||||
fn schedule_clean(&self,
|
||||
cleanup_scope: ScopeId,
|
||||
cleanup: Box<Cleanup>) {
|
||||
cleanup: CleanupObj) {
|
||||
match cleanup_scope {
|
||||
AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
|
||||
CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup),
|
||||
@ -350,7 +351,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
|
||||
fn schedule_clean_in_ast_scope(&self,
|
||||
cleanup_scope: ast::NodeId,
|
||||
cleanup: Box<Cleanup>) {
|
||||
cleanup: CleanupObj) {
|
||||
/*!
|
||||
* Schedules a cleanup to occur upon exit from `cleanup_scope`.
|
||||
* If `cleanup_scope` is not provided, then the cleanup is scheduled
|
||||
@ -378,7 +379,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||
|
||||
fn schedule_clean_in_custom_scope(&self,
|
||||
custom_scope: CustomScopeIndex,
|
||||
cleanup: Box<Cleanup>) {
|
||||
cleanup: CleanupObj) {
|
||||
/*!
|
||||
* Schedules a cleanup to occur in the top-most scope,
|
||||
* which must be a temporary scope.
|
||||
@ -1021,13 +1022,13 @@ pub trait CleanupMethods<'a> {
|
||||
content_ty: ty::t);
|
||||
fn schedule_clean(&self,
|
||||
cleanup_scope: ScopeId,
|
||||
cleanup: Box<Cleanup>);
|
||||
cleanup: CleanupObj);
|
||||
fn schedule_clean_in_ast_scope(&self,
|
||||
cleanup_scope: ast::NodeId,
|
||||
cleanup: Box<Cleanup>);
|
||||
cleanup: CleanupObj);
|
||||
fn schedule_clean_in_custom_scope(&self,
|
||||
custom_scope: CustomScopeIndex,
|
||||
cleanup: Box<Cleanup>);
|
||||
cleanup: CleanupObj);
|
||||
fn needs_invoke(&self) -> bool;
|
||||
fn get_landing_pad(&'a self) -> BasicBlockRef;
|
||||
}
|
||||
|
@ -498,9 +498,8 @@ impl TypeMap {
|
||||
|
||||
unique_type_id.push_char(':');
|
||||
|
||||
for bound in bounds.iter() {
|
||||
for bound in bounds.builtin_bounds.iter() {
|
||||
match bound {
|
||||
ty::BoundStatic => unique_type_id.push_str("'static"),
|
||||
ty::BoundSend => unique_type_id.push_str("Send"),
|
||||
ty::BoundSized => unique_type_id.push_str("Sized"),
|
||||
ty::BoundCopy => unique_type_id.push_str("Copy"),
|
||||
|
@ -35,7 +35,7 @@ use middle::trans::tvec;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::trans::type_of::{type_of, sizing_type_of, align_of};
|
||||
use middle::ty;
|
||||
use util::ppaux::ty_to_short_str;
|
||||
use util::ppaux::{ty_to_short_str, Repr};
|
||||
use util::ppaux;
|
||||
|
||||
use arena::TypedArena;
|
||||
@ -131,6 +131,7 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
||||
pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
-> &'a Block<'a> {
|
||||
// NB: v is an *alias* of type t here, not a direct value.
|
||||
debug!("drop_ty(t={})", t.repr(bcx.tcx()));
|
||||
let _icx = push_ctxt("drop_ty");
|
||||
if ty::type_needs_drop(bcx.tcx(), t) {
|
||||
let ccx = bcx.ccx();
|
||||
@ -213,6 +214,7 @@ fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
let _icx = push_ctxt("make_visit_glue");
|
||||
let mut bcx = bcx;
|
||||
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
||||
ty::ReStatic,
|
||||
ty::ReStatic) {
|
||||
Ok(pair) => pair,
|
||||
Err(s) => {
|
||||
|
@ -273,7 +273,7 @@ pub enum UnsizeKind {
|
||||
// An unsize coercion applied to the tail field of a struct.
|
||||
// The uint is the index of the type parameter which is unsized.
|
||||
UnsizeStruct(Box<UnsizeKind>, uint),
|
||||
UnsizeVtable(ty::BuiltinBounds,
|
||||
UnsizeVtable(ty::ExistentialBounds,
|
||||
ast::DefId, /* Trait ID */
|
||||
subst::Substs /* Trait substitutions */)
|
||||
}
|
||||
@ -464,7 +464,6 @@ pub struct ctxt {
|
||||
pub lang_items: middle::lang_items::LanguageItems,
|
||||
/// A mapping of fake provided method def_ids to the default implementation
|
||||
pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
|
||||
pub supertraits: RefCell<DefIdMap<Rc<Vec<Rc<TraitRef>>>>>,
|
||||
pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
|
||||
pub struct_fields: RefCell<DefIdMap<Rc<Vec<field_ty>>>>,
|
||||
|
||||
@ -620,7 +619,7 @@ pub struct ClosureTy {
|
||||
pub fn_style: ast::FnStyle,
|
||||
pub onceness: ast::Onceness,
|
||||
pub store: TraitStore,
|
||||
pub bounds: BuiltinBounds,
|
||||
pub bounds: ExistentialBounds,
|
||||
pub sig: FnSig,
|
||||
pub abi: abi::Abi,
|
||||
}
|
||||
@ -932,7 +931,7 @@ pub enum sty {
|
||||
pub struct TyTrait {
|
||||
pub def_id: DefId,
|
||||
pub substs: Substs,
|
||||
pub bounds: BuiltinBounds
|
||||
pub bounds: ExistentialBounds
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, Eq, Hash, Show)]
|
||||
@ -995,18 +994,30 @@ pub enum type_err {
|
||||
terr_variadic_mismatch(expected_found<bool>)
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, Eq, Hash, Show)]
|
||||
/// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
|
||||
/// as well as the existential type parameter in an object type.
|
||||
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
|
||||
pub struct ParamBounds {
|
||||
pub opt_region_bound: Option<ty::Region>,
|
||||
pub builtin_bounds: BuiltinBounds,
|
||||
pub trait_bounds: Vec<Rc<TraitRef>>
|
||||
}
|
||||
|
||||
/// Bounds suitable for an existentially quantified type parameter
|
||||
/// such as those that appear in object types or closure types. The
|
||||
/// major difference between this case and `ParamBounds` is that
|
||||
/// general purpose trait bounds are omitted.
|
||||
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
|
||||
pub struct ExistentialBounds {
|
||||
pub region_bound: ty::Region,
|
||||
pub builtin_bounds: BuiltinBounds
|
||||
}
|
||||
|
||||
pub type BuiltinBounds = EnumSet<BuiltinBound>;
|
||||
|
||||
#[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)]
|
||||
#[repr(uint)]
|
||||
pub enum BuiltinBound {
|
||||
BoundStatic,
|
||||
BoundSend,
|
||||
BoundSized,
|
||||
BoundCopy,
|
||||
@ -1019,13 +1030,21 @@ pub fn empty_builtin_bounds() -> BuiltinBounds {
|
||||
|
||||
pub fn all_builtin_bounds() -> BuiltinBounds {
|
||||
let mut set = EnumSet::empty();
|
||||
set.add(BoundStatic);
|
||||
set.add(BoundSend);
|
||||
set.add(BoundSized);
|
||||
set.add(BoundSync);
|
||||
set
|
||||
}
|
||||
|
||||
pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds {
|
||||
/*!
|
||||
* An existential bound that does not implement any traits.
|
||||
*/
|
||||
|
||||
ty::ExistentialBounds { region_bound: r,
|
||||
builtin_bounds: empty_builtin_bounds() }
|
||||
}
|
||||
|
||||
impl CLike for BuiltinBound {
|
||||
fn to_uint(&self) -> uint {
|
||||
*self as uint
|
||||
@ -1141,8 +1160,8 @@ pub struct TypeParameterDef {
|
||||
pub def_id: ast::DefId,
|
||||
pub space: subst::ParamSpace,
|
||||
pub index: uint,
|
||||
pub bounds: Rc<ParamBounds>,
|
||||
pub default: Option<ty::t>
|
||||
pub bounds: ParamBounds,
|
||||
pub default: Option<ty::t>,
|
||||
}
|
||||
|
||||
#[deriving(Encodable, Decodable, Clone, Show)]
|
||||
@ -1151,6 +1170,7 @@ pub struct RegionParameterDef {
|
||||
pub def_id: ast::DefId,
|
||||
pub space: subst::ParamSpace,
|
||||
pub index: uint,
|
||||
pub bounds: Vec<ty::Region>,
|
||||
}
|
||||
|
||||
/// Information about the type/lifetime parameters associated with an
|
||||
@ -1198,6 +1218,12 @@ pub struct ParameterEnvironment {
|
||||
|
||||
/// Bounds on the various type parameters
|
||||
pub bounds: VecPerParamSpace<ParamBounds>,
|
||||
|
||||
/// Each type parameter has an implicit region bound that
|
||||
/// indicates it must outlive at least the function body (the user
|
||||
/// may specify stronger requirements). This field indicates the
|
||||
/// region of the callee.
|
||||
pub implicit_region_bound: ty::Region,
|
||||
}
|
||||
|
||||
impl ParameterEnvironment {
|
||||
@ -1292,7 +1318,7 @@ pub struct Polytype {
|
||||
/// As `Polytype` but for a trait ref.
|
||||
pub struct TraitDef {
|
||||
pub generics: Generics,
|
||||
pub bounds: BuiltinBounds,
|
||||
pub bounds: ParamBounds,
|
||||
pub trait_ref: Rc<ty::TraitRef>,
|
||||
}
|
||||
|
||||
@ -1382,7 +1408,6 @@ pub fn mk_ctxt(s: Session,
|
||||
normalized_cache: RefCell::new(HashMap::new()),
|
||||
lang_items: lang_items,
|
||||
provided_method_sources: RefCell::new(DefIdMap::new()),
|
||||
supertraits: RefCell::new(DefIdMap::new()),
|
||||
superstructs: RefCell::new(DefIdMap::new()),
|
||||
struct_fields: RefCell::new(DefIdMap::new()),
|
||||
destructor_for_type: RefCell::new(DefIdMap::new()),
|
||||
@ -1459,6 +1484,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
}
|
||||
return f;
|
||||
}
|
||||
fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
|
||||
rflags(bounds.region_bound)
|
||||
}
|
||||
match &st {
|
||||
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
|
||||
&ty_str => {}
|
||||
@ -1483,8 +1511,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
|
||||
flags |= sflags(substs);
|
||||
}
|
||||
&ty_trait(box ty::TyTrait { ref substs, .. }) => {
|
||||
&ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => {
|
||||
flags |= sflags(substs);
|
||||
flags |= flags_for_bounds(bounds);
|
||||
}
|
||||
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
|
||||
flags |= get(tt).flags
|
||||
@ -1514,6 +1543,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
flags |= get(f.sig.output).flags;
|
||||
// T -> _|_ is *not* _|_ !
|
||||
flags &= !(has_ty_bot as uint);
|
||||
flags |= flags_for_bounds(&f.bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1711,8 +1741,8 @@ pub fn mk_ctor_fn(cx: &ctxt,
|
||||
pub fn mk_trait(cx: &ctxt,
|
||||
did: ast::DefId,
|
||||
substs: Substs,
|
||||
bounds: BuiltinBounds)
|
||||
-> t {
|
||||
bounds: ExistentialBounds)
|
||||
-> t {
|
||||
// take a copy of substs so that we own the vectors inside
|
||||
let inner = box TyTrait {
|
||||
def_id: did,
|
||||
@ -1800,6 +1830,27 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|)
|
||||
|t| { fldt(t); t }).fold_ty(ty)
|
||||
}
|
||||
|
||||
impl ParamTy {
|
||||
pub fn new(space: subst::ParamSpace,
|
||||
index: uint,
|
||||
def_id: ast::DefId)
|
||||
-> ParamTy {
|
||||
ParamTy { space: space, idx: index, def_id: def_id }
|
||||
}
|
||||
|
||||
pub fn for_self(trait_def_id: ast::DefId) -> ParamTy {
|
||||
ParamTy::new(subst::SelfSpace, 0, trait_def_id)
|
||||
}
|
||||
|
||||
pub fn for_def(def: &TypeParameterDef) -> ParamTy {
|
||||
ParamTy::new(def.space, def.index, def.def_id)
|
||||
}
|
||||
|
||||
pub fn to_ty(self, tcx: &ty::ctxt) -> ty::t {
|
||||
ty::mk_param(tcx, self.space, self.idx, self.def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemSubsts {
|
||||
pub fn empty() -> ItemSubsts {
|
||||
ItemSubsts { substs: Substs::empty() }
|
||||
@ -2115,9 +2166,6 @@ def_type_content_sets!(
|
||||
// that it neither reaches nor owns a managed pointer.
|
||||
Nonsendable = 0b0000_0111__0000_0100__0000,
|
||||
|
||||
// Things that prevent values from being considered 'static
|
||||
Nonstatic = 0b0000_0010__0000_0000__0000,
|
||||
|
||||
// Things that prevent values from being considered sized
|
||||
Nonsized = 0b0000_0000__0000_0000__0001,
|
||||
|
||||
@ -2142,9 +2190,8 @@ def_type_content_sets!(
|
||||
)
|
||||
|
||||
impl TypeContents {
|
||||
pub fn meets_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
|
||||
pub fn meets_builtin_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
|
||||
match bb {
|
||||
BoundStatic => self.is_static(cx),
|
||||
BoundSend => self.is_sendable(cx),
|
||||
BoundSized => self.is_sized(cx),
|
||||
BoundCopy => self.is_copy(cx),
|
||||
@ -2160,10 +2207,6 @@ impl TypeContents {
|
||||
(self.bits & tc.bits) != 0
|
||||
}
|
||||
|
||||
pub fn is_static(&self, _: &ctxt) -> bool {
|
||||
!self.intersects(TC::Nonstatic)
|
||||
}
|
||||
|
||||
pub fn is_sendable(&self, _: &ctxt) -> bool {
|
||||
!self.intersects(TC::Nonsendable)
|
||||
}
|
||||
@ -2272,10 +2315,6 @@ impl fmt::Show for TypeContents {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_is_static(cx: &ctxt, t: ty::t) -> bool {
|
||||
type_contents(cx, t).is_static(cx)
|
||||
}
|
||||
|
||||
pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool {
|
||||
type_contents(cx, t).is_sendable(cx)
|
||||
}
|
||||
@ -2482,10 +2521,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
|
||||
let ty_param_defs = cx.ty_param_defs.borrow();
|
||||
let tp_def = ty_param_defs.get(&p.def_id.node);
|
||||
kind_bounds_to_contents(cx,
|
||||
tp_def.bounds.builtin_bounds,
|
||||
tp_def.bounds.trait_bounds.as_slice())
|
||||
}
|
||||
kind_bounds_to_contents(
|
||||
cx,
|
||||
tp_def.bounds.builtin_bounds,
|
||||
tp_def.bounds.trait_bounds.as_slice())
|
||||
}
|
||||
|
||||
ty_infer(_) => {
|
||||
// This occurs during coherence, but shouldn't occur at other
|
||||
@ -2577,10 +2617,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
}
|
||||
|
||||
fn object_contents(cx: &ctxt,
|
||||
bounds: BuiltinBounds)
|
||||
bounds: ExistentialBounds)
|
||||
-> TypeContents {
|
||||
// These are the type contents of the (opaque) interior
|
||||
kind_bounds_to_contents(cx, bounds, [])
|
||||
kind_bounds_to_contents(cx, bounds.builtin_bounds, [])
|
||||
}
|
||||
|
||||
fn kind_bounds_to_contents(cx: &ctxt,
|
||||
@ -2591,7 +2631,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
let mut tc = TC::All;
|
||||
each_inherited_builtin_bound(cx, bounds, traits, |bound| {
|
||||
tc = tc - match bound {
|
||||
BoundStatic => TC::Nonstatic,
|
||||
BoundSend => TC::Nonsendable,
|
||||
BoundSized => TC::Nonsized,
|
||||
BoundCopy => TC::Noncopy,
|
||||
@ -2612,7 +2651,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
|
||||
each_bound_trait_and_supertraits(cx, traits, |trait_ref| {
|
||||
let trait_def = lookup_trait_def(cx, trait_ref.def_id);
|
||||
for bound in trait_def.bounds.iter() {
|
||||
for bound in trait_def.bounds.builtin_bounds.iter() {
|
||||
f(bound);
|
||||
}
|
||||
true
|
||||
@ -3272,16 +3311,19 @@ pub fn adjust_ty(cx: &ctxt,
|
||||
AutoAddEnv(store) => {
|
||||
match ty::get(unadjusted_ty).sty {
|
||||
ty::ty_bare_fn(ref b) => {
|
||||
let bounds = ty::ExistentialBounds {
|
||||
region_bound: ReStatic,
|
||||
builtin_bounds: all_builtin_bounds(),
|
||||
};
|
||||
|
||||
ty::mk_closure(
|
||||
cx,
|
||||
ty::ClosureTy {
|
||||
fn_style: b.fn_style,
|
||||
onceness: ast::Many,
|
||||
store: store,
|
||||
bounds: ty::all_builtin_bounds(),
|
||||
sig: b.sig.clone(),
|
||||
abi: b.abi,
|
||||
})
|
||||
ty::ClosureTy {fn_style: b.fn_style,
|
||||
onceness: ast::Many,
|
||||
store: store,
|
||||
bounds: bounds,
|
||||
sig: b.sig.clone(),
|
||||
abi: b.abi})
|
||||
}
|
||||
ref b => {
|
||||
cx.sess.bug(
|
||||
@ -3920,30 +3962,6 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_supertraits(cx: &ctxt, id: ast::DefId) -> Rc<Vec<Rc<TraitRef>>> {
|
||||
// Check the cache.
|
||||
match cx.supertraits.borrow().find(&id) {
|
||||
Some(trait_refs) => { return trait_refs.clone(); }
|
||||
None => {} // Continue.
|
||||
}
|
||||
|
||||
// Not in the cache. It had better be in the metadata, which means it
|
||||
// shouldn't be local.
|
||||
assert!(!is_local(id));
|
||||
|
||||
// Get the supertraits out of the metadata and create the
|
||||
// TraitRef for each.
|
||||
let result = Rc::new(csearch::get_supertraits(cx, id));
|
||||
cx.supertraits.borrow_mut().insert(id, result.clone());
|
||||
result
|
||||
}
|
||||
|
||||
pub fn trait_ref_supertraits(cx: &ctxt, trait_ref: &ty::TraitRef) -> Vec<Rc<TraitRef>> {
|
||||
let supertrait_refs = trait_supertraits(cx, trait_ref.def_id);
|
||||
supertrait_refs.iter().map(
|
||||
|supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs)).collect()
|
||||
}
|
||||
|
||||
fn lookup_locally_or_in_crate_store<V:Clone>(
|
||||
descr: &str,
|
||||
def_id: ast::DefId,
|
||||
@ -4055,9 +4073,12 @@ pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
|
||||
def.def_id()
|
||||
}
|
||||
|
||||
pub fn try_add_builtin_trait(tcx: &ctxt,
|
||||
trait_def_id: ast::DefId,
|
||||
builtin_bounds: &mut BuiltinBounds) -> bool {
|
||||
pub fn try_add_builtin_trait(
|
||||
tcx: &ctxt,
|
||||
trait_def_id: ast::DefId,
|
||||
builtin_bounds: &mut EnumSet<BuiltinBound>)
|
||||
-> bool
|
||||
{
|
||||
//! Checks whether `trait_ref` refers to one of the builtin
|
||||
//! traits, like `Send`, and adds the corresponding
|
||||
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
|
||||
@ -4343,6 +4364,18 @@ pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc<ty::TraitDef> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a reference to a trait, returns the bounds declared on the
|
||||
/// trait, with appropriate substitutions applied.
|
||||
pub fn bounds_for_trait_ref(tcx: &ctxt,
|
||||
trait_ref: &TraitRef)
|
||||
-> ty::ParamBounds
|
||||
{
|
||||
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||
debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})",
|
||||
trait_def.repr(tcx), trait_ref.repr(tcx));
|
||||
trait_def.bounds.subst(tcx, &trait_ref.substs)
|
||||
}
|
||||
|
||||
/// Iterate over attributes of a definition.
|
||||
// (This should really be an iterator, but that would require csearch and
|
||||
// decoder to use iterators instead of higher-order functions.)
|
||||
@ -4410,14 +4443,10 @@ pub fn lookup_field_type(tcx: &ctxt,
|
||||
node_id_to_type(tcx, id.node)
|
||||
} else {
|
||||
let mut tcache = tcx.tcache.borrow_mut();
|
||||
match tcache.find(&id) {
|
||||
Some(&Polytype {ty, ..}) => ty,
|
||||
None => {
|
||||
let tpt = csearch::get_field_type(tcx, struct_id, id);
|
||||
tcache.insert(id, tpt.clone());
|
||||
tpt.ty
|
||||
}
|
||||
}
|
||||
let pty = tcache.find_or_insert_with(id, |_| {
|
||||
csearch::get_field_type(tcx, struct_id, id)
|
||||
});
|
||||
pty.ty
|
||||
};
|
||||
t.subst(tcx, substs)
|
||||
}
|
||||
@ -4745,9 +4774,10 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
|
||||
}
|
||||
|
||||
// Add supertraits to supertrait_set
|
||||
let supertrait_refs = trait_ref_supertraits(tcx,
|
||||
&**trait_refs.get(i));
|
||||
for supertrait_ref in supertrait_refs.iter() {
|
||||
let trait_ref = trait_refs.get(i).clone();
|
||||
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||
for supertrait_ref in trait_def.bounds.trait_bounds.iter() {
|
||||
let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs);
|
||||
debug!("each_bound_trait_and_supertraits(supertrait_ref={})",
|
||||
supertrait_ref.repr(tcx));
|
||||
|
||||
@ -4765,6 +4795,61 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn required_region_bounds(tcx: &ctxt,
|
||||
region_bounds: &[ty::Region],
|
||||
builtin_bounds: BuiltinBounds,
|
||||
trait_bounds: &[Rc<TraitRef>])
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
/*!
|
||||
* Given a type which must meet the builtin bounds and trait
|
||||
* bounds, returns a set of lifetimes which the type must outlive.
|
||||
*
|
||||
* Requires that trait definitions have been processed.
|
||||
*/
|
||||
|
||||
let mut all_bounds = Vec::new();
|
||||
|
||||
debug!("required_region_bounds(builtin_bounds={}, trait_bounds={})",
|
||||
builtin_bounds.repr(tcx),
|
||||
trait_bounds.repr(tcx));
|
||||
|
||||
all_bounds.push_all(region_bounds);
|
||||
|
||||
push_region_bounds([],
|
||||
builtin_bounds,
|
||||
&mut all_bounds);
|
||||
|
||||
debug!("from builtin bounds: all_bounds={}", all_bounds.repr(tcx));
|
||||
|
||||
each_bound_trait_and_supertraits(
|
||||
tcx,
|
||||
trait_bounds,
|
||||
|trait_ref| {
|
||||
let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
|
||||
push_region_bounds(bounds.opt_region_bound.as_slice(),
|
||||
bounds.builtin_bounds,
|
||||
&mut all_bounds);
|
||||
debug!("from {}: bounds={} all_bounds={}",
|
||||
trait_ref.repr(tcx),
|
||||
bounds.repr(tcx),
|
||||
all_bounds.repr(tcx));
|
||||
true
|
||||
});
|
||||
|
||||
return all_bounds;
|
||||
|
||||
fn push_region_bounds(region_bounds: &[ty::Region],
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
all_bounds: &mut Vec<ty::Region>) {
|
||||
all_bounds.push_all(region_bounds.as_slice());
|
||||
|
||||
if builtin_bounds.contains_elem(ty::BoundSend) {
|
||||
all_bounds.push(ty::ReStatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tydesc_ty(tcx: &ctxt) -> Result<t, String> {
|
||||
tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| {
|
||||
tcx.intrinsic_defs.borrow().find_copy(&tydesc_lang_item)
|
||||
@ -4780,7 +4865,10 @@ pub fn get_opaque_ty(tcx: &ctxt) -> Result<t, String> {
|
||||
}
|
||||
|
||||
pub fn visitor_object_ty(tcx: &ctxt,
|
||||
region: ty::Region) -> Result<(Rc<TraitRef>, t), String> {
|
||||
ptr_region: ty::Region,
|
||||
trait_region: ty::Region)
|
||||
-> Result<(Rc<TraitRef>, t), String>
|
||||
{
|
||||
let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) {
|
||||
Ok(id) => id,
|
||||
Err(s) => { return Err(s); }
|
||||
@ -4788,11 +4876,12 @@ pub fn visitor_object_ty(tcx: &ctxt,
|
||||
let substs = Substs::empty();
|
||||
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
|
||||
Ok((trait_ref.clone(),
|
||||
mk_rptr(tcx, region, mt {mutbl: ast::MutMutable,
|
||||
ty: mk_trait(tcx,
|
||||
trait_ref.def_id,
|
||||
trait_ref.substs.clone(),
|
||||
empty_builtin_bounds()) })))
|
||||
mk_rptr(tcx, ptr_region,
|
||||
mt {mutbl: ast::MutMutable,
|
||||
ty: mk_trait(tcx,
|
||||
trait_ref.def_id,
|
||||
trait_ref.substs.clone(),
|
||||
ty::region_existential_bound(trait_region))})))
|
||||
}
|
||||
|
||||
pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
|
||||
@ -5184,6 +5273,18 @@ pub fn construct_parameter_environment(
|
||||
generics.types.get_slice(space));
|
||||
}
|
||||
|
||||
//
|
||||
// Compute region bounds. For now, these relations are stored in a
|
||||
// global table on the tcx, so just enter them there. I'm not
|
||||
// crazy about this scheme, but it's convenient, at least.
|
||||
//
|
||||
|
||||
for &space in subst::ParamSpace::all().iter() {
|
||||
record_region_bounds_from_defs(tcx, space, &free_substs,
|
||||
generics.regions.get_slice(space));
|
||||
}
|
||||
|
||||
|
||||
debug!("construct_parameter_environment: free_id={} \
|
||||
free_subst={} \
|
||||
bounds={}",
|
||||
@ -5193,7 +5294,8 @@ pub fn construct_parameter_environment(
|
||||
|
||||
return ty::ParameterEnvironment {
|
||||
free_substs: free_substs,
|
||||
bounds: bounds
|
||||
bounds: bounds,
|
||||
implicit_region_bound: ty::ReScope(free_id),
|
||||
};
|
||||
|
||||
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
|
||||
@ -5222,10 +5324,41 @@ pub fn construct_parameter_environment(
|
||||
free_substs: &subst::Substs,
|
||||
defs: &[TypeParameterDef]) {
|
||||
for def in defs.iter() {
|
||||
let b = (*def.bounds).subst(tcx, free_substs);
|
||||
let b = def.bounds.subst(tcx, free_substs);
|
||||
bounds.push(space, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_region_bounds_from_defs(tcx: &ty::ctxt,
|
||||
space: subst::ParamSpace,
|
||||
free_substs: &subst::Substs,
|
||||
defs: &[RegionParameterDef]) {
|
||||
for (subst_region, def) in
|
||||
free_substs.regions().get_slice(space).iter().zip(
|
||||
defs.iter())
|
||||
{
|
||||
// For each region parameter 'subst...
|
||||
let bounds = def.bounds.subst(tcx, free_substs);
|
||||
for bound_region in bounds.iter() {
|
||||
// Which is declared with a bound like 'subst:'bound...
|
||||
match (subst_region, bound_region) {
|
||||
(&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => {
|
||||
// Record that 'subst outlives 'bound. Or, put
|
||||
// another way, 'bound <= 'subst.
|
||||
tcx.region_maps.relate_free_regions(bound_fr, subst_fr);
|
||||
},
|
||||
_ => {
|
||||
// All named regions are instantiated with free regions.
|
||||
tcx.sess.bug(
|
||||
format!("push_region_bounds_from_defs: \
|
||||
non free region: {} / {}",
|
||||
subst_region.repr(tcx),
|
||||
bound_region.repr(tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
@ -5346,4 +5479,3 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,11 @@ pub trait TypeFolder {
|
||||
super_fold_trait_store(self, s)
|
||||
}
|
||||
|
||||
fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds)
|
||||
-> ty::ExistentialBounds {
|
||||
super_fold_existential_bounds(self, s)
|
||||
}
|
||||
|
||||
fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef {
|
||||
super_fold_autoref(self, ar)
|
||||
}
|
||||
@ -236,9 +241,16 @@ impl TypeFoldable for ty::BuiltinBounds {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFoldable for ty::ExistentialBounds {
|
||||
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ExistentialBounds {
|
||||
folder.fold_existential_bounds(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFoldable for ty::ParamBounds {
|
||||
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ParamBounds {
|
||||
ty::ParamBounds {
|
||||
opt_region_bound: self.opt_region_bound.fold_with(folder),
|
||||
builtin_bounds: self.builtin_bounds.fold_with(folder),
|
||||
trait_bounds: self.trait_bounds.fold_with(folder),
|
||||
}
|
||||
@ -259,8 +271,14 @@ impl TypeFoldable for ty::TypeParameterDef {
|
||||
}
|
||||
|
||||
impl TypeFoldable for ty::RegionParameterDef {
|
||||
fn fold_with<F:TypeFolder>(&self, _folder: &mut F) -> ty::RegionParameterDef {
|
||||
*self
|
||||
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::RegionParameterDef {
|
||||
ty::RegionParameterDef {
|
||||
name: self.name,
|
||||
def_id: self.def_id,
|
||||
space: self.space,
|
||||
index: self.index,
|
||||
bounds: self.bounds.fold_with(folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +358,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
|
||||
sig: fty.sig.fold_with(this),
|
||||
fn_style: fty.fn_style,
|
||||
onceness: fty.onceness,
|
||||
bounds: fty.bounds,
|
||||
bounds: fty.bounds.fold_with(this),
|
||||
abi: fty.abi,
|
||||
}
|
||||
}
|
||||
@ -389,7 +407,7 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
def_id: def_id,
|
||||
substs: substs.fold_with(this),
|
||||
bounds: bounds
|
||||
bounds: this.fold_existential_bounds(bounds),
|
||||
})
|
||||
}
|
||||
ty::ty_tup(ref ts) => {
|
||||
@ -430,6 +448,15 @@ pub fn super_fold_trait_store<T:TypeFolder>(this: &mut T,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_existential_bounds<T:TypeFolder>(this: &mut T,
|
||||
bounds: ty::ExistentialBounds)
|
||||
-> ty::ExistentialBounds {
|
||||
ty::ExistentialBounds {
|
||||
region_bound: bounds.region_bound.fold_with(this),
|
||||
builtin_bounds: bounds.builtin_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_autoref<T:TypeFolder>(this: &mut T,
|
||||
autoref: &ty::AutoRef)
|
||||
-> ty::AutoRef
|
||||
|
@ -57,19 +57,19 @@ use middle::resolve_lifetime as rl;
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{VecPerParamSpace};
|
||||
use middle::ty;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::rscope::RegionScope;
|
||||
use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
|
||||
use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
|
||||
use middle::typeck::lookup_def_tcx;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope};
|
||||
use middle::typeck::rscope;
|
||||
use middle::typeck::TypeAndSubsts;
|
||||
use middle::typeck;
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use syntax::abi;
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::print::pprust::{lifetime_to_string, path_to_string};
|
||||
|
||||
pub trait AstConv {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt;
|
||||
@ -111,8 +111,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
|
||||
};
|
||||
|
||||
debug!("ast_region_to_region(lifetime={} id={}) yields {}",
|
||||
lifetime_to_string(lifetime),
|
||||
lifetime.id, r.repr(tcx));
|
||||
lifetime.repr(tcx),
|
||||
lifetime.id,
|
||||
r.repr(tcx));
|
||||
|
||||
r
|
||||
}
|
||||
@ -145,7 +146,7 @@ pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
|
||||
};
|
||||
|
||||
debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}",
|
||||
opt_lifetime.as_ref().map(|e| lifetime_to_string(e)),
|
||||
opt_lifetime.repr(this.tcx()),
|
||||
r.repr(this.tcx()));
|
||||
|
||||
r
|
||||
@ -284,11 +285,11 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
|
||||
}
|
||||
|
||||
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
did: ast::DefId,
|
||||
path: &ast::Path)
|
||||
-> TypeAndSubsts
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
did: ast::DefId,
|
||||
path: &ast::Path)
|
||||
-> TypeAndSubsts
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let ty::Polytype {
|
||||
@ -370,7 +371,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
|
||||
None => {
|
||||
tcx.sess.span_bug(ast_ty.span,
|
||||
format!("unbound path {}",
|
||||
path_to_string(path)).as_slice())
|
||||
path.repr(tcx)).as_slice())
|
||||
}
|
||||
Some(&d) => d
|
||||
};
|
||||
@ -430,7 +431,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
|
||||
.sess
|
||||
.span_bug(ast_ty.span,
|
||||
format!("unbound path {}",
|
||||
path_to_string(path)).as_slice())
|
||||
path.repr(this.tcx())).as_slice())
|
||||
}
|
||||
Some(&d) => d
|
||||
};
|
||||
@ -520,6 +521,16 @@ enum PointerTy {
|
||||
Uniq
|
||||
}
|
||||
|
||||
impl PointerTy {
|
||||
fn default_region(&self) -> ty::Region {
|
||||
match *self {
|
||||
Box => ty::ReStatic,
|
||||
Uniq => ty::ReStatic,
|
||||
RPtr(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_ref_for_unboxed_function<AC:AstConv,
|
||||
RS:RegionScope>(
|
||||
this: &AC,
|
||||
@ -589,10 +600,11 @@ fn mk_pointer<AC:AstConv,
|
||||
rscope,
|
||||
&**unboxed_function,
|
||||
None);
|
||||
let r = ptr_ty.default_region();
|
||||
let tr = ty::mk_trait(this.tcx(),
|
||||
def_id,
|
||||
substs,
|
||||
ty::empty_builtin_bounds());
|
||||
ty::region_existential_bound(r));
|
||||
match ptr_ty {
|
||||
Uniq => {
|
||||
return ty::mk_uniq(this.tcx(), tr);
|
||||
@ -612,7 +624,7 @@ fn mk_pointer<AC:AstConv,
|
||||
|
||||
}
|
||||
}
|
||||
ast::TyPath(ref path, ref bounds, id) => {
|
||||
ast::TyPath(ref path, ref opt_bounds, id) => {
|
||||
// Note that the "bounds must be empty if path is not a trait"
|
||||
// restriction is enforced in the below case for ty_path, which
|
||||
// will run after this as long as the path isn't a trait.
|
||||
@ -636,14 +648,22 @@ fn mk_pointer<AC:AstConv,
|
||||
Some(&def::DefTrait(trait_def_id)) => {
|
||||
let result = ast_path_to_trait_ref(
|
||||
this, rscope, trait_def_id, None, path);
|
||||
let static_region = match ptr_ty {
|
||||
RPtr(r) if r == ty::ReStatic => true,
|
||||
_ => false
|
||||
let bounds = match *opt_bounds {
|
||||
None => {
|
||||
conv_existential_bounds(this,
|
||||
rscope,
|
||||
path.span,
|
||||
[result.clone()].as_slice(),
|
||||
[].as_slice())
|
||||
}
|
||||
Some(ref bounds) => {
|
||||
conv_existential_bounds(this,
|
||||
rscope,
|
||||
path.span,
|
||||
[result.clone()].as_slice(),
|
||||
bounds.as_slice())
|
||||
}
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
static_region);
|
||||
let tr = ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
@ -737,27 +757,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
|
||||
bf.abi, &*bf.decl))
|
||||
}
|
||||
ast::TyClosure(ref f, ref region) => {
|
||||
|
||||
// resolve the function bound region in the original region
|
||||
// scope `rscope`, not the scope of the function parameters
|
||||
let bound_region = opt_ast_region_to_region(this, rscope,
|
||||
ast_ty.span, region);
|
||||
|
||||
ast::TyClosure(ref f) => {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
bound_region == ty::ReStatic);
|
||||
|
||||
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
|
||||
let bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
ast_ty.span,
|
||||
[].as_slice(),
|
||||
f.bounds.as_slice());
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
f.fn_style,
|
||||
f.onceness,
|
||||
bounds,
|
||||
store,
|
||||
ty::RegionTraitStore(
|
||||
bounds.region_bound,
|
||||
ast::MutMutable),
|
||||
&*f.decl,
|
||||
abi::Rust,
|
||||
None);
|
||||
@ -766,10 +781,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast::TyProc(ref f) => {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
false);
|
||||
let bounds = conv_existential_bounds(this, rscope,
|
||||
ast_ty.span,
|
||||
[].as_slice(),
|
||||
f.bounds.as_slice());
|
||||
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
@ -780,6 +795,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
&*f.decl,
|
||||
abi::Rust,
|
||||
None);
|
||||
|
||||
ty::mk_closure(tcx, fn_decl)
|
||||
}
|
||||
ast::TyUnboxedFn(..) => {
|
||||
@ -793,7 +809,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
tcx.sess
|
||||
.span_bug(ast_ty.span,
|
||||
format!("unbound path {}",
|
||||
path_to_string(path)).as_slice())
|
||||
path.repr(tcx)).as_slice())
|
||||
}
|
||||
Some(&d) => d
|
||||
};
|
||||
@ -808,16 +824,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
}
|
||||
match a_def {
|
||||
def::DefTrait(trait_def_id) => {
|
||||
let result = ast_path_to_trait_ref(
|
||||
this, rscope, trait_def_id, None, path);
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
false);
|
||||
ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds)
|
||||
let result = ast_path_to_trait_ref(
|
||||
this, rscope, trait_def_id, None, path);
|
||||
let empty_bounds: &[ast::TyParamBound] = &[];
|
||||
let ast_bounds = match *bounds {
|
||||
Some(ref b) => b.as_slice(),
|
||||
None => empty_bounds
|
||||
};
|
||||
let bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
ast_ty.span,
|
||||
&[result.clone()],
|
||||
ast_bounds);
|
||||
ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds)
|
||||
}
|
||||
def::DefTy(did) | def::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
@ -1022,9 +1044,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv>(
|
||||
_ => {
|
||||
match implied_output_region {
|
||||
Some(implied_output_region) => {
|
||||
let rb = ImpliedSingleRscope {
|
||||
region: implied_output_region,
|
||||
};
|
||||
let rb = SpecificRscope::new(implied_output_region);
|
||||
ast_ty_to_ty(this, &rb, &*decl.output)
|
||||
}
|
||||
None => {
|
||||
@ -1130,7 +1150,7 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
id: ast::NodeId,
|
||||
fn_style: ast::FnStyle,
|
||||
onceness: ast::Onceness,
|
||||
bounds: ty::BuiltinBounds,
|
||||
bounds: ty::ExistentialBounds,
|
||||
store: ty::TraitStore,
|
||||
decl: &ast::FnDecl,
|
||||
abi: abi::Abi,
|
||||
@ -1176,67 +1196,250 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||
span: Span,
|
||||
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||
static_region: bool)
|
||||
-> ty::BuiltinBounds {
|
||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||
//! struct. Reports an error if any of the bounds that appear
|
||||
//! in the AST refer to general traits and not the built-in traits
|
||||
//! like `Send`. Used to translate the bounds that
|
||||
//! appear in closure and trait types, where only builtin bounds are
|
||||
//! legal.
|
||||
//! If no bounds were specified, we choose a "default" bound based on
|
||||
//! the allocation type of the fn/trait, as per issue #7264. The user can
|
||||
//! override this with an empty bounds list, e.g. "Box<fn:()>" or
|
||||
//! "Box<Trait:>".
|
||||
pub fn conv_existential_bounds<AC:AstConv, RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
main_trait_refs: &[Rc<ty::TraitRef>],
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds
|
||||
{
|
||||
/*!
|
||||
* Given an existential type like `Foo+'a+Bar`, this routine
|
||||
* converts the `'a` and `Bar` intos an `ExistentialBounds`
|
||||
* struct. The `main_trait_refs` argument specifies the `Foo` --
|
||||
* it is absent for closures. Eventually this should all be
|
||||
* normalized, I think, so that there is no "main trait ref" and
|
||||
* instead we just have a flat list of bounds as the existential
|
||||
* type.
|
||||
*/
|
||||
|
||||
match ast_bounds {
|
||||
&Some(ref bound_vec) => {
|
||||
let mut builtin_bounds = ty::empty_builtin_bounds();
|
||||
for ast_bound in bound_vec.iter() {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(ref b) => {
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
def::DefTrait(trait_did) => {
|
||||
if ty::try_add_builtin_trait(tcx, trait_did,
|
||||
&mut builtin_bounds) {
|
||||
continue; // success
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
tcx.sess.span_fatal(
|
||||
b.path.span,
|
||||
"only the builtin traits can be used as closure \
|
||||
or object bounds");
|
||||
}
|
||||
ast::StaticRegionTyParamBound => {
|
||||
builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
ast::UnboxedFnTyParamBound(_) => {
|
||||
tcx.sess.span_err(span,
|
||||
"unboxed functions are not allowed \
|
||||
here");
|
||||
}
|
||||
ast::OtherRegionTyParamBound(span) => {
|
||||
if !tcx.sess.features.issue_5723_bootstrap.get() {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
"only the 'static lifetime is accepted \
|
||||
here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
builtin_bounds
|
||||
},
|
||||
// &'static Trait is sugar for &'static Trait:'static.
|
||||
&None if static_region => {
|
||||
let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set
|
||||
}
|
||||
&None => ty::empty_builtin_bounds(),
|
||||
let ast_bound_refs: Vec<&ast::TyParamBound> =
|
||||
ast_bounds.iter().collect();
|
||||
|
||||
let PartitionedBounds { builtin_bounds,
|
||||
trait_bounds,
|
||||
region_bounds,
|
||||
unboxed_fn_ty_bounds } =
|
||||
partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
|
||||
|
||||
if !trait_bounds.is_empty() {
|
||||
let b = trait_bounds.get(0);
|
||||
this.tcx().sess.span_err(
|
||||
b.path.span,
|
||||
format!("only the builtin traits can be used \
|
||||
as closure or object bounds").as_slice());
|
||||
}
|
||||
|
||||
if !unboxed_fn_ty_bounds.is_empty() {
|
||||
this.tcx().sess.span_err(
|
||||
span,
|
||||
format!("only the builtin traits can be used \
|
||||
as closure or object bounds").as_slice());
|
||||
}
|
||||
|
||||
// The "main trait refs", rather annoyingly, have no type
|
||||
// specified for the `Self` parameter of the trait. The reason for
|
||||
// this is that they are, after all, *existential* types, and
|
||||
// hence that type is unknown. However, leaving this type missing
|
||||
// causes the substitution code to go all awry when walking the
|
||||
// bounds, so here we clone those trait refs and insert ty::err as
|
||||
// the self type. Perhaps we should do this more generally, it'd
|
||||
// be convenient (or perhaps something else, i.e., ty::erased).
|
||||
let main_trait_refs: Vec<Rc<ty::TraitRef>> =
|
||||
main_trait_refs.iter()
|
||||
.map(|t|
|
||||
Rc::new(ty::TraitRef {
|
||||
def_id: t.def_id,
|
||||
substs: t.substs.with_self_ty(ty::mk_err()) }))
|
||||
.collect();
|
||||
|
||||
let region_bound = compute_region_bound(this,
|
||||
rscope,
|
||||
span,
|
||||
builtin_bounds,
|
||||
region_bounds.as_slice(),
|
||||
main_trait_refs.as_slice());
|
||||
|
||||
ty::ExistentialBounds {
|
||||
region_bound: region_bound,
|
||||
builtin_bounds: builtin_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_opt_region_bound(tcx: &ty::ctxt,
|
||||
span: Span,
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
trait_bounds: &[Rc<ty::TraitRef>])
|
||||
-> Option<ty::Region>
|
||||
{
|
||||
/*!
|
||||
* Given the bounds on a type parameter / existential type,
|
||||
* determines what single region bound (if any) we can use to
|
||||
* summarize this type. The basic idea is that we will use the
|
||||
* bound the user provided, if they provided one, and otherwise
|
||||
* search the supertypes of trait bounds for region bounds. It may
|
||||
* be that we can derive no bound at all, in which case we return
|
||||
* `None`.
|
||||
*/
|
||||
|
||||
if region_bounds.len() > 1 {
|
||||
tcx.sess.span_err(
|
||||
region_bounds[1].span,
|
||||
format!("only a single explicit lifetime bound is permitted").as_slice());
|
||||
}
|
||||
|
||||
if region_bounds.len() != 0 {
|
||||
// Explicitly specified region bound. Use that.
|
||||
let r = region_bounds[0];
|
||||
return Some(ast_region_to_region(tcx, r));
|
||||
}
|
||||
|
||||
// No explicit region bound specified. Therefore, examine trait
|
||||
// bounds and see if we can derive region bounds from those.
|
||||
let derived_region_bounds =
|
||||
ty::required_region_bounds(
|
||||
tcx,
|
||||
[],
|
||||
builtin_bounds,
|
||||
trait_bounds);
|
||||
|
||||
// If there are no derived region bounds, then report back that we
|
||||
// can find no region bound.
|
||||
if derived_region_bounds.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// If any of the derived region bounds are 'static, that is always
|
||||
// the best choice.
|
||||
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
|
||||
return Some(ty::ReStatic);
|
||||
}
|
||||
|
||||
// Determine whether there is exactly one unique region in the set
|
||||
// of derived region bounds. If so, use that. Otherwise, report an
|
||||
// error.
|
||||
let r = *derived_region_bounds.get(0);
|
||||
if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
format!("ambiguous lifetime bound, \
|
||||
explicit lifetime bound required").as_slice());
|
||||
}
|
||||
return Some(r);
|
||||
}
|
||||
|
||||
fn compute_region_bound<AC:AstConv, RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
trait_bounds: &[Rc<ty::TraitRef>])
|
||||
-> ty::Region
|
||||
{
|
||||
/*!
|
||||
* A version of `compute_opt_region_bound` for use where some
|
||||
* region bound is required (existential types,
|
||||
* basically). Reports an error if no region bound can be derived
|
||||
* and we are in an `rscope` that does not provide a default.
|
||||
*/
|
||||
|
||||
match compute_opt_region_bound(this.tcx(), span, builtin_bounds,
|
||||
region_bounds, trait_bounds) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
match rscope.default_region_bound(span) {
|
||||
Some(r) => { r }
|
||||
None => {
|
||||
this.tcx().sess.span_err(
|
||||
span,
|
||||
format!("explicit lifetime bound required").as_slice());
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PartitionedBounds<'a> {
|
||||
pub builtin_bounds: ty::BuiltinBounds,
|
||||
pub trait_bounds: Vec<&'a ast::TraitRef>,
|
||||
pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnTy>,
|
||||
pub region_bounds: Vec<&'a ast::Lifetime>,
|
||||
}
|
||||
|
||||
pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
_span: Span,
|
||||
ast_bounds: &'a [&ast::TyParamBound])
|
||||
-> PartitionedBounds<'a>
|
||||
{
|
||||
/*!
|
||||
* Divides a list of bounds from the AST into three groups:
|
||||
* builtin bounds (Copy, Sized etc), general trait bounds,
|
||||
* and region bounds.
|
||||
*/
|
||||
|
||||
let mut builtin_bounds = ty::empty_builtin_bounds();
|
||||
let mut region_bounds = Vec::new();
|
||||
let mut trait_bounds = Vec::new();
|
||||
let mut unboxed_fn_ty_bounds = Vec::new();
|
||||
let mut trait_def_ids = HashMap::new();
|
||||
for &ast_bound in ast_bounds.iter() {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(ref b) => {
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
def::DefTrait(trait_did) => {
|
||||
match trait_def_ids.find(&trait_did) {
|
||||
// Already seen this trait. We forbid
|
||||
// duplicates in the list (for some
|
||||
// reason).
|
||||
Some(span) => {
|
||||
span_err!(
|
||||
tcx.sess, b.path.span, E0127,
|
||||
"trait `{}` already appears in the \
|
||||
list of bounds",
|
||||
b.path.user_string(tcx));
|
||||
tcx.sess.span_note(
|
||||
*span,
|
||||
"previous appearance is here");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
None => { }
|
||||
}
|
||||
|
||||
trait_def_ids.insert(trait_did, b.path.span);
|
||||
|
||||
if ty::try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
continue; // success
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Not a trait? that's an error, but it'll get
|
||||
// reported later.
|
||||
}
|
||||
}
|
||||
trait_bounds.push(b);
|
||||
}
|
||||
ast::RegionTyParamBound(ref l) => {
|
||||
region_bounds.push(l);
|
||||
}
|
||||
ast::UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||
unboxed_fn_ty_bounds.push(unboxed_function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PartitionedBounds {
|
||||
builtin_bounds: builtin_bounds,
|
||||
trait_bounds: trait_bounds,
|
||||
region_bounds: region_bounds,
|
||||
unboxed_fn_ty_bounds: unboxed_fn_ty_bounds
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ use middle::ty;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
|
||||
use middle::typeck::check;
|
||||
use middle::typeck::infer::MiscVariable;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::MethodCallee;
|
||||
use middle::typeck::{MethodOrigin, MethodParam};
|
||||
@ -240,6 +239,7 @@ fn construct_transformed_self_ty_for_object(
|
||||
span: Span,
|
||||
trait_def_id: ast::DefId,
|
||||
rcvr_substs: &subst::Substs,
|
||||
rcvr_bounds: ty::ExistentialBounds,
|
||||
method_ty: &ty::Method)
|
||||
-> ty::t
|
||||
{
|
||||
@ -276,8 +276,7 @@ fn construct_transformed_self_ty_for_object(
|
||||
tcx.sess.span_bug(span, "static method for object type receiver");
|
||||
}
|
||||
ByValueExplicitSelfCategory => {
|
||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
||||
ty::empty_builtin_bounds());
|
||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds);
|
||||
ty::mk_uniq(tcx, tr)
|
||||
}
|
||||
ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
|
||||
@ -286,12 +285,12 @@ fn construct_transformed_self_ty_for_object(
|
||||
ty::ty_rptr(r, mt) => { // must be SelfRegion
|
||||
let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
|
||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
||||
ty::empty_builtin_bounds());
|
||||
rcvr_bounds);
|
||||
ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
|
||||
}
|
||||
ty::ty_uniq(_) => { // must be SelfUniq
|
||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
||||
ty::empty_builtin_bounds());
|
||||
rcvr_bounds);
|
||||
ty::mk_uniq(tcx, tr)
|
||||
}
|
||||
_ => {
|
||||
@ -442,8 +441,9 @@ impl<'a> LookupContext<'a> {
|
||||
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
||||
match get(self_ty).sty {
|
||||
ty_trait(box TyTrait { def_id, ref substs, .. }) => {
|
||||
self.push_inherent_candidates_from_object(def_id, substs);
|
||||
ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
|
||||
self.push_inherent_candidates_from_object(
|
||||
def_id, substs, bounds);
|
||||
self.push_inherent_impl_candidates_for_type(def_id);
|
||||
}
|
||||
ty_enum(did, _) |
|
||||
@ -538,15 +538,13 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
|
||||
let vcx = self.fcx.vtable_context();
|
||||
let region_params =
|
||||
vec!(vcx.infcx.next_region_var(MiscVariable(self.span)));
|
||||
|
||||
// Get the tupled type of the arguments.
|
||||
let arguments_type = *closure_function_type.sig.inputs.get(0);
|
||||
let return_type = closure_function_type.sig.output;
|
||||
|
||||
let closure_region =
|
||||
vcx.infcx.next_region_var(MiscVariable(self.span));
|
||||
vcx.infcx.next_region_var(infer::MiscVariable(self.span));
|
||||
let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
|
||||
closure_did,
|
||||
closure_region);
|
||||
@ -555,7 +553,7 @@ impl<'a> LookupContext<'a> {
|
||||
RcvrMatchesIfSubtype(unboxed_closure_type),
|
||||
rcvr_substs: subst::Substs::new_trait(
|
||||
vec![arguments_type, return_type],
|
||||
region_params,
|
||||
vec![],
|
||||
*vcx.infcx.next_ty_vars(1).get(0)),
|
||||
method_ty: method,
|
||||
origin: MethodStaticUnboxedClosure(closure_did),
|
||||
@ -595,11 +593,11 @@ impl<'a> LookupContext<'a> {
|
||||
|
||||
fn push_inherent_candidates_from_object(&mut self,
|
||||
did: DefId,
|
||||
substs: &subst::Substs) {
|
||||
substs: &subst::Substs,
|
||||
bounds: ty::ExistentialBounds) {
|
||||
debug!("push_inherent_candidates_from_object(did={}, substs={})",
|
||||
self.did_to_string(did),
|
||||
substs.repr(self.tcx()));
|
||||
let _indenter = indenter();
|
||||
let tcx = self.tcx();
|
||||
let span = self.span;
|
||||
|
||||
@ -617,28 +615,30 @@ impl<'a> LookupContext<'a> {
|
||||
substs: rcvr_substs.clone()
|
||||
});
|
||||
|
||||
self.push_inherent_candidates_from_bounds_inner(&[trait_ref.clone()],
|
||||
|new_trait_ref, m, method_num, _bound_num| {
|
||||
let vtable_index = get_method_index(tcx, &*new_trait_ref,
|
||||
trait_ref.clone(), method_num);
|
||||
let mut m = (*m).clone();
|
||||
// We need to fix up the transformed self type.
|
||||
*m.fty.sig.inputs.get_mut(0) =
|
||||
construct_transformed_self_ty_for_object(
|
||||
tcx, span, did, &rcvr_substs, &m);
|
||||
self.push_inherent_candidates_from_bounds_inner(
|
||||
&[trait_ref.clone()],
|
||||
|_this, new_trait_ref, m, method_num, _bound_num| {
|
||||
let vtable_index =
|
||||
get_method_index(tcx, &*new_trait_ref,
|
||||
trait_ref.clone(), method_num);
|
||||
let mut m = (*m).clone();
|
||||
// We need to fix up the transformed self type.
|
||||
*m.fty.sig.inputs.get_mut(0) =
|
||||
construct_transformed_self_ty_for_object(
|
||||
tcx, span, did, &rcvr_substs, bounds, &m);
|
||||
|
||||
Some(Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfObject(did),
|
||||
rcvr_substs: new_trait_ref.substs.clone(),
|
||||
method_ty: Rc::new(m),
|
||||
origin: MethodObject(MethodObject {
|
||||
Some(Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfObject(did),
|
||||
rcvr_substs: new_trait_ref.substs.clone(),
|
||||
method_ty: Rc::new(m),
|
||||
origin: MethodObject(MethodObject {
|
||||
trait_id: new_trait_ref.def_id,
|
||||
object_trait_id: did,
|
||||
method_num: method_num,
|
||||
real_index: vtable_index
|
||||
})
|
||||
})
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn push_inherent_candidates_from_param(&mut self,
|
||||
@ -666,7 +666,7 @@ impl<'a> LookupContext<'a> {
|
||||
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
|
||||
.as_slice();
|
||||
self.push_inherent_candidates_from_bounds_inner(bounds,
|
||||
|trait_ref, m, method_num, bound_num| {
|
||||
|this, trait_ref, m, method_num, bound_num| {
|
||||
match restrict_to {
|
||||
Some(trait_did) => {
|
||||
if trait_did != trait_ref.def_id {
|
||||
@ -675,6 +675,18 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
debug!("found match: trait_ref={} substs={} m={}",
|
||||
trait_ref.repr(this.tcx()),
|
||||
trait_ref.substs.repr(this.tcx()),
|
||||
m.repr(this.tcx()));
|
||||
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
|
||||
Some(Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
||||
rcvr_substs: trait_ref.substs.clone(),
|
||||
@ -691,13 +703,15 @@ impl<'a> LookupContext<'a> {
|
||||
|
||||
// Do a search through a list of bounds, using a callback to actually
|
||||
// create the candidates.
|
||||
fn push_inherent_candidates_from_bounds_inner(&mut self,
|
||||
bounds: &[Rc<TraitRef>],
|
||||
mk_cand: |tr: Rc<TraitRef>,
|
||||
m: Rc<ty::Method>,
|
||||
method_num: uint,
|
||||
bound_num: uint|
|
||||
-> Option<Candidate>) {
|
||||
fn push_inherent_candidates_from_bounds_inner(
|
||||
&mut self,
|
||||
bounds: &[Rc<TraitRef>],
|
||||
mk_cand: |this: &mut LookupContext,
|
||||
tr: Rc<TraitRef>,
|
||||
m: Rc<ty::Method>,
|
||||
method_num: uint,
|
||||
bound_num: uint|
|
||||
-> Option<Candidate>) {
|
||||
let tcx = self.tcx();
|
||||
let mut next_bound_idx = 0; // count only trait bounds
|
||||
|
||||
@ -719,7 +733,8 @@ impl<'a> LookupContext<'a> {
|
||||
ty::MethodTraitItem(ref method) => (*method).clone(),
|
||||
};
|
||||
|
||||
match mk_cand(bound_trait_ref,
|
||||
match mk_cand(self,
|
||||
bound_trait_ref,
|
||||
method,
|
||||
pos,
|
||||
this_bound_idx) {
|
||||
@ -1338,6 +1353,11 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
self.fcx.add_region_obligations_for_parameters(
|
||||
self.span,
|
||||
&all_substs,
|
||||
&candidate.method_ty.generics);
|
||||
|
||||
MethodCallee {
|
||||
origin: candidate.origin,
|
||||
ty: fty,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -126,14 +126,14 @@ use middle::ty::{ReScope};
|
||||
use middle::ty;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::FnCtxt;
|
||||
use middle::typeck::check::regionmanip::relate_nested_regions;
|
||||
use middle::typeck::check::regionmanip;
|
||||
use middle::typeck::infer::resolve_and_force_all_but_regions;
|
||||
use middle::typeck::infer::resolve_type;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::MethodCall;
|
||||
use middle::pat_util;
|
||||
use util::nodemap::{DefIdMap, NodeMap};
|
||||
use util::ppaux::{ty_to_string, region_to_string, Repr};
|
||||
use util::ppaux::{ty_to_string, Repr};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
@ -143,6 +143,46 @@ use syntax::visit::Visitor;
|
||||
use std::cell::RefCell;
|
||||
use std::gc::Gc;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC ENTRY POINTS
|
||||
|
||||
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
|
||||
let mut rcx = Rcx::new(fcx, e.id);
|
||||
if fcx.err_count_since_creation() == 0 {
|
||||
// regionck assumes typeck succeeded
|
||||
rcx.visit_expr(e, ());
|
||||
rcx.visit_region_obligations(e.id);
|
||||
}
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
pub fn regionck_type_defn(fcx: &FnCtxt,
|
||||
span: Span,
|
||||
component_tys: &[ty::t]) {
|
||||
let mut rcx = Rcx::new(fcx, 0);
|
||||
for &component_ty in component_tys.iter() {
|
||||
// Check that each type outlives the empty region. Since the
|
||||
// empty region is a subregion of all others, this can't fail
|
||||
// unless the type does not meet the well-formedness
|
||||
// requirements.
|
||||
type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
|
||||
component_ty, ty::ReEmpty);
|
||||
}
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
|
||||
let mut rcx = Rcx::new(fcx, blk.id);
|
||||
if fcx.err_count_since_creation() == 0 {
|
||||
// regionck assumes typeck succeeded
|
||||
rcx.visit_fn_body(id, blk);
|
||||
}
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// INTERNALS
|
||||
|
||||
// If mem categorization results in an error, it's because the type
|
||||
// check failed (or will fail, when the error is uncovered and
|
||||
// reported during writeback). In this case, we just ignore this part
|
||||
@ -159,10 +199,32 @@ macro_rules! ignore_err(
|
||||
pub struct Rcx<'a> {
|
||||
fcx: &'a FnCtxt<'a>,
|
||||
|
||||
region_param_pairs: Vec<(ty::Region, ty::ParamTy)>,
|
||||
|
||||
// id of innermost fn or loop
|
||||
repeating_scope: ast::NodeId,
|
||||
}
|
||||
|
||||
/// When entering a function, we can derive relationships from the
|
||||
/// signature between various regions and type parameters. Consider
|
||||
/// a function like:
|
||||
///
|
||||
/// fn foo<'a, A>(x: &'a A) { ... }
|
||||
///
|
||||
/// Here, we can derive that `A` must outlive `'a`, because otherwise
|
||||
/// the caller would be illegal. We record this by storing a series of
|
||||
/// pairs (in this case, `('a, A)`). These pairs will be consulted
|
||||
/// later during regionck.
|
||||
///
|
||||
/// In the case of nested fns, additional relationships may be
|
||||
/// derived. The result is a link list walking up the stack (hence
|
||||
/// the `previous` field).
|
||||
#[deriving(Clone)]
|
||||
pub struct RegionSubParamConstraints<'a> {
|
||||
pairs: Vec<(ty::Region, ty::ParamTy)>,
|
||||
previous: Option<&'a RegionSubParamConstraints<'a>>,
|
||||
}
|
||||
|
||||
fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
|
||||
/*!
|
||||
* Returns the validity region of `def` -- that is, how long
|
||||
@ -189,6 +251,13 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
|
||||
}
|
||||
|
||||
impl<'a> Rcx<'a> {
|
||||
pub fn new(fcx: &'a FnCtxt<'a>,
|
||||
initial_repeating_scope: ast::NodeId) -> Rcx<'a> {
|
||||
Rcx { fcx: fcx,
|
||||
repeating_scope: initial_repeating_scope,
|
||||
region_param_pairs: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'a ty::ctxt {
|
||||
self.fcx.ccx.tcx
|
||||
}
|
||||
@ -259,6 +328,114 @@ impl<'a> Rcx<'a> {
|
||||
|method_call| self.resolve_method_type(method_call))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn_body(&mut self,
|
||||
id: ast::NodeId,
|
||||
body: &ast::Block)
|
||||
{
|
||||
// When we enter a function, we can derive
|
||||
|
||||
let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
|
||||
let fn_sig = match fn_sig_map.find(&id) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
self.tcx().sess.bug(
|
||||
format!("No fn-sig entry for id={}", id).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
let len = self.region_param_pairs.len();
|
||||
self.relate_free_regions(fn_sig.as_slice(), body.id);
|
||||
self.visit_block(body, ());
|
||||
self.visit_region_obligations(body.id);
|
||||
self.region_param_pairs.truncate(len);
|
||||
}
|
||||
|
||||
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
|
||||
{
|
||||
debug!("visit_region_obligations: node_id={}", node_id);
|
||||
let region_obligations = self.fcx.inh.region_obligations.borrow();
|
||||
match region_obligations.find(&node_id) {
|
||||
None => { }
|
||||
Some(vec) => {
|
||||
for r_o in vec.iter() {
|
||||
debug!("visit_region_obligations: r_o={}",
|
||||
r_o.repr(self.tcx()));
|
||||
let sup_type = self.resolve_type(r_o.sup_type);
|
||||
type_must_outlive(self, r_o.origin.clone(),
|
||||
sup_type, r_o.sub_region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn relate_free_regions(&mut self,
|
||||
fn_sig_tys: &[ty::t],
|
||||
body_id: ast::NodeId) {
|
||||
/*!
|
||||
* This method populates the region map's `free_region_map`.
|
||||
* It walks over the transformed argument and return types for
|
||||
* each function just before we check the body of that
|
||||
* function, looking for types where you have a borrowed
|
||||
* pointer to other borrowed data (e.g., `&'a &'b [uint]`. We
|
||||
* do not allow references to outlive the things they point
|
||||
* at, so we can assume that `'a <= 'b`. This holds for both
|
||||
* the argument and return types, basically because, on the caller
|
||||
* side, the caller is responsible for checking that the type of
|
||||
* every expression (including the actual values for the arguments,
|
||||
* as well as the return type of the fn call) is well-formed.
|
||||
*
|
||||
* Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
|
||||
*/
|
||||
|
||||
debug!("relate_free_regions >>");
|
||||
let tcx = self.tcx();
|
||||
|
||||
for &ty in fn_sig_tys.iter() {
|
||||
let ty = self.resolve_type(ty);
|
||||
debug!("relate_free_regions(t={})", ty.repr(tcx));
|
||||
let body_scope = ty::ReScope(body_id);
|
||||
let constraints =
|
||||
regionmanip::region_wf_constraints(
|
||||
tcx,
|
||||
ty,
|
||||
body_scope);
|
||||
for constraint in constraints.iter() {
|
||||
debug!("constraint: {}", constraint.repr(tcx));
|
||||
match *constraint {
|
||||
regionmanip::RegionSubRegionConstraint(_,
|
||||
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))) => {
|
||||
self.fcx.inh.infcx.add_given(free_a, vid_b);
|
||||
}
|
||||
regionmanip::RegionSubRegionConstraint(..) => {
|
||||
// In principle, we could record (and take
|
||||
// advantage of) every relationship here, but
|
||||
// we are also free not to -- it simply means
|
||||
// strictly less that we can successfully type
|
||||
// check. (It may also be that we should
|
||||
// revise our inference system to be more
|
||||
// general and to make use of *every*
|
||||
// relationship that arises here, but
|
||||
// presently we do not.)
|
||||
}
|
||||
regionmanip::RegionSubParamConstraint(_, r_a, p_b) => {
|
||||
debug!("RegionSubParamConstraint: {} <= {}",
|
||||
r_a.repr(tcx), p_b.repr(tcx));
|
||||
|
||||
self.region_param_pairs.push((r_a, p_b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("<< relate_free_regions");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'fcx> mc::Typer for Rcx<'fcx> {
|
||||
@ -302,26 +479,6 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
|
||||
let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id };
|
||||
let rcx = &mut rcx;
|
||||
if fcx.err_count_since_creation() == 0 {
|
||||
// regionck assumes typeck succeeded
|
||||
rcx.visit_expr(e, ());
|
||||
}
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
|
||||
let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id };
|
||||
let rcx = &mut rcx;
|
||||
if fcx.err_count_since_creation() == 0 {
|
||||
// regionck assumes typeck succeeded
|
||||
rcx.visit_block(blk, ());
|
||||
}
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
impl<'a> Visitor<()> for Rcx<'a> {
|
||||
// (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
|
||||
// However, right now we run into an issue whereby some free
|
||||
@ -331,6 +488,11 @@ impl<'a> Visitor<()> for Rcx<'a> {
|
||||
// hierarchy, and in particular the relationships between free
|
||||
// regions, until regionck, as described in #3238.
|
||||
|
||||
fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl,
|
||||
b: &ast::Block, _s: Span, id: ast::NodeId, _e: ()) {
|
||||
self.visit_fn_body(id, b)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
|
||||
|
||||
fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
|
||||
@ -396,9 +558,9 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
|
||||
// variable's type enclose at least the variable's scope.
|
||||
|
||||
let var_region = tcx.region_maps.var_region(id);
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, id, var_region,
|
||||
infer::BindingTypeIsNotValidAtDecl(span));
|
||||
type_of_node_must_outlive(
|
||||
rcx, infer::BindingTypeIsNotValidAtDecl(span),
|
||||
id, var_region);
|
||||
})
|
||||
}
|
||||
|
||||
@ -406,6 +568,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
|
||||
expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
|
||||
|
||||
// No matter what, the type of each expression must outlive the
|
||||
// scope of that expression. This also guarantees basic WF.
|
||||
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||
|
||||
type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span),
|
||||
expr_ty, ty::ReScope(expr.id));
|
||||
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
|
||||
|
||||
@ -416,40 +585,28 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
|
||||
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
|
||||
match ty::adjusted_object_region(adjustment) {
|
||||
Some(trait_region) => {
|
||||
// Determine if we are casting `expr` to a trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
for autoref in opt_autoref.iter() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
|
||||
constrain_regions_in_type(rcx, trait_region,
|
||||
infer::RelateObjectBound(expr.span), expr_ty);
|
||||
}
|
||||
None => {
|
||||
for autoref in opt_autoref.iter() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
}
|
||||
}
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
type_of_node_must_outlive(
|
||||
rcx, infer::AutoBorrow(expr.span),
|
||||
expr.id, ty::ReScope(expr.id));
|
||||
}
|
||||
}
|
||||
/*
|
||||
ty::AutoObject(_, ref bounds, _, _) => {
|
||||
// Determine if we are casting `expr` to a trait
|
||||
// instance. If so, we have to be sure that the type
|
||||
// of the source obeys the new region bound.
|
||||
let source_ty = rcx.resolve_node_type(expr.id);
|
||||
type_must_outlive(rcx, infer::RelateObjectBound(expr.span),
|
||||
source_ty, bounds.region_bound);
|
||||
}
|
||||
*/
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -457,12 +614,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprCall(ref callee, ref args) => {
|
||||
if has_method_map {
|
||||
constrain_call(rcx, None, expr, Some(*callee),
|
||||
constrain_call(rcx, expr, Some(*callee),
|
||||
args.as_slice(), false);
|
||||
} else {
|
||||
constrain_callee(rcx, callee.id, expr, &**callee);
|
||||
constrain_call(rcx,
|
||||
Some(callee.id),
|
||||
expr,
|
||||
None,
|
||||
args.as_slice(),
|
||||
@ -473,7 +629,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
}
|
||||
|
||||
ast::ExprMethodCall(_, _, ref args) => {
|
||||
constrain_call(rcx, None, expr, Some(*args.get(0)),
|
||||
constrain_call(rcx, expr, Some(*args.get(0)),
|
||||
args.slice_from(1), false);
|
||||
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
@ -486,7 +642,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
|
||||
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||
if has_method_map {
|
||||
constrain_call(rcx, None, expr, Some(lhs.clone()),
|
||||
constrain_call(rcx, expr, Some(lhs.clone()),
|
||||
[rhs.clone()], true);
|
||||
}
|
||||
|
||||
@ -501,7 +657,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
// overloaded op. Note that we (sadly) currently use an
|
||||
// implicit "by ref" sort of passing style here. This
|
||||
// should be converted to an adjustment!
|
||||
constrain_call(rcx, None, expr, Some(lhs.clone()),
|
||||
constrain_call(rcx, expr, Some(lhs.clone()),
|
||||
[rhs.clone()], true);
|
||||
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
@ -509,17 +665,25 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
|
||||
ast::ExprUnary(_, ref lhs) if has_method_map => {
|
||||
// As above.
|
||||
constrain_call(rcx, None, expr, Some(lhs.clone()), [], true);
|
||||
constrain_call(rcx, expr, Some(lhs.clone()), [], true);
|
||||
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
||||
ast::ExprUnary(ast::UnBox, ref base) => {
|
||||
// Managed data must not have borrowed pointers within it:
|
||||
let base_ty = rcx.resolve_node_type(base.id);
|
||||
type_must_outlive(rcx, infer::Managed(expr.span),
|
||||
base_ty, ty::ReStatic);
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
||||
ast::ExprUnary(ast::UnDeref, ref base) => {
|
||||
// For *a, the lifetime of a must enclose the deref
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
|
||||
Some(method) => {
|
||||
constrain_call(rcx, None, expr, Some(base.clone()), [], true);
|
||||
constrain_call(rcx, expr, Some(base.clone()), [], true);
|
||||
ty::ty_fn_ret(method.ty)
|
||||
}
|
||||
None => rcx.resolve_node_type(base.id)
|
||||
@ -547,34 +711,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
// Determine if we are casting `source` to a trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
let target_ty = rcx.resolve_node_type(expr.id);
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_rptr(trait_region, ty::mt{ty, ..}) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(..) => {
|
||||
let source_ty = rcx.resolve_expr_type_adjusted(&**source);
|
||||
constrain_regions_in_type(
|
||||
rcx,
|
||||
trait_region,
|
||||
infer::RelateObjectBound(expr.span),
|
||||
source_ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
constrain_cast(rcx, expr, &**source);
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
||||
@ -589,8 +726,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
//
|
||||
// FIXME(#6268) nested method calls requires that this rule change
|
||||
let ty0 = rcx.resolve_node_type(expr.id);
|
||||
constrain_regions_in_type(rcx, ty::ReScope(expr.id),
|
||||
infer::AddrOf(expr.span), ty0);
|
||||
type_must_outlive(rcx, infer::AddrOf(expr.span),
|
||||
ty0, ty::ReScope(expr.id));
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
||||
@ -644,42 +781,108 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_cast(rcx: &mut Rcx,
|
||||
cast_expr: &ast::Expr,
|
||||
source_expr: &ast::Expr)
|
||||
{
|
||||
debug!("constrain_cast(cast_expr={}, source_expr={})",
|
||||
cast_expr.repr(rcx.tcx()),
|
||||
source_expr.repr(rcx.tcx()));
|
||||
|
||||
let source_ty = rcx.resolve_node_type(source_expr.id);
|
||||
let target_ty = rcx.resolve_node_type(cast_expr.id);
|
||||
|
||||
walk_cast(rcx, cast_expr, source_ty, target_ty);
|
||||
|
||||
fn walk_cast(rcx: &mut Rcx,
|
||||
cast_expr: &ast::Expr,
|
||||
from_ty: ty::t,
|
||||
to_ty: ty::t) {
|
||||
debug!("walk_cast(from_ty={}, to_ty={})",
|
||||
from_ty.repr(rcx.tcx()),
|
||||
to_ty.repr(rcx.tcx()));
|
||||
match (&ty::get(from_ty).sty, &ty::get(to_ty).sty) {
|
||||
/*From:*/ (&ty::ty_rptr(from_r, ref from_mt),
|
||||
/*To: */ &ty::ty_rptr(to_r, ref to_mt)) => {
|
||||
// Target cannot outlive source, naturally.
|
||||
rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), to_r, from_r);
|
||||
walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty);
|
||||
}
|
||||
|
||||
/*From:*/ (_,
|
||||
/*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => {
|
||||
// When T is existentially quantified as a trait
|
||||
// `Foo+'to`, it must outlive the region bound `'to`.
|
||||
type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span),
|
||||
from_ty, bounds.region_bound);
|
||||
}
|
||||
|
||||
/*From:*/ (&ty::ty_uniq(from_referent_ty),
|
||||
/*To: */ &ty::ty_uniq(to_referent_ty)) => {
|
||||
walk_cast(rcx, cast_expr, from_referent_ty, to_referent_ty);
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
expr: &ast::Expr,
|
||||
body: &ast::Block) {
|
||||
let tcx = rcx.fcx.tcx();
|
||||
let function_type = rcx.resolve_node_type(expr.id);
|
||||
|
||||
match ty::get(function_type).sty {
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(region, _), ..}) => {
|
||||
ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..),
|
||||
bounds: ref bounds,
|
||||
..}) => {
|
||||
// For closure, ensure that the variables outlive region
|
||||
// bound, since they are captured by reference.
|
||||
freevars::with_freevars(tcx, expr.id, |freevars| {
|
||||
if freevars.is_empty() {
|
||||
// No free variables means that the environment
|
||||
// will be NULL at runtime and hence the closure
|
||||
// has static lifetime.
|
||||
} else {
|
||||
// Closure must not outlive the variables it closes over.
|
||||
constrain_free_variables(rcx, region, expr, freevars);
|
||||
// Variables being referenced must outlive closure.
|
||||
constrain_free_variables_in_stack_closure(
|
||||
rcx, bounds.region_bound, expr, freevars);
|
||||
|
||||
// Closure cannot outlive the appropriate temporary scope.
|
||||
// Closure is stack allocated and hence cannot
|
||||
// outlive the appropriate temporary scope.
|
||||
let s = rcx.repeating_scope;
|
||||
rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
|
||||
region, ty::ReScope(s));
|
||||
rcx.fcx.mk_subr(infer::InfStackClosure(expr.span),
|
||||
bounds.region_bound, ty::ReScope(s));
|
||||
}
|
||||
});
|
||||
}
|
||||
ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
|
||||
bounds: ref bounds,
|
||||
..}) => {
|
||||
// For proc, ensure that the *types* of the variables
|
||||
// outlive region bound, since they are captured by value.
|
||||
freevars::with_freevars(tcx, expr.id, |freevars| {
|
||||
ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx, bounds.region_bound, expr, freevars);
|
||||
});
|
||||
}
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
freevars::with_freevars(tcx, expr.id, |freevars| {
|
||||
// No free variables means that there is no environment and
|
||||
// hence the closure has static lifetime. Otherwise, the
|
||||
// closure must not outlive the variables it closes over
|
||||
// by-reference.
|
||||
//
|
||||
// NDM -- this seems wrong, discuss with pcwalton, should
|
||||
// be straightforward enough.
|
||||
if !freevars.is_empty() {
|
||||
constrain_free_variables(rcx, region, expr, freevars);
|
||||
ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx, region, expr, freevars);
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => ()
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let repeating_scope = rcx.set_repeating_scope(body.id);
|
||||
@ -698,36 +901,74 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
_ => ()
|
||||
}
|
||||
|
||||
fn constrain_free_variables(rcx: &mut Rcx,
|
||||
region: ty::Region,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[freevars::freevar_entry]) {
|
||||
fn ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx: &mut Rcx,
|
||||
region_bound: ty::Region,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[freevars::freevar_entry])
|
||||
{
|
||||
/*!
|
||||
* Make sure that all free variables referenced inside the closure
|
||||
* outlive the closure itself. Also, create an entry in the
|
||||
* upvar_borrows map with a region.
|
||||
* Make sure that the type of all free variables referenced
|
||||
* inside a closure/proc outlive the closure/proc's lifetime
|
||||
* bound. This is just a special case of the usual rules about
|
||||
* closed over values outliving the object's lifetime bound.
|
||||
*/
|
||||
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
|
||||
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
|
||||
region_bound.repr(tcx), expr.repr(tcx));
|
||||
|
||||
for freevar in freevars.iter() {
|
||||
let var_node_id = {
|
||||
let def_id = freevar.def.def_id();
|
||||
assert!(def_id.krate == ast::LOCAL_CRATE);
|
||||
def_id.node
|
||||
};
|
||||
|
||||
let var_ty = rcx.resolve_node_type(var_node_id);
|
||||
|
||||
type_must_outlive(
|
||||
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
|
||||
var_ty, region_bound);
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_free_variables_in_stack_closure(
|
||||
rcx: &mut Rcx,
|
||||
region_bound: ty::Region,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[freevars::freevar_entry])
|
||||
{
|
||||
/*!
|
||||
* Make sure that all free variables referenced inside the
|
||||
* closure outlive the closure's lifetime bound. Also, create
|
||||
* an entry in the upvar_borrows map with a region.
|
||||
*/
|
||||
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
let infcx = rcx.fcx.infcx();
|
||||
debug!("constrain_free_variables({}, {})",
|
||||
region.repr(tcx), expr.repr(tcx));
|
||||
region_bound.repr(tcx), expr.repr(tcx));
|
||||
for freevar in freevars.iter() {
|
||||
debug!("freevar def is {:?}", freevar.def);
|
||||
|
||||
// Identify the variable being closed over and its node-id.
|
||||
let def = freevar.def;
|
||||
let def_id = def.def_id();
|
||||
assert!(def_id.krate == ast::LOCAL_CRATE);
|
||||
let upvar_id = ty::UpvarId { var_id: def_id.node,
|
||||
let var_node_id = {
|
||||
let def_id = def.def_id();
|
||||
assert!(def_id.krate == ast::LOCAL_CRATE);
|
||||
def_id.node
|
||||
};
|
||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||
closure_expr_id: expr.id };
|
||||
|
||||
// Create a region variable to represent this borrow. This borrow
|
||||
// must outlive the region on the closure.
|
||||
let origin = infer::UpvarRegion(upvar_id, expr.span);
|
||||
let freevar_region = infcx.next_region_var(origin);
|
||||
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
|
||||
region, freevar_region);
|
||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||
region_bound, freevar_region);
|
||||
|
||||
// Create a UpvarBorrow entry. Note that we begin with a
|
||||
// const borrow_kind, but change it to either mut or
|
||||
@ -738,10 +979,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
upvar_borrow);
|
||||
|
||||
// Guarantee that the closure does not outlive the variable itself.
|
||||
let en_region = region_of_def(rcx.fcx, def);
|
||||
debug!("en_region = {}", en_region.repr(tcx));
|
||||
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
|
||||
region, en_region);
|
||||
let enclosing_region = region_of_def(rcx.fcx, def);
|
||||
debug!("enclosing_region = {}", enclosing_region.repr(tcx));
|
||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||
region_bound, enclosing_region);
|
||||
}
|
||||
}
|
||||
|
||||
@ -817,7 +1058,7 @@ fn constrain_callee(rcx: &mut Rcx,
|
||||
}
|
||||
ty::UniqTraitStore => ty::ReStatic
|
||||
};
|
||||
rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
|
||||
rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
|
||||
call_region, region);
|
||||
}
|
||||
_ => {
|
||||
@ -832,9 +1073,6 @@ fn constrain_callee(rcx: &mut Rcx,
|
||||
}
|
||||
|
||||
fn constrain_call(rcx: &mut Rcx,
|
||||
// might be expr_call, expr_method_call, or an overloaded
|
||||
// operator
|
||||
fn_expr_id: Option<ast::NodeId>,
|
||||
call_expr: &ast::Expr,
|
||||
receiver: Option<Gc<ast::Expr>>,
|
||||
arg_exprs: &[Gc<ast::Expr>],
|
||||
@ -853,16 +1091,6 @@ fn constrain_call(rcx: &mut Rcx,
|
||||
receiver.repr(tcx),
|
||||
arg_exprs.repr(tcx),
|
||||
implicitly_ref_args);
|
||||
let callee_ty = match fn_expr_id {
|
||||
Some(id) => rcx.resolve_node_type(id),
|
||||
None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
|
||||
.expect("call should have been to a method")
|
||||
};
|
||||
if ty::type_is_error(callee_ty) {
|
||||
// Bail, as function type is unknown
|
||||
return;
|
||||
}
|
||||
let fn_sig = ty::ty_fn_sig(callee_ty);
|
||||
|
||||
// `callee_region` is the scope representing the time in which the
|
||||
// call occurs.
|
||||
@ -871,14 +1099,16 @@ fn constrain_call(rcx: &mut Rcx,
|
||||
let callee_scope = call_expr.id;
|
||||
let callee_region = ty::ReScope(callee_scope);
|
||||
|
||||
debug!("callee_region={}", callee_region.repr(tcx));
|
||||
|
||||
for arg_expr in arg_exprs.iter() {
|
||||
debug!("Argument");
|
||||
debug!("Argument: {}", arg_expr.repr(tcx));
|
||||
|
||||
// ensure that any regions appearing in the argument type are
|
||||
// valid for at least the lifetime of the function:
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, arg_expr.id, callee_region,
|
||||
infer::CallArg(arg_expr.span));
|
||||
type_of_node_must_outlive(
|
||||
rcx, infer::CallArg(arg_expr.span),
|
||||
arg_expr.id, callee_region);
|
||||
|
||||
// unfortunately, there are two means of taking implicit
|
||||
// references, and we need to propagate constraints as a
|
||||
@ -891,19 +1121,14 @@ fn constrain_call(rcx: &mut Rcx,
|
||||
|
||||
// as loop above, but for receiver
|
||||
for r in receiver.iter() {
|
||||
debug!("Receiver");
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, r.id, callee_region, infer::CallRcvr(r.span));
|
||||
debug!("receiver: {}", r.repr(tcx));
|
||||
type_of_node_must_outlive(
|
||||
rcx, infer::CallRcvr(r.span),
|
||||
r.id, callee_region);
|
||||
if implicitly_ref_args {
|
||||
link_by_ref(rcx, &**r, callee_scope);
|
||||
}
|
||||
}
|
||||
|
||||
// constrain regions that may appear in the return type to be
|
||||
// valid for the function call:
|
||||
constrain_regions_in_type(
|
||||
rcx, callee_region, infer::CallReturn(call_expr.span),
|
||||
fn_sig.output);
|
||||
}
|
||||
|
||||
fn constrain_autoderefs(rcx: &mut Rcx,
|
||||
@ -942,12 +1167,10 @@ fn constrain_autoderefs(rcx: &mut Rcx,
|
||||
}
|
||||
|
||||
// Specialized version of constrain_call.
|
||||
constrain_regions_in_type(rcx, r_deref_expr,
|
||||
infer::CallRcvr(deref_expr.span),
|
||||
self_ty);
|
||||
constrain_regions_in_type(rcx, r_deref_expr,
|
||||
infer::CallReturn(deref_expr.span),
|
||||
fn_sig.output);
|
||||
type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
|
||||
self_ty, r_deref_expr);
|
||||
type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
|
||||
fn_sig.output, r_deref_expr);
|
||||
fn_sig.output
|
||||
}
|
||||
None => derefd_ty
|
||||
@ -974,7 +1197,7 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
|
||||
deref_span: Span,
|
||||
minimum_lifetime: ty::Region,
|
||||
maximum_lifetime: ty::Region) {
|
||||
rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
|
||||
rcx.fcx.mk_subr(infer::DerefPointer(deref_span),
|
||||
minimum_lifetime, maximum_lifetime)
|
||||
}
|
||||
|
||||
@ -996,7 +1219,7 @@ fn constrain_index(rcx: &mut Rcx,
|
||||
match ty::get(indexed_ty).sty {
|
||||
ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
|
||||
rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span),
|
||||
r_index_expr, r_ptr);
|
||||
}
|
||||
_ => {}
|
||||
@ -1006,14 +1229,17 @@ fn constrain_index(rcx: &mut Rcx,
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_regions_in_type_of_node(
|
||||
fn type_of_node_must_outlive(
|
||||
rcx: &mut Rcx,
|
||||
origin: infer::SubregionOrigin,
|
||||
id: ast::NodeId,
|
||||
minimum_lifetime: ty::Region,
|
||||
origin: infer::SubregionOrigin) {
|
||||
//! Guarantees that any lifetimes which appear in the type of
|
||||
//! the node `id` (after applying adjustments) are valid for at
|
||||
//! least `minimum_lifetime`
|
||||
minimum_lifetime: ty::Region)
|
||||
{
|
||||
/*!
|
||||
* Guarantees that any lifetimes which appear in the type of
|
||||
* the node `id` (after applying adjustments) are valid for at
|
||||
* least `minimum_lifetime`
|
||||
*/
|
||||
|
||||
let tcx = rcx.fcx.tcx();
|
||||
|
||||
@ -1028,54 +1254,7 @@ fn constrain_regions_in_type_of_node(
|
||||
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
||||
ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
|
||||
id, minimum_lifetime);
|
||||
constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
|
||||
}
|
||||
|
||||
fn constrain_regions_in_type(
|
||||
rcx: &mut Rcx,
|
||||
minimum_lifetime: ty::Region,
|
||||
origin: infer::SubregionOrigin,
|
||||
ty: ty::t) {
|
||||
/*!
|
||||
* Requires that any regions which appear in `ty` must be
|
||||
* superregions of `minimum_lifetime`. Also enforces the constraint
|
||||
* that given a pointer type `&'r T`, T must not contain regions
|
||||
* that outlive 'r, as well as analogous constraints for other
|
||||
* lifetime'd types.
|
||||
*
|
||||
* This check prevents regions from being used outside of the block in
|
||||
* which they are valid. Recall that regions represent blocks of
|
||||
* code or expressions: this requirement basically says "any place
|
||||
* that uses or may use a region R must be within the block of
|
||||
* code that R corresponds to."
|
||||
*/
|
||||
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
|
||||
debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
|
||||
region_to_string(tcx, "", false, minimum_lifetime),
|
||||
ty_to_string(tcx, ty));
|
||||
|
||||
relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
|
||||
debug!("relate_nested_regions(r_sub={}, r_sup={})",
|
||||
r_sub.repr(tcx),
|
||||
r_sup.repr(tcx));
|
||||
|
||||
if r_sup.is_bound() || r_sub.is_bound() {
|
||||
// a bound region is one which appears inside an fn type.
|
||||
// (e.g., the `&` in `fn(&T)`). Such regions need not be
|
||||
// constrained by `minimum_lifetime` as they are placeholders
|
||||
// for regions that are as-yet-unknown.
|
||||
} else if r_sub == minimum_lifetime {
|
||||
rcx.fcx.mk_subr(
|
||||
true, origin.clone(),
|
||||
r_sub, r_sup);
|
||||
} else {
|
||||
rcx.fcx.mk_subr(
|
||||
true, infer::ReferenceOutlivesReferent(ty, origin.span()),
|
||||
r_sub, r_sup);
|
||||
}
|
||||
});
|
||||
type_must_outlive(rcx, origin, ty, minimum_lifetime);
|
||||
}
|
||||
|
||||
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
||||
@ -1290,7 +1469,7 @@ fn link_region(rcx: &Rcx,
|
||||
debug!("link_region: {} <= {}",
|
||||
region_min.repr(rcx.tcx()),
|
||||
r_borrowed.repr(rcx.tcx()));
|
||||
rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
|
||||
rcx.fcx.mk_subr(cause, region_min, r_borrowed);
|
||||
|
||||
if kind != ty::ImmBorrow {
|
||||
// If this is a mutable borrow, then the thing
|
||||
@ -1522,3 +1701,99 @@ fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn type_must_outlive(rcx: &mut Rcx,
|
||||
origin: infer::SubregionOrigin,
|
||||
ty: ty::t,
|
||||
region: ty::Region)
|
||||
{
|
||||
/*!
|
||||
* Ensures that all borrowed data reachable via `ty` outlives `region`.
|
||||
*/
|
||||
|
||||
debug!("type_must_outlive(ty={}, region={})",
|
||||
ty.repr(rcx.tcx()),
|
||||
region.repr(rcx.tcx()));
|
||||
|
||||
let constraints =
|
||||
regionmanip::region_wf_constraints(
|
||||
rcx.tcx(),
|
||||
ty,
|
||||
region);
|
||||
for constraint in constraints.iter() {
|
||||
debug!("constraint: {}", constraint.repr(rcx.tcx()));
|
||||
match *constraint {
|
||||
regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => {
|
||||
rcx.fcx.mk_subr(origin.clone(), r_a, r_b);
|
||||
}
|
||||
regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => {
|
||||
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
|
||||
rcx.fcx.mk_subr(o1, r_a, r_b);
|
||||
}
|
||||
regionmanip::RegionSubParamConstraint(None, r_a, param_b) => {
|
||||
param_must_outlive(rcx, origin.clone(), r_a, param_b);
|
||||
}
|
||||
regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => {
|
||||
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
|
||||
param_must_outlive(rcx, o1, r_a, param_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn param_must_outlive(rcx: &Rcx,
|
||||
origin: infer::SubregionOrigin,
|
||||
region: ty::Region,
|
||||
param_ty: ty::ParamTy) {
|
||||
let param_env = &rcx.fcx.inh.param_env;
|
||||
|
||||
debug!("param_must_outlive(region={}, param_ty={})",
|
||||
region.repr(rcx.tcx()),
|
||||
param_ty.repr(rcx.tcx()));
|
||||
|
||||
// Collect all regions that `param_ty` is known to outlive into
|
||||
// this vector:
|
||||
let mut param_bounds;
|
||||
|
||||
// To start, collect bounds from user:
|
||||
let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
|
||||
param_bounds =
|
||||
ty::required_region_bounds(rcx.tcx(),
|
||||
param_bound.opt_region_bound.as_slice(),
|
||||
param_bound.builtin_bounds,
|
||||
param_bound.trait_bounds.as_slice());
|
||||
|
||||
// Collect default bound of fn body that applies to all in scope
|
||||
// type parameters:
|
||||
param_bounds.push(param_env.implicit_region_bound);
|
||||
|
||||
// Finally, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
// of known relations from the fn ctxt.
|
||||
//
|
||||
// This is crucial because otherwise code like this fails:
|
||||
//
|
||||
// fn foo<'a, A>(x: &'a A) { x.bar() }
|
||||
//
|
||||
// The problem is that the type of `x` is `&'a A`. To be
|
||||
// well-formed, then, A must be lower-bounded by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
for &(ref r, ref p) in rcx.region_param_pairs.iter() {
|
||||
debug!("param_ty={}/{} p={}/{}",
|
||||
param_ty.repr(rcx.tcx()),
|
||||
param_ty.def_id,
|
||||
p.repr(rcx.tcx()),
|
||||
p.def_id);
|
||||
if param_ty == *p {
|
||||
param_bounds.push(*r);
|
||||
}
|
||||
}
|
||||
|
||||
// Inform region inference that this parameter type must be
|
||||
// properly bounded.
|
||||
infer::verify_param_bound(rcx.fcx.infcx(),
|
||||
origin,
|
||||
param_ty,
|
||||
region,
|
||||
param_bounds);
|
||||
}
|
||||
|
@ -10,13 +10,15 @@
|
||||
|
||||
// #![warn(deprecated_mode)]
|
||||
|
||||
use middle::subst::{ParamSpace, Subst, Substs};
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux;
|
||||
|
||||
// Helper functions related to manipulating region types.
|
||||
|
||||
@ -44,125 +46,363 @@ pub fn replace_late_bound_regions_in_fn_sig(
|
||||
(map, fn_sig)
|
||||
}
|
||||
|
||||
pub fn relate_nested_regions(tcx: &ty::ctxt,
|
||||
opt_region: Option<ty::Region>,
|
||||
ty: ty::t,
|
||||
relate_op: |ty::Region, ty::Region|) {
|
||||
pub enum WfConstraint {
|
||||
RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
|
||||
RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
|
||||
}
|
||||
|
||||
struct Wf<'a> {
|
||||
tcx: &'a ty::ctxt,
|
||||
stack: Vec<(ty::Region, Option<ty::t>)>,
|
||||
out: Vec<WfConstraint>,
|
||||
}
|
||||
|
||||
pub fn region_wf_constraints(
|
||||
tcx: &ty::ctxt,
|
||||
ty: ty::t,
|
||||
outer_region: ty::Region)
|
||||
-> Vec<WfConstraint>
|
||||
{
|
||||
/*!
|
||||
* This rather specialized function walks each region `r` that appear
|
||||
* in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
|
||||
* here is the region of any enclosing `&'r T` pointer. If there is
|
||||
* no enclosing pointer, and `opt_region` is Some, then `opt_region.get()`
|
||||
* is used instead. Otherwise, no callback occurs at all).
|
||||
*
|
||||
* Here are some examples to give you an intution:
|
||||
*
|
||||
* - `relate_nested_regions(Some('r1), &'r2 uint)` invokes
|
||||
* - `relate_op('r1, 'r2)`
|
||||
* - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes
|
||||
* - `relate_op('r1, 'r2)`
|
||||
* - `relate_op('r2, 'r3)`
|
||||
* - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes
|
||||
* - `relate_op('r2, 'r3)`
|
||||
* - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes
|
||||
* - `relate_op('r2, 'r3)`
|
||||
* - `relate_op('r2, 'r4)`
|
||||
* - `relate_op('r3, 'r4)`
|
||||
*
|
||||
* This function is used in various pieces of code because we enforce the
|
||||
* constraint that a region pointer cannot outlive the things it points at.
|
||||
* Hence, in the second example above, `'r2` must be a subregion of `'r3`.
|
||||
* This routine computes the well-formedness constraints that must
|
||||
* hold for the type `ty` to appear in a context with lifetime
|
||||
* `outer_region`
|
||||
*/
|
||||
|
||||
let mut rr = RegionRelator { tcx: tcx,
|
||||
stack: Vec::new(),
|
||||
relate_op: relate_op };
|
||||
match opt_region {
|
||||
Some(o_r) => { rr.stack.push(o_r); }
|
||||
None => {}
|
||||
}
|
||||
rr.fold_ty(ty);
|
||||
let mut stack = Vec::new();
|
||||
stack.push((outer_region, None));
|
||||
let mut wf = Wf { tcx: tcx,
|
||||
stack: stack,
|
||||
out: Vec::new() };
|
||||
wf.accumulate_from_ty(ty);
|
||||
wf.out
|
||||
}
|
||||
|
||||
struct RegionRelator<'a> {
|
||||
tcx: &'a ty::ctxt,
|
||||
stack: Vec<ty::Region>,
|
||||
relate_op: |ty::Region, ty::Region|: 'a,
|
||||
}
|
||||
impl<'a> Wf<'a> {
|
||||
fn accumulate_from_ty(&mut self, ty: ty::t) {
|
||||
debug!("Wf::accumulate_from_ty(ty={})",
|
||||
ty.repr(self.tcx));
|
||||
|
||||
// FIXME(#10151) -- Define more precisely when a region is
|
||||
// considered "nested". Consider taking variance into account as
|
||||
// well.
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_nil |
|
||||
ty::ty_bot |
|
||||
ty::ty_bool |
|
||||
ty::ty_char |
|
||||
ty::ty_int(..) |
|
||||
ty::ty_uint(..) |
|
||||
ty::ty_float(..) |
|
||||
ty::ty_bare_fn(..) |
|
||||
ty::ty_err |
|
||||
ty::ty_str => {
|
||||
// No borrowed content reachable here.
|
||||
}
|
||||
|
||||
impl<'a> TypeFolder for RegionRelator<'a> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
|
||||
self.tcx
|
||||
ty::ty_closure(box ref c) => {
|
||||
self.accumulate_from_closure_ty(ty, c);
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
// An "unboxed closure type" is basically
|
||||
// modeled here as equivalent to a struct like
|
||||
//
|
||||
// struct TheClosure<'b> {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// where the `'b` is the lifetime bound of the
|
||||
// contents (i.e., all contents must outlive 'b).
|
||||
self.push_region_constraint_from_top(region);
|
||||
}
|
||||
|
||||
ty::ty_trait(ref t) => {
|
||||
self.accumulate_from_object_ty(ty, &t.bounds)
|
||||
}
|
||||
|
||||
ty::ty_enum(def_id, ref substs) |
|
||||
ty::ty_struct(def_id, ref substs) => {
|
||||
self.accumulate_from_adt(ty, def_id, substs)
|
||||
}
|
||||
|
||||
ty::ty_vec(t, _) |
|
||||
ty::ty_ptr(ty::mt { ty: t, .. }) |
|
||||
ty::ty_box(t) |
|
||||
ty::ty_uniq(t) => {
|
||||
self.accumulate_from_ty(t)
|
||||
}
|
||||
|
||||
ty::ty_rptr(r_b, mt) => {
|
||||
self.accumulate_from_rptr(ty, r_b, mt.ty);
|
||||
}
|
||||
|
||||
ty::ty_param(p) => {
|
||||
self.push_param_constraint_from_top(p);
|
||||
}
|
||||
|
||||
ty::ty_tup(ref tuptys) => {
|
||||
for &tupty in tuptys.iter() {
|
||||
self.accumulate_from_ty(tupty);
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_infer(_) => {
|
||||
// This should not happen, BUT:
|
||||
//
|
||||
// Currently we uncover region relationships on
|
||||
// entering the fn check. We should do this after
|
||||
// the fn check, then we can call this case a bug().
|
||||
}
|
||||
|
||||
ty::ty_open(_) => {
|
||||
self.tcx.sess.bug(
|
||||
format!("Unexpected type encountered while doing wf check: {}",
|
||||
ty.repr(self.tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_rptr(r, ty::mt {ty, ..}) => {
|
||||
self.relate(r);
|
||||
self.stack.push(r);
|
||||
ty_fold::super_fold_ty(self, ty);
|
||||
fn accumulate_from_rptr(&mut self,
|
||||
ty: ty::t,
|
||||
r_b: ty::Region,
|
||||
ty_b: ty::t) {
|
||||
// We are walking down a type like this, and current
|
||||
// position is indicated by caret:
|
||||
//
|
||||
// &'a &'b ty_b
|
||||
// ^
|
||||
//
|
||||
// At this point, top of stack will be `'a`. We must
|
||||
// require that `'a <= 'b`.
|
||||
|
||||
self.push_region_constraint_from_top(r_b);
|
||||
|
||||
// Now we push `'b` onto the stack, because it must
|
||||
// constrain any borrowed content we find within `T`.
|
||||
|
||||
self.stack.push((r_b, Some(ty)));
|
||||
self.accumulate_from_ty(ty_b);
|
||||
self.stack.pop().unwrap();
|
||||
}
|
||||
|
||||
fn push_region_constraint_from_top(&mut self,
|
||||
r_b: ty::Region) {
|
||||
/*!
|
||||
* Pushes a constraint that `r_b` must outlive the
|
||||
* top region on the stack.
|
||||
*/
|
||||
|
||||
// Indicates that we have found borrowed content with a lifetime
|
||||
// of at least `r_b`. This adds a constraint that `r_b` must
|
||||
// outlive the region `r_a` on top of the stack.
|
||||
//
|
||||
// As an example, imagine walking a type like:
|
||||
//
|
||||
// &'a &'b T
|
||||
// ^
|
||||
//
|
||||
// when we hit the inner pointer (indicated by caret), `'a` will
|
||||
// be on top of stack and `'b` will be the lifetime of the content
|
||||
// we just found. So we add constraint that `'a <= 'b`.
|
||||
|
||||
let &(r_a, opt_ty) = self.stack.last().unwrap();
|
||||
self.push_sub_region_constraint(opt_ty, r_a, r_b);
|
||||
}
|
||||
|
||||
fn push_sub_region_constraint(&mut self,
|
||||
opt_ty: Option<ty::t>,
|
||||
r_a: ty::Region,
|
||||
r_b: ty::Region) {
|
||||
/*! Pushes a constraint that `r_a <= r_b`, due to `opt_ty` */
|
||||
self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
|
||||
}
|
||||
|
||||
fn push_param_constraint_from_top(&mut self,
|
||||
param_ty: ty::ParamTy) {
|
||||
/*!
|
||||
* Pushes a constraint that `param_ty` must outlive the
|
||||
* top region on the stack.
|
||||
*/
|
||||
|
||||
let &(region, opt_ty) = self.stack.last().unwrap();
|
||||
self.push_param_constraint(region, opt_ty, param_ty);
|
||||
}
|
||||
|
||||
fn push_param_constraint(&mut self,
|
||||
region: ty::Region,
|
||||
opt_ty: Option<ty::t>,
|
||||
param_ty: ty::ParamTy) {
|
||||
/*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */
|
||||
self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
|
||||
}
|
||||
|
||||
fn accumulate_from_adt(&mut self,
|
||||
ty: ty::t,
|
||||
def_id: ast::DefId,
|
||||
substs: &Substs)
|
||||
{
|
||||
// The generic declarations from the type, appropriately
|
||||
// substituted for the actual substitutions.
|
||||
let generics =
|
||||
ty::lookup_item_type(self.tcx, def_id)
|
||||
.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().iter() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
for ®ion_bound in region_param_def.bounds.iter() {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
ty::Covariant | ty::Invariant => {
|
||||
self.accumulate_from_ty(type_param_ty);
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect bounds on this type parameter for any
|
||||
// region bounds.
|
||||
for &r in type_param_def.bounds.opt_region_bound.iter() {
|
||||
self.stack.push((r, Some(ty)));
|
||||
self.accumulate_from_ty(type_param_ty);
|
||||
self.stack.pop().unwrap();
|
||||
}
|
||||
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
ty
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
self.relate(r);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RegionRelator<'a> {
|
||||
fn relate(&mut self, r_sub: ty::Region) {
|
||||
for &r in self.stack.iter() {
|
||||
if !r.is_bound() && !r_sub.is_bound() {
|
||||
(self.relate_op)(r, r_sub);
|
||||
}
|
||||
fn accumulate_from_closure_ty(&mut self,
|
||||
ty: ty::t,
|
||||
c: &ty::ClosureTy)
|
||||
{
|
||||
match c.store {
|
||||
ty::RegionTraitStore(r_b, _) => {
|
||||
self.push_region_constraint_from_top(r_b);
|
||||
}
|
||||
ty::UniqTraitStore => { }
|
||||
}
|
||||
|
||||
self.accumulate_from_object_ty(ty, &c.bounds)
|
||||
}
|
||||
|
||||
fn accumulate_from_object_ty(&mut self,
|
||||
ty: ty::t,
|
||||
bounds: &ty::ExistentialBounds)
|
||||
{
|
||||
// Imagine a type like this:
|
||||
//
|
||||
// trait Foo { }
|
||||
// trait Bar<'c> : 'c { }
|
||||
//
|
||||
// &'b (Foo+'c+Bar<'d>)
|
||||
// ^
|
||||
//
|
||||
// In this case, the following relationships must hold:
|
||||
//
|
||||
// 'b <= 'c
|
||||
// 'd <= 'c
|
||||
//
|
||||
// The first conditions is due to the normal region pointer
|
||||
// rules, which say that a reference cannot outlive its
|
||||
// referent.
|
||||
//
|
||||
// The final condition may be a bit surprising. In particular,
|
||||
// you may expect that it would have been `'c <= 'd`, since
|
||||
// usually lifetimes of outer things are conservative
|
||||
// approximations for inner things. However, it works somewhat
|
||||
// differently with trait objects: here the idea is that if the
|
||||
// user specifies a region bound (`'c`, in this case) it is the
|
||||
// "master bound" that *implies* that bounds from other traits are
|
||||
// all met. (Remember that *all bounds* in a type like
|
||||
// `Foo+Bar+Zed` must be met, not just one, hence if we write
|
||||
// `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
|
||||
// 'y.)
|
||||
//
|
||||
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
|
||||
// am looking forward to the future here.
|
||||
|
||||
// The content of this object type must outlive
|
||||
// `bounds.region_bound`:
|
||||
let r_c = bounds.region_bound;
|
||||
self.push_region_constraint_from_top(r_c);
|
||||
|
||||
// And then, in turn, to be well-formed, the
|
||||
// `region_bound` that user specified must imply the
|
||||
// region bounds required from all of the trait types:
|
||||
let required_region_bounds =
|
||||
ty::required_region_bounds(self.tcx,
|
||||
[],
|
||||
bounds.builtin_bounds,
|
||||
[]);
|
||||
for &r_d in required_region_bounds.iter() {
|
||||
// Each of these is an instance of the `'c <= 'b`
|
||||
// constraint above
|
||||
self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn relate_free_regions(tcx: &ty::ctxt, fn_sig: &ty::FnSig) {
|
||||
/*!
|
||||
* This function populates the region map's `free_region_map`.
|
||||
* It walks over the transformed self type and argument types
|
||||
* for each function just before we check the body of that
|
||||
* function, looking for types where you have a borrowed
|
||||
* pointer to other borrowed data (e.g., `&'a &'b [uint]`.
|
||||
* We do not allow references to outlive the things they
|
||||
* point at, so we can assume that `'a <= 'b`.
|
||||
*
|
||||
* Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
|
||||
*/
|
||||
|
||||
debug!("relate_free_regions >>");
|
||||
|
||||
let mut all_tys = Vec::new();
|
||||
for arg in fn_sig.inputs.iter() {
|
||||
all_tys.push(*arg);
|
||||
}
|
||||
|
||||
for &t in all_tys.iter() {
|
||||
debug!("relate_free_regions(t={})", ppaux::ty_to_string(tcx, t));
|
||||
relate_nested_regions(tcx, None, t, |a, b| {
|
||||
match (&a, &b) {
|
||||
(&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
|
||||
tcx.region_maps.relate_free_regions(free_a, free_b);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
debug!("<< relate_free_regions");
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||
let result = type_param_defs.map_rev(|def| {
|
||||
let ty = *substs.types.get(def.space, def.index);
|
||||
lookup_vtables_for_param(vcx, span, Some(substs),
|
||||
&*def.bounds, ty, is_early)
|
||||
&def.bounds, ty, is_early)
|
||||
});
|
||||
|
||||
debug!("lookup_vtables result(\
|
||||
@ -564,7 +564,7 @@ fn fixup_substs(vcx: &VtableContext,
|
||||
// use a dummy type just to package up the substs that need fixing up
|
||||
let t = ty::mk_trait(tcx,
|
||||
id, substs,
|
||||
ty::empty_builtin_bounds());
|
||||
ty::region_existential_bound(ty::ReStatic));
|
||||
fixup_ty(vcx, span, t, is_early).map(|t_f| {
|
||||
match ty::get(t_f).sty {
|
||||
ty::ty_trait(ref inner) => inner.substs.clone(),
|
||||
@ -644,7 +644,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
(&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {}
|
||||
(&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
|
||||
infer::mk_subr(fcx.infcx(),
|
||||
false,
|
||||
infer::RelateObjectBound(ex.span),
|
||||
r_t,
|
||||
r_s);
|
||||
@ -702,9 +701,11 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
opt_region_bound: None,
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: vec!(target_trait_ref)
|
||||
};
|
||||
|
||||
let vtables =
|
||||
lookup_vtables_for_param(&vcx,
|
||||
ex.span,
|
||||
|
@ -42,47 +42,31 @@ use middle::ty::{Polytype};
|
||||
use middle::ty;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::astconv::{AstConv, ty_of_arg};
|
||||
use middle::typeck::astconv::{ast_ty_to_ty};
|
||||
use middle::typeck::astconv::{ast_ty_to_ty, ast_region_to_region};
|
||||
use middle::typeck::astconv;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::rscope::*;
|
||||
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||
use middle::typeck;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux::{Repr,UserString};
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
use std::gc::Gc;
|
||||
|
||||
use syntax::abi;
|
||||
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
|
||||
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap;
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token::{special_idents};
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust::{path_to_string};
|
||||
use syntax::visit;
|
||||
|
||||
struct CollectItemTypesVisitor<'a> {
|
||||
ccx: &'a CrateCtxt<'a>
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
|
||||
fn visit_item(&mut self, i: &ast::Item, _: ()) {
|
||||
convert(self.ccx, i);
|
||||
visit::walk_item(self, i, ());
|
||||
}
|
||||
fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
|
||||
convert_foreign(self.ccx, i);
|
||||
visit::walk_foreign_item(self, i, ());
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Main entry point
|
||||
|
||||
pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
|
||||
fn collect_intrinsic_type(ccx: &CrateCtxt,
|
||||
@ -99,10 +83,57 @@ pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
|
||||
Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
|
||||
}
|
||||
|
||||
let mut visitor = CollectTraitDefVisitor{ ccx: ccx };
|
||||
visit::walk_crate(&mut visitor, krate, ());
|
||||
|
||||
let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
|
||||
visit::walk_crate(&mut visitor, krate, ());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// First phase: just collect *trait definitions* -- basically, the set
|
||||
// of type parameters and supertraits. This is information we need to
|
||||
// know later when parsing field defs.
|
||||
|
||||
struct CollectTraitDefVisitor<'a> {
|
||||
ccx: &'a CrateCtxt<'a>
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<()> for CollectTraitDefVisitor<'a> {
|
||||
fn visit_item(&mut self, i: &ast::Item, _: ()) {
|
||||
match i.node {
|
||||
ast::ItemTrait(..) => {
|
||||
// computing the trait def also fills in the table
|
||||
let _ = trait_def_of_item(self.ccx, i);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
visit::walk_item(self, i, ());
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Second phase: collection proper.
|
||||
|
||||
struct CollectItemTypesVisitor<'a> {
|
||||
ccx: &'a CrateCtxt<'a>
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
|
||||
fn visit_item(&mut self, i: &ast::Item, _: ()) {
|
||||
convert(self.ccx, i);
|
||||
visit::walk_item(self, i, ());
|
||||
}
|
||||
fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
|
||||
convert_foreign(self.ccx, i);
|
||||
visit::walk_foreign_item(self, i, ());
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Utility types and common code for the above passes.
|
||||
|
||||
pub trait ToTy {
|
||||
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
|
||||
}
|
||||
@ -193,9 +224,9 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
trait_id: ast::NodeId,
|
||||
trait_def: &ty::TraitDef) {
|
||||
fn collect_trait_methods(ccx: &CrateCtxt,
|
||||
trait_id: ast::NodeId,
|
||||
trait_def: &ty::TraitDef) {
|
||||
let tcx = ccx.tcx;
|
||||
match tcx.map.get(trait_id) {
|
||||
ast_map::NodeItem(item) => {
|
||||
@ -360,7 +391,13 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
ms: &[Gc<ast::Method>],
|
||||
untransformed_rcvr_ty: ty::t,
|
||||
rcvr_ty_generics: &ty::Generics,
|
||||
rcvr_visibility: ast::Visibility) {
|
||||
rcvr_visibility: ast::Visibility)
|
||||
{
|
||||
debug!("convert_methods(untransformed_rcvr_ty={}, \
|
||||
rcvr_ty_generics={})",
|
||||
untransformed_rcvr_ty.repr(ccx.tcx),
|
||||
rcvr_ty_generics.repr(ccx.tcx));
|
||||
|
||||
let tcx = ccx.tcx;
|
||||
let mut seen_methods = HashSet::new();
|
||||
for m in ms.iter() {
|
||||
@ -388,6 +425,9 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
|
||||
write_ty_to_tcx(tcx, m.id, fty);
|
||||
|
||||
debug!("writing method type: def_id={} mty={}",
|
||||
mty.def_id, mty.repr(ccx.tcx));
|
||||
|
||||
tcx.impl_or_trait_items
|
||||
.borrow_mut()
|
||||
.insert(mty.def_id, ty::MethodTraitItem(mty));
|
||||
@ -448,9 +488,20 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
|
||||
generics: &ast::Generics,
|
||||
thing: &'static str) {
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
if ty_param.bounds.len() > 0 {
|
||||
span_err!(ccx.tcx.sess, span, E0122,
|
||||
"trait bounds are not allowed in {} definitions", thing);
|
||||
for bound in ty_param.bounds.iter() {
|
||||
match *bound {
|
||||
ast::TraitTyParamBound(..) | ast::UnboxedFnTyParamBound(..) => {
|
||||
// According to accepted RFC #XXX, we should
|
||||
// eventually accept these, but it will not be
|
||||
// part of this PR. Still, convert to warning to
|
||||
// make bootstrapping easier.
|
||||
span_warn!(ccx.tcx.sess, span, E0122,
|
||||
"trait bounds are not (yet) enforced \
|
||||
in {} definitions",
|
||||
thing);
|
||||
}
|
||||
ast::RegionTyParamBound(..) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -520,6 +571,10 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
ast::ItemTrait(_, _, _, ref trait_methods) => {
|
||||
let trait_def = trait_def_of_item(ccx, it);
|
||||
|
||||
debug!("trait_def: ident={} trait_def={}",
|
||||
it.ident.repr(ccx.tcx),
|
||||
trait_def.repr(ccx.tcx()));
|
||||
|
||||
for trait_method in trait_methods.iter() {
|
||||
let self_type = ty::mk_param(ccx.tcx,
|
||||
subst::SelfSpace,
|
||||
@ -556,7 +611,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
// We need to do this *after* converting methods, since
|
||||
// convert_methods produces a tcache entry that is wrong for
|
||||
// static trait methods. This is somewhat unfortunate.
|
||||
ensure_trait_methods(ccx, it.id, &*trait_def);
|
||||
collect_trait_methods(ccx, it.id, &*trait_def);
|
||||
},
|
||||
ast::ItemStruct(struct_def, _) => {
|
||||
// Write the class type.
|
||||
@ -739,6 +794,19 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt,
|
||||
unboxed_function: &ast::UnboxedFnTy,
|
||||
param_ty: ty::ParamTy)
|
||||
-> Rc<ty::TraitRef>
|
||||
{
|
||||
let rscope = ExplicitRscope;
|
||||
let param_ty = param_ty.to_ty(ccx.tcx);
|
||||
Rc::new(astconv::trait_ref_for_unboxed_function(ccx,
|
||||
&rscope,
|
||||
unboxed_function,
|
||||
Some(param_ty)))
|
||||
}
|
||||
|
||||
fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
|
||||
if trait_id.krate != ast::LOCAL_CRATE {
|
||||
return ty::lookup_trait_def(ccx.tcx, trait_id)
|
||||
@ -761,9 +829,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let (generics, unbound, supertraits) = match it.node {
|
||||
ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => {
|
||||
(generics, unbound, supertraits)
|
||||
let (generics, unbound, bounds) = match it.node {
|
||||
ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => {
|
||||
(generics, unbound, bounds)
|
||||
}
|
||||
ref s => {
|
||||
tcx.sess.span_bug(
|
||||
@ -779,13 +847,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
|
||||
&substs,
|
||||
generics);
|
||||
|
||||
let builtin_bounds =
|
||||
ensure_supertraits(ccx, it.id, it.span, supertraits, unbound);
|
||||
let self_param_ty = ty::ParamTy::for_self(def_id);
|
||||
|
||||
let bounds = compute_bounds(ccx, token::SELF_KEYWORD_NAME, self_param_ty,
|
||||
bounds.as_slice(), unbound, it.span,
|
||||
&generics.where_clause);
|
||||
|
||||
let substs = mk_item_substs(ccx, &ty_generics);
|
||||
let trait_def = Rc::new(ty::TraitDef {
|
||||
generics: ty_generics,
|
||||
bounds: builtin_bounds,
|
||||
bounds: bounds,
|
||||
trait_ref: Rc::new(ty::TraitRef {
|
||||
def_id: def_id,
|
||||
substs: substs
|
||||
@ -824,55 +895,6 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
|
||||
|
||||
subst::Substs::new_trait(types, regions, self_ty)
|
||||
}
|
||||
|
||||
fn ensure_supertraits(ccx: &CrateCtxt,
|
||||
id: ast::NodeId,
|
||||
sp: codemap::Span,
|
||||
ast_trait_refs: &Vec<ast::TraitRef>,
|
||||
unbound: &Option<ast::TyParamBound>)
|
||||
-> ty::BuiltinBounds
|
||||
{
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
// Called only the first time trait_def_of_item is called.
|
||||
// Supertraits are ensured at the same time.
|
||||
assert!(!tcx.supertraits.borrow().contains_key(&local_def(id)));
|
||||
|
||||
let self_ty = ty::mk_self_type(ccx.tcx, local_def(id));
|
||||
let mut ty_trait_refs: Vec<Rc<ty::TraitRef>> = Vec::new();
|
||||
let mut bounds = ty::empty_builtin_bounds();
|
||||
for ast_trait_ref in ast_trait_refs.iter() {
|
||||
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
|
||||
|
||||
// FIXME(#8559): Need to instantiate the trait_ref whether
|
||||
// or not it's a builtin trait, so that the trait's node
|
||||
// id appears in the tcx trait_ref map. This is only
|
||||
// needed for metadata; see the similar fixme in
|
||||
// encoder.rs.
|
||||
|
||||
let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty);
|
||||
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
|
||||
|
||||
// FIXME(#5527) Could have same trait multiple times
|
||||
if ty_trait_refs.iter().any(
|
||||
|other_trait| other_trait.def_id == trait_ref.def_id)
|
||||
{
|
||||
// This means a trait inherited from the same
|
||||
// supertrait more than once.
|
||||
span_err!(tcx.sess, sp, E0127,
|
||||
"duplicate supertrait in trait declaration");
|
||||
break;
|
||||
} else {
|
||||
ty_trait_refs.push(trait_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_unsized_bound(ccx, unbound, &mut bounds, "trait", sp);
|
||||
tcx.supertraits.borrow_mut().insert(local_def(id),
|
||||
Rc::new(ty_trait_refs));
|
||||
bounds
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
|
||||
@ -984,11 +1006,12 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
|
||||
|
||||
fn ty_generics_for_type(ccx: &CrateCtxt,
|
||||
generics: &ast::Generics)
|
||||
-> ty::Generics {
|
||||
-> ty::Generics
|
||||
{
|
||||
ty_generics(ccx,
|
||||
subst::TypeSpace,
|
||||
&generics.lifetimes,
|
||||
&generics.ty_params,
|
||||
generics.lifetimes.as_slice(),
|
||||
generics.ty_params.as_slice(),
|
||||
ty::Generics::empty(),
|
||||
&generics.where_clause)
|
||||
}
|
||||
@ -1000,8 +1023,8 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
|
||||
-> ty::Generics {
|
||||
let mut generics = ty_generics(ccx,
|
||||
subst::TypeSpace,
|
||||
&generics.lifetimes,
|
||||
&generics.ty_params,
|
||||
generics.lifetimes.as_slice(),
|
||||
generics.ty_params.as_slice(),
|
||||
ty::Generics::empty(),
|
||||
&generics.where_clause);
|
||||
|
||||
@ -1018,10 +1041,11 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
|
||||
index: 0,
|
||||
ident: special_idents::type_self,
|
||||
def_id: local_def(param_id),
|
||||
bounds: Rc::new(ty::ParamBounds {
|
||||
bounds: ty::ParamBounds {
|
||||
opt_region_bound: None,
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: vec!(self_trait_ref),
|
||||
}),
|
||||
},
|
||||
default: None
|
||||
};
|
||||
|
||||
@ -1039,8 +1063,8 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
|
||||
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
||||
ty_generics(ccx,
|
||||
subst::FnSpace,
|
||||
&early_lifetimes,
|
||||
&generics.ty_params,
|
||||
early_lifetimes.as_slice(),
|
||||
generics.ty_params.as_slice(),
|
||||
base_generics,
|
||||
&generics.where_clause)
|
||||
}
|
||||
@ -1053,7 +1077,7 @@ fn add_unsized_bound(ccx: &CrateCtxt,
|
||||
span: Span) {
|
||||
let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
|
||||
match unbound {
|
||||
&Some(TraitTyParamBound(ref tpb)) => {
|
||||
&Some(ast::TraitTyParamBound(ref tpb)) => {
|
||||
// #FIXME(8559) currently requires the unbound to be built-in.
|
||||
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
|
||||
match kind_id {
|
||||
@ -1084,18 +1108,23 @@ fn add_unsized_bound(ccx: &CrateCtxt,
|
||||
|
||||
fn ty_generics(ccx: &CrateCtxt,
|
||||
space: subst::ParamSpace,
|
||||
lifetimes: &Vec<ast::LifetimeDef>,
|
||||
types: &OwnedSlice<ast::TyParam>,
|
||||
lifetime_defs: &[ast::LifetimeDef],
|
||||
types: &[ast::TyParam],
|
||||
base_generics: ty::Generics,
|
||||
where_clause: &ast::WhereClause)
|
||||
-> ty::Generics {
|
||||
-> ty::Generics
|
||||
{
|
||||
let mut result = base_generics;
|
||||
|
||||
for (i, l) in lifetimes.iter().enumerate() {
|
||||
for (i, l) in lifetime_defs.iter().enumerate() {
|
||||
let bounds = l.bounds.iter()
|
||||
.map(|l| ast_region_to_region(ccx.tcx, l))
|
||||
.collect();
|
||||
let def = ty::RegionParameterDef { name: l.lifetime.name,
|
||||
space: space,
|
||||
index: i,
|
||||
def_id: local_def(l.lifetime.id) };
|
||||
def_id: local_def(l.lifetime.id),
|
||||
bounds: bounds };
|
||||
debug!("ty_generics: def for region param: {}", def);
|
||||
result.regions.push(space, def);
|
||||
}
|
||||
@ -1123,19 +1152,17 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||
None => { }
|
||||
}
|
||||
|
||||
let param_ty = ty::ParamTy {space: space,
|
||||
idx: index,
|
||||
def_id: local_def(param.id)};
|
||||
let bounds = Rc::new(compute_bounds(ccx,
|
||||
param_ty,
|
||||
¶m.bounds,
|
||||
¶m.unbound,
|
||||
param.ident,
|
||||
param.span,
|
||||
where_clause));
|
||||
let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
|
||||
let bounds = compute_bounds(ccx,
|
||||
param.ident.name,
|
||||
param_ty,
|
||||
param.bounds.as_slice(),
|
||||
¶m.unbound,
|
||||
param.span,
|
||||
where_clause);
|
||||
let default = param.default.map(|path| {
|
||||
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
|
||||
let cur_idx = param_ty.idx;
|
||||
let cur_idx = index;
|
||||
|
||||
ty::walk_ty(ty, |t| {
|
||||
match ty::get(t).sty {
|
||||
@ -1164,130 +1191,139 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||
|
||||
def
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_bounds(ccx: &CrateCtxt,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bounds: &OwnedSlice<ast::TyParamBound>,
|
||||
unbound: &Option<ast::TyParamBound>,
|
||||
ident: ast::Ident,
|
||||
span: Span,
|
||||
where_clause: &ast::WhereClause)
|
||||
-> ty::ParamBounds {
|
||||
/*!
|
||||
* Translate the AST's notion of ty param bounds (which are an
|
||||
* enum consisting of a newtyped Ty or a region) to ty's
|
||||
* notion of ty param bounds, which can either be user-defined
|
||||
* traits, or the built-in trait (formerly known as kind): Send.
|
||||
*/
|
||||
fn compute_bounds(
|
||||
ccx: &CrateCtxt,
|
||||
name_of_bounded_thing: ast::Name,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bounds: &[ast::TyParamBound],
|
||||
unbound: &Option<ast::TyParamBound>,
|
||||
span: Span,
|
||||
where_clause: &ast::WhereClause)
|
||||
-> ty::ParamBounds
|
||||
{
|
||||
/*!
|
||||
* Translate the AST's notion of ty param bounds (which are an
|
||||
* enum consisting of a newtyped Ty or a region) to ty's
|
||||
* notion of ty param bounds, which can either be user-defined
|
||||
* traits, or the built-in trait (formerly known as kind): Send.
|
||||
*/
|
||||
|
||||
let mut param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: Vec::new()
|
||||
};
|
||||
for ast_bound in ast_bounds.iter() {
|
||||
compute_bound(ccx, &mut param_bounds, param_ty, ast_bound);
|
||||
}
|
||||
for predicate in where_clause.predicates.iter() {
|
||||
let predicate_param_id = ccx.tcx
|
||||
.def_map
|
||||
.borrow()
|
||||
.find(&predicate.id)
|
||||
.expect("compute_bounds(): resolve \
|
||||
didn't resolve the type \
|
||||
parameter identifier in a \
|
||||
`where` clause")
|
||||
.def_id();
|
||||
if param_ty.def_id != predicate_param_id {
|
||||
continue
|
||||
}
|
||||
for bound in predicate.bounds.iter() {
|
||||
compute_bound(ccx, &mut param_bounds, param_ty, bound);
|
||||
}
|
||||
}
|
||||
let mut param_bounds = conv_param_bounds(ccx,
|
||||
span,
|
||||
param_ty,
|
||||
ast_bounds,
|
||||
where_clause);
|
||||
|
||||
add_unsized_bound(ccx,
|
||||
unbound,
|
||||
&mut param_bounds.builtin_bounds,
|
||||
"type parameter",
|
||||
span);
|
||||
|
||||
check_bounds_compatible(ccx.tcx, ¶m_bounds, ident, span);
|
||||
add_unsized_bound(ccx,
|
||||
unbound,
|
||||
&mut param_bounds.builtin_bounds,
|
||||
"type parameter",
|
||||
span);
|
||||
|
||||
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
|
||||
check_bounds_compatible(ccx.tcx, name_of_bounded_thing,
|
||||
¶m_bounds, span);
|
||||
|
||||
param_bounds
|
||||
}
|
||||
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
|
||||
|
||||
/// Translates the AST's notion of a type parameter bound to
|
||||
/// typechecking's notion of the same, and pushes the resulting bound onto
|
||||
/// the appropriate section of `param_bounds`.
|
||||
fn compute_bound(ccx: &CrateCtxt,
|
||||
param_bounds: &mut ty::ParamBounds,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bound: &ast::TyParamBound) {
|
||||
match *ast_bound {
|
||||
TraitTyParamBound(ref b) => {
|
||||
let ty = ty::mk_param(ccx.tcx, param_ty.space,
|
||||
param_ty.idx, param_ty.def_id);
|
||||
let trait_ref = instantiate_trait_ref(ccx, b, ty);
|
||||
if !ty::try_add_builtin_trait(
|
||||
ccx.tcx, trait_ref.def_id,
|
||||
&mut param_bounds.builtin_bounds) {
|
||||
// Must be a user-defined trait
|
||||
param_bounds.trait_bounds.push(trait_ref);
|
||||
}
|
||||
}
|
||||
param_bounds
|
||||
}
|
||||
|
||||
StaticRegionTyParamBound => {
|
||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
|
||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||
let rscope = ExplicitRscope;
|
||||
let self_ty = ty::mk_param(ccx.tcx,
|
||||
param_ty.space,
|
||||
param_ty.idx,
|
||||
param_ty.def_id);
|
||||
let trait_ref =
|
||||
astconv::trait_ref_for_unboxed_function(ccx,
|
||||
&rscope,
|
||||
unboxed_function,
|
||||
Some(self_ty));
|
||||
param_bounds.trait_bounds.push(Rc::new(trait_ref));
|
||||
}
|
||||
|
||||
OtherRegionTyParamBound(span) => {
|
||||
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
|
||||
ccx.tcx.sess.span_err(
|
||||
span,
|
||||
"only the 'static lifetime is accepted here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_bounds_compatible(tcx: &ty::ctxt,
|
||||
param_bounds: &ty::ParamBounds,
|
||||
ident: ast::Ident,
|
||||
span: Span) {
|
||||
// Currently the only bound which is incompatible with other bounds is
|
||||
// Sized/Unsized.
|
||||
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
|
||||
ty::each_bound_trait_and_supertraits(tcx,
|
||||
param_bounds.trait_bounds.as_slice(),
|
||||
|trait_ref| {
|
||||
fn check_bounds_compatible(tcx: &ty::ctxt,
|
||||
name_of_bounded_thing: ast::Name,
|
||||
param_bounds: &ty::ParamBounds,
|
||||
span: Span) {
|
||||
// Currently the only bound which is incompatible with other bounds is
|
||||
// Sized/Unsized.
|
||||
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
|
||||
ty::each_bound_trait_and_supertraits(
|
||||
tcx,
|
||||
param_bounds.trait_bounds.as_slice(),
|
||||
|trait_ref| {
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
|
||||
if trait_def.bounds.contains_elem(ty::BoundSized) {
|
||||
if trait_def.bounds.builtin_bounds.contains_elem(ty::BoundSized) {
|
||||
span_err!(tcx.sess, span, E0129,
|
||||
"incompatible bounds on type parameter {}, \
|
||||
bound {} does not allow unsized type",
|
||||
token::get_ident(ident),
|
||||
"incompatible bounds on type parameter `{}`, \
|
||||
bound `{}` does not allow unsized type",
|
||||
name_of_bounded_thing.user_string(tcx),
|
||||
ppaux::trait_ref_to_string(tcx, &*trait_ref));
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_param_bounds(ccx: &CrateCtxt,
|
||||
span: Span,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bounds: &[ast::TyParamBound],
|
||||
where_clause: &ast::WhereClause)
|
||||
-> ty::ParamBounds
|
||||
{
|
||||
let all_bounds =
|
||||
merge_param_bounds(ccx, param_ty, ast_bounds, where_clause);
|
||||
let astconv::PartitionedBounds { builtin_bounds,
|
||||
trait_bounds,
|
||||
region_bounds,
|
||||
unboxed_fn_ty_bounds } =
|
||||
astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice());
|
||||
let unboxed_fn_ty_bounds =
|
||||
unboxed_fn_ty_bounds.move_iter()
|
||||
.map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty));
|
||||
let trait_bounds: Vec<Rc<ty::TraitRef>> =
|
||||
trait_bounds.move_iter()
|
||||
.map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
|
||||
.chain(unboxed_fn_ty_bounds)
|
||||
.collect();
|
||||
let opt_region_bound =
|
||||
astconv::compute_opt_region_bound(
|
||||
ccx.tcx, span, builtin_bounds, region_bounds.as_slice(),
|
||||
trait_bounds.as_slice());
|
||||
ty::ParamBounds {
|
||||
opt_region_bound: opt_region_bound,
|
||||
builtin_bounds: builtin_bounds,
|
||||
trait_bounds: trait_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_param_bounds<'a>(ccx: &CrateCtxt,
|
||||
param_ty: ty::ParamTy,
|
||||
ast_bounds: &'a [ast::TyParamBound],
|
||||
where_clause: &'a ast::WhereClause)
|
||||
-> Vec<&'a ast::TyParamBound>
|
||||
{
|
||||
/*!
|
||||
* Merges the bounds declared on a type parameter with those
|
||||
* found from where clauses into a single list.
|
||||
*/
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
||||
for ast_bound in ast_bounds.iter() {
|
||||
result.push(ast_bound);
|
||||
}
|
||||
|
||||
for predicate in where_clause.predicates.iter() {
|
||||
let predicate_param_id = ccx.tcx
|
||||
.def_map
|
||||
.borrow()
|
||||
.find(&predicate.id)
|
||||
.expect("compute_bounds(): resolve \
|
||||
didn't resolve the type \
|
||||
parameter identifier in a \
|
||||
`where` clause")
|
||||
.def_id();
|
||||
if param_ty.def_id != predicate_param_id {
|
||||
continue
|
||||
}
|
||||
for bound in predicate.bounds.iter() {
|
||||
result.push(bound);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
|
||||
|
@ -221,7 +221,7 @@ pub trait Combine {
|
||||
};
|
||||
let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
|
||||
let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
|
||||
let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
|
||||
let bounds = if_ok!(self.existential_bounds(a.bounds, b.bounds));
|
||||
let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
|
||||
let abi = if_ok!(self.abi(a.abi, b.abi));
|
||||
Ok(ty::ClosureTy {
|
||||
@ -251,9 +251,26 @@ pub trait Combine {
|
||||
}
|
||||
|
||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>;
|
||||
|
||||
fn existential_bounds(&self,
|
||||
a: ty::ExistentialBounds,
|
||||
b: ty::ExistentialBounds)
|
||||
-> cres<ty::ExistentialBounds>
|
||||
{
|
||||
let r = try!(self.contraregions(a.region_bound, b.region_bound));
|
||||
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
|
||||
Ok(ty::ExistentialBounds { region_bound: r,
|
||||
builtin_bounds: nb })
|
||||
}
|
||||
|
||||
fn builtin_bounds(&self,
|
||||
a: ty::BuiltinBounds,
|
||||
b: ty::BuiltinBounds)
|
||||
-> cres<ty::BuiltinBounds>;
|
||||
|
||||
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||
-> cres<ty::Region>;
|
||||
|
||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
|
||||
|
||||
fn trait_stores(&self,
|
||||
@ -479,7 +496,7 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||
if a_.def_id == b_.def_id => {
|
||||
debug!("Trying to match traits {:?} and {:?}", a, b);
|
||||
let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
|
||||
let bounds = if_ok!(this.bounds(a_.bounds, b_.bounds));
|
||||
let bounds = if_ok!(this.existential_bounds(a_.bounds, b_.bounds));
|
||||
Ok(ty::mk_trait(tcx,
|
||||
a_.def_id,
|
||||
substs.clone(),
|
||||
|
@ -75,6 +75,7 @@ use middle::typeck::infer::region_inference::RegionResolutionError;
|
||||
use middle::typeck::infer::region_inference::ConcreteFailure;
|
||||
use middle::typeck::infer::region_inference::SubSupConflict;
|
||||
use middle::typeck::infer::region_inference::SupSupConflict;
|
||||
use middle::typeck::infer::region_inference::ParamBoundFailure;
|
||||
use middle::typeck::infer::region_inference::ProcessedErrors;
|
||||
use middle::typeck::infer::region_inference::SameRegions;
|
||||
use std::cell::{Cell, RefCell};
|
||||
@ -89,10 +90,13 @@ use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::codemap;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
use util::ppaux::UserString;
|
||||
use util::ppaux::bound_region_to_string;
|
||||
use util::ppaux::note_and_explain_region;
|
||||
|
||||
// Note: only import UserString, not Repr, since user-facing error
|
||||
// messages shouldn't include debug serializations.
|
||||
use util::ppaux::UserString;
|
||||
|
||||
pub trait ErrorReporting {
|
||||
fn report_region_errors(&self,
|
||||
errors: &Vec<RegionResolutionError>);
|
||||
@ -118,6 +122,12 @@ pub trait ErrorReporting {
|
||||
sub: Region,
|
||||
sup: Region);
|
||||
|
||||
fn report_param_bound_failure(&self,
|
||||
origin: SubregionOrigin,
|
||||
param_ty: ty::ParamTy,
|
||||
sub: Region,
|
||||
sups: Vec<Region>);
|
||||
|
||||
fn report_sub_sup_conflict(&self,
|
||||
var_origin: RegionVariableOrigin,
|
||||
sub_origin: SubregionOrigin,
|
||||
@ -145,7 +155,7 @@ trait ErrorReportingHelpers {
|
||||
var_origin: RegionVariableOrigin);
|
||||
|
||||
fn note_region_origin(&self,
|
||||
origin: SubregionOrigin);
|
||||
origin: &SubregionOrigin);
|
||||
|
||||
fn give_expl_lifetime_param(&self,
|
||||
decl: &ast::FnDecl,
|
||||
@ -167,6 +177,10 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
self.report_concrete_failure(origin, sub, sup);
|
||||
}
|
||||
|
||||
ParamBoundFailure(origin, param_ty, sub, sups) => {
|
||||
self.report_param_bound_failure(origin, param_ty, sub, sups);
|
||||
}
|
||||
|
||||
SubSupConflict(var_origin,
|
||||
sub_origin, sub_r,
|
||||
sup_origin, sup_r) => {
|
||||
@ -410,6 +424,62 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
found.user_string(self.tcx)))
|
||||
}
|
||||
|
||||
fn report_param_bound_failure(&self,
|
||||
origin: SubregionOrigin,
|
||||
param_ty: ty::ParamTy,
|
||||
sub: Region,
|
||||
_sups: Vec<Region>) {
|
||||
|
||||
// FIXME: it would be better to report the first error message
|
||||
// with the span of the parameter itself, rather than the span
|
||||
// where the error was detected. But that span is not readily
|
||||
// accessible.
|
||||
|
||||
match sub {
|
||||
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
||||
// Does the required lifetime have a nice name we can print?
|
||||
self.tcx.sess.span_err(
|
||||
origin.span(),
|
||||
format!(
|
||||
"the parameter type `{}` may not live long enough; \
|
||||
consider adding an explicit lifetime bound `{}:{}`...",
|
||||
param_ty.user_string(self.tcx),
|
||||
param_ty.user_string(self.tcx),
|
||||
sub.user_string(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
ty::ReStatic => {
|
||||
// Does the required lifetime have a nice name we can print?
|
||||
self.tcx.sess.span_err(
|
||||
origin.span(),
|
||||
format!(
|
||||
"the parameter type `{}` may not live long enough; \
|
||||
consider adding an explicit lifetime bound `{}:'static`...",
|
||||
param_ty.user_string(self.tcx),
|
||||
param_ty.user_string(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
_ => {
|
||||
// If not, be less specific.
|
||||
self.tcx.sess.span_err(
|
||||
origin.span(),
|
||||
format!(
|
||||
"the parameter type `{}` may not live long enough; \
|
||||
consider adding an explicit lifetime bound to `{}`",
|
||||
param_ty.user_string(self.tcx),
|
||||
param_ty.user_string(self.tcx)).as_slice());
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
format!("the parameter type `{}` must be valid for ",
|
||||
param_ty.user_string(self.tcx)).as_slice(),
|
||||
sub,
|
||||
"...");
|
||||
}
|
||||
}
|
||||
|
||||
self.note_region_origin(&origin);
|
||||
}
|
||||
|
||||
fn report_concrete_failure(&self,
|
||||
origin: SubregionOrigin,
|
||||
sub: Region,
|
||||
@ -538,6 +608,67 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::RelateProcBound(span, var_node_id, ty) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!(
|
||||
"the type `{}` of captured variable `{}` \
|
||||
outlives the `proc()` it \
|
||||
is captured in",
|
||||
self.ty_to_string(ty),
|
||||
ty::local_var_name_str(self.tcx,
|
||||
var_node_id)).as_slice());
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"`proc()` is valid for ",
|
||||
sub,
|
||||
"");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
format!("the type `{}` is only valid for ",
|
||||
self.ty_to_string(ty)).as_slice(),
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::RelateParamBound(span, param_ty, ty) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("the type `{}` (provided as the value of \
|
||||
the parameter `{}`) does not fulfill the \
|
||||
required lifetime",
|
||||
self.ty_to_string(ty),
|
||||
param_ty.user_string(self.tcx)).as_slice());
|
||||
note_and_explain_region(self.tcx,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
"");
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"declared lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"lifetime parameter instantiated with ",
|
||||
sup,
|
||||
"");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"but lifetime parameter must outlive ",
|
||||
sub,
|
||||
"");
|
||||
}
|
||||
infer::RelateDefaultParamBound(span, ty) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("the type `{}` (provided as the value of \
|
||||
a type parameter) is not valid at this point",
|
||||
self.ty_to_string(ty)).as_slice());
|
||||
note_and_explain_region(self.tcx,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
"");
|
||||
}
|
||||
infer::CallRcvr(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
@ -593,6 +724,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::ExprTypeIsNotInScope(t, span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("type of expression contains references \
|
||||
that are not valid during the expression: `{}`",
|
||||
self.ty_to_string(t)).as_slice());
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"type is only valid for ",
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
@ -606,9 +749,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("in type `{}`, pointer has a longer lifetime than \
|
||||
the data it references",
|
||||
ty.user_string(self.tcx)).as_slice());
|
||||
format!("in type `{}`, reference has a longer lifetime \
|
||||
than the data it references",
|
||||
self.ty_to_string(ty)).as_slice());
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"the pointer is valid for ",
|
||||
@ -620,6 +763,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::Managed(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("cannot put borrowed references into managed memory").as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,7 +785,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
sup_region,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(sup_origin);
|
||||
self.note_region_origin(&sup_origin);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -645,7 +793,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
sub_region,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(sub_origin);
|
||||
self.note_region_origin(&sub_origin);
|
||||
}
|
||||
|
||||
fn report_sup_sup_conflict(&self,
|
||||
@ -662,7 +810,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
region1,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(origin1);
|
||||
self.note_region_origin(&origin1);
|
||||
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
@ -670,7 +818,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||
region2,
|
||||
"...");
|
||||
|
||||
self.note_region_origin(origin2);
|
||||
self.note_region_origin(&origin2);
|
||||
}
|
||||
|
||||
fn report_processed_errors(&self,
|
||||
@ -920,8 +1068,12 @@ impl<'a> Rebuilder<'a> {
|
||||
-> OwnedSlice<ast::TyParamBound> {
|
||||
ty_param_bounds.map(|tpb| {
|
||||
match tpb {
|
||||
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
|
||||
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
|
||||
&ast::RegionTyParamBound(lt) => {
|
||||
// FIXME -- it's unclear whether I'm supposed to
|
||||
// substitute lifetime here. I suspect we need to
|
||||
// be passing down a map.
|
||||
ast::RegionTyParamBound(lt)
|
||||
}
|
||||
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
|
||||
ast::UnboxedFnTyParamBound(unboxed_function_type)
|
||||
}
|
||||
@ -1291,8 +1443,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||
var_description).as_slice());
|
||||
}
|
||||
|
||||
fn note_region_origin(&self, origin: SubregionOrigin) {
|
||||
match origin {
|
||||
fn note_region_origin(&self, origin: &SubregionOrigin) {
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => {
|
||||
let desc = match trace.origin {
|
||||
infer::Misc(_) => {
|
||||
@ -1384,8 +1536,16 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||
infer::RelateObjectBound(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that source pointer does not outlive \
|
||||
lifetime bound of the object type");
|
||||
"...so that it can be closed over into an object");
|
||||
}
|
||||
infer::RelateProcBound(span, var_node_id, _ty) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!(
|
||||
"...so that the variable `{}` can be captured \
|
||||
into a proc",
|
||||
ty::local_var_name_str(self.tcx,
|
||||
var_node_id)).as_slice());
|
||||
}
|
||||
infer::CallRcvr(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
@ -1414,16 +1574,52 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||
"...so that reference is valid \
|
||||
at the time of implicit borrow");
|
||||
}
|
||||
infer::ExprTypeIsNotInScope(t, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!("...so type `{}` of expression is valid during the \
|
||||
expression",
|
||||
self.ty_to_string(t)).as_slice());
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that variable is valid at time of its declaration");
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(_, span) => {
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that the pointer does not outlive the \
|
||||
data it points at");
|
||||
format!("...so that the reference type `{}` \
|
||||
does not outlive the data it points at",
|
||||
self.ty_to_string(ty)).as_slice());
|
||||
}
|
||||
infer::Managed(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that the value can be stored in managed memory.");
|
||||
}
|
||||
infer::RelateParamBound(span, param_ty, t) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!("...so that the parameter `{}`, \
|
||||
when instantiated with `{}`, \
|
||||
will meet its declared lifetime bounds.",
|
||||
param_ty.user_string(self.tcx),
|
||||
self.ty_to_string(t)).as_slice());
|
||||
}
|
||||
infer::RelateDefaultParamBound(span, t) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!("...so that type parameter \
|
||||
instantiated with `{}`, \
|
||||
will meet its declared lifetime bounds.",
|
||||
self.ty_to_string(t)).as_slice());
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!("...so that the declared lifetime parameter bounds \
|
||||
are satisfied").as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,10 @@ impl<'f> Combine for Glb<'f> {
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
fn builtin_bounds(&self,
|
||||
a: ty::BuiltinBounds,
|
||||
b: ty::BuiltinBounds)
|
||||
-> cres<ty::BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds, so
|
||||
// the GLB (mutual subtype) is the union.
|
||||
Ok(a.union(b))
|
||||
|
@ -90,7 +90,10 @@ impl<'f> Combine for Lub<'f> {
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
fn builtin_bounds(&self,
|
||||
a: ty::BuiltinBounds,
|
||||
b: ty::BuiltinBounds)
|
||||
-> cres<ty::BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds, so
|
||||
// the LUB (mutual supertype) is the intersection.
|
||||
Ok(a.intersection(b))
|
||||
|
@ -168,6 +168,22 @@ pub enum SubregionOrigin {
|
||||
// relating `'a` to `'b`
|
||||
RelateObjectBound(Span),
|
||||
|
||||
// When closing over a variable in a closure/proc, ensure that the
|
||||
// type of the variable outlives the lifetime bound.
|
||||
RelateProcBound(Span, ast::NodeId, ty::t),
|
||||
|
||||
// The given type parameter was instantiated with the given type,
|
||||
// and that type must outlive some region.
|
||||
RelateParamBound(Span, ty::ParamTy, ty::t),
|
||||
|
||||
// The given region parameter was instantiated with a region
|
||||
// that must outlive some other region.
|
||||
RelateRegionParamBound(Span),
|
||||
|
||||
// A bound placed on type parameters that states that must outlive
|
||||
// the moment of their instantiation.
|
||||
RelateDefaultParamBound(Span, ty::t),
|
||||
|
||||
// Creating a pointer `b` to contents of another reference
|
||||
Reborrow(Span),
|
||||
|
||||
@ -177,6 +193,9 @@ pub enum SubregionOrigin {
|
||||
// (&'a &'b T) where a >= b
|
||||
ReferenceOutlivesReferent(ty::t, Span),
|
||||
|
||||
// The type T of an expression E must outlive the lifetime for E.
|
||||
ExprTypeIsNotInScope(ty::t, Span),
|
||||
|
||||
// A `ref b` whose region does not enclose the decl site
|
||||
BindingTypeIsNotValidAtDecl(Span),
|
||||
|
||||
@ -194,6 +213,9 @@ pub enum SubregionOrigin {
|
||||
|
||||
// An auto-borrow that does not enclose the expr where it occurs
|
||||
AutoBorrow(Span),
|
||||
|
||||
// Managed data cannot contain borrowed pointers.
|
||||
Managed(Span),
|
||||
}
|
||||
|
||||
/// Reasons to create a region inference variable
|
||||
@ -336,7 +358,6 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures {
|
||||
}
|
||||
|
||||
pub fn mk_subr(cx: &InferCtxt,
|
||||
_a_is_expected: bool,
|
||||
origin: SubregionOrigin,
|
||||
a: ty::Region,
|
||||
b: ty::Region) {
|
||||
@ -346,6 +367,18 @@ pub fn mk_subr(cx: &InferCtxt,
|
||||
cx.region_vars.commit(snapshot);
|
||||
}
|
||||
|
||||
pub fn verify_param_bound(cx: &InferCtxt,
|
||||
origin: SubregionOrigin,
|
||||
param_ty: ty::ParamTy,
|
||||
a: ty::Region,
|
||||
bs: Vec<ty::Region>) {
|
||||
debug!("verify_param_bound({}, {} <: {})",
|
||||
param_ty.repr(cx.tcx),
|
||||
a.repr(cx.tcx),
|
||||
bs.repr(cx.tcx));
|
||||
|
||||
cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
|
||||
}
|
||||
pub fn mk_eqty(cx: &InferCtxt,
|
||||
a_is_expected: bool,
|
||||
origin: TypeOrigin,
|
||||
@ -589,6 +622,13 @@ impl<'a> InferCtxt<'a> {
|
||||
self.rollback_to(snapshot);
|
||||
r
|
||||
}
|
||||
|
||||
pub fn add_given(&self,
|
||||
sub: ty::FreeRegion,
|
||||
sup: ty::RegionVid)
|
||||
{
|
||||
self.region_vars.add_given(sub, sup);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> InferCtxt<'a> {
|
||||
@ -687,14 +727,13 @@ impl<'a> InferCtxt<'a> {
|
||||
}
|
||||
|
||||
pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
|
||||
trait_ref:
|
||||
&ty::TraitRef)
|
||||
trait_ref: &ty::TraitRef)
|
||||
-> ty::TraitRef {
|
||||
// make up a dummy type just to reuse/abuse the resolve machinery
|
||||
let dummy0 = ty::mk_trait(self.tcx,
|
||||
trait_ref.def_id,
|
||||
trait_ref.substs.clone(),
|
||||
ty::empty_builtin_bounds());
|
||||
ty::region_existential_bound(ty::ReStatic));
|
||||
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
|
||||
match ty::get(dummy1).sty {
|
||||
ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
|
||||
@ -896,15 +935,21 @@ impl SubregionOrigin {
|
||||
FreeVariable(a, _) => a,
|
||||
IndexSlice(a) => a,
|
||||
RelateObjectBound(a) => a,
|
||||
RelateProcBound(a, _, _) => a,
|
||||
RelateParamBound(a, _, _) => a,
|
||||
RelateRegionParamBound(a) => a,
|
||||
RelateDefaultParamBound(a, _) => a,
|
||||
Reborrow(a) => a,
|
||||
ReborrowUpvar(a, _) => a,
|
||||
ReferenceOutlivesReferent(_, a) => a,
|
||||
ExprTypeIsNotInScope(_, a) => a,
|
||||
BindingTypeIsNotValidAtDecl(a) => a,
|
||||
CallRcvr(a) => a,
|
||||
CallArg(a) => a,
|
||||
CallReturn(a) => a,
|
||||
AddrOf(a) => a,
|
||||
AutoBorrow(a) => a,
|
||||
Managed(a) => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -933,6 +978,27 @@ impl Repr for SubregionOrigin {
|
||||
RelateObjectBound(a) => {
|
||||
format!("RelateObjectBound({})", a.repr(tcx))
|
||||
}
|
||||
RelateProcBound(a, b, c) => {
|
||||
format!("RelateProcBound({},{},{})",
|
||||
a.repr(tcx),
|
||||
b,
|
||||
c.repr(tcx))
|
||||
}
|
||||
RelateParamBound(a, b, c) => {
|
||||
format!("RelateParamBound({},{},{})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx),
|
||||
c.repr(tcx))
|
||||
}
|
||||
RelateRegionParamBound(a) => {
|
||||
format!("RelateRegionParamBound({})",
|
||||
a.repr(tcx))
|
||||
}
|
||||
RelateDefaultParamBound(a, b) => {
|
||||
format!("RelateDefaultParamBound({},{})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx))
|
||||
}
|
||||
Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
|
||||
ReborrowUpvar(a, b) => {
|
||||
format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
|
||||
@ -940,6 +1006,11 @@ impl Repr for SubregionOrigin {
|
||||
ReferenceOutlivesReferent(_, a) => {
|
||||
format!("ReferenceOutlivesReferent({})", a.repr(tcx))
|
||||
}
|
||||
ExprTypeIsNotInScope(a, b) => {
|
||||
format!("ExprTypeIsNotInScope({}, {})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx))
|
||||
}
|
||||
BindingTypeIsNotValidAtDecl(a) => {
|
||||
format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
|
||||
}
|
||||
@ -948,6 +1019,7 @@ impl Repr for SubregionOrigin {
|
||||
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
||||
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
||||
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
|
||||
Managed(a) => format!("Managed({})", a.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,12 +30,32 @@ use syntax::ast;
|
||||
|
||||
mod doc;
|
||||
|
||||
// A constraint that influences the inference process.
|
||||
#[deriving(PartialEq, Eq, Hash)]
|
||||
pub enum Constraint {
|
||||
// One region variable is subregion of another
|
||||
ConstrainVarSubVar(RegionVid, RegionVid),
|
||||
|
||||
// Concrete region is subregion of region variable
|
||||
ConstrainRegSubVar(Region, RegionVid),
|
||||
|
||||
// Region variable is subregion of concrete region
|
||||
ConstrainVarSubReg(RegionVid, Region),
|
||||
ConstrainRegSubReg(Region, Region),
|
||||
}
|
||||
|
||||
// Something we have to verify after region inference is done, but
|
||||
// which does not directly influence the inference process
|
||||
pub enum Verify {
|
||||
// VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor
|
||||
// `b` are inference variables.
|
||||
VerifyRegSubReg(SubregionOrigin, Region, Region),
|
||||
|
||||
// VerifyParamBound(T, _, R, RS): The parameter type `T` must
|
||||
// outlive the region `R`. `T` is known to outlive `RS`. Therefore
|
||||
// verify that `R <= RS[i]` for some `i`. Inference variables may
|
||||
// be involved (but this verification step doesn't influence
|
||||
// inference).
|
||||
VerifyParamBound(ty::ParamTy, SubregionOrigin, Region, Vec<Region>),
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, Eq, Hash)]
|
||||
@ -51,6 +71,8 @@ pub enum UndoLogEntry {
|
||||
Mark,
|
||||
AddVar(RegionVid),
|
||||
AddConstraint(Constraint),
|
||||
AddVerify(uint),
|
||||
AddGiven(ty::FreeRegion, ty::RegionVid),
|
||||
AddCombination(CombineMapType, TwoRegions)
|
||||
}
|
||||
|
||||
@ -66,6 +88,13 @@ pub enum RegionResolutionError {
|
||||
/// `o` requires that `a <= b`, but this does not hold
|
||||
ConcreteFailure(SubregionOrigin, Region, Region),
|
||||
|
||||
/// `ParamBoundFailure(p, s, a, bs)
|
||||
///
|
||||
/// The parameter type `p` must be known to outlive the lifetime
|
||||
/// `a`, but it is only known to outlive `bs` (and none of the
|
||||
/// regions in `bs` outlive `a`).
|
||||
ParamBoundFailure(SubregionOrigin, ty::ParamTy, Region, Vec<Region>),
|
||||
|
||||
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
|
||||
///
|
||||
/// Could not infer a value for `v` because `sub_r <= v` (due to
|
||||
@ -125,7 +154,38 @@ pub type CombineMap = HashMap<TwoRegions, RegionVid>;
|
||||
pub struct RegionVarBindings<'a> {
|
||||
tcx: &'a ty::ctxt,
|
||||
var_origins: RefCell<Vec<RegionVariableOrigin>>,
|
||||
|
||||
// Constraints of the form `A <= B` introduced by the region
|
||||
// checker. Here at least one of `A` and `B` must be a region
|
||||
// variable.
|
||||
constraints: RefCell<HashMap<Constraint, SubregionOrigin>>,
|
||||
|
||||
// A "verify" is something that we need to verify after inference is
|
||||
// done, but which does not directly affect inference in any way.
|
||||
//
|
||||
// An example is a `A <= B` where neither `A` nor `B` are
|
||||
// inference variables.
|
||||
verifys: RefCell<Vec<Verify>>,
|
||||
|
||||
// A "given" is a relationship that is known to hold. In particular,
|
||||
// we often know from closure fn signatures that a particular free
|
||||
// region must be a subregion of a region variable:
|
||||
//
|
||||
// foo.iter().filter(<'a> |x: &'a &'b T| ...)
|
||||
//
|
||||
// In situations like this, `'b` is in fact a region variable
|
||||
// introduced by the call to `iter()`, and `'a` is a bound region
|
||||
// on the closure (as indicated by the `<'a>` prefix). If we are
|
||||
// naive, we wind up inferring that `'b` must be `'static`,
|
||||
// because we require that it be greater than `'a` and we do not
|
||||
// know what `'a` is precisely.
|
||||
//
|
||||
// This hashmap is used to avoid that naive scenario. Basically we
|
||||
// record the fact that `'a <= 'b` is implied by the fn signature,
|
||||
// and then ignore the constraint when solving equations. This is
|
||||
// a bit of a hack but seems to work.
|
||||
givens: RefCell<HashSet<(ty::FreeRegion, ty::RegionVid)>>,
|
||||
|
||||
lubs: RefCell<CombineMap>,
|
||||
glbs: RefCell<CombineMap>,
|
||||
skolemization_count: Cell<uint>,
|
||||
@ -164,6 +224,8 @@ impl<'a> RegionVarBindings<'a> {
|
||||
var_origins: RefCell::new(Vec::new()),
|
||||
values: RefCell::new(None),
|
||||
constraints: RefCell::new(HashMap::new()),
|
||||
verifys: RefCell::new(Vec::new()),
|
||||
givens: RefCell::new(HashSet::new()),
|
||||
lubs: RefCell::new(HashMap::new()),
|
||||
glbs: RefCell::new(HashMap::new()),
|
||||
skolemization_count: Cell::new(0),
|
||||
@ -216,12 +278,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||
Mark | CommitedSnapshot => { }
|
||||
AddVar(vid) => {
|
||||
let mut var_origins = self.var_origins.borrow_mut();
|
||||
assert_eq!(var_origins.len(), vid.index + 1);
|
||||
var_origins.pop().unwrap();
|
||||
assert_eq!(var_origins.len(), vid.index);
|
||||
}
|
||||
AddConstraint(ref constraint) => {
|
||||
self.constraints.borrow_mut().remove(constraint);
|
||||
}
|
||||
AddVerify(index) => {
|
||||
self.verifys.borrow_mut().pop();
|
||||
assert_eq!(self.verifys.borrow().len(), index);
|
||||
}
|
||||
AddGiven(sub, sup) => {
|
||||
self.givens.borrow_mut().remove(&(sub, sup));
|
||||
}
|
||||
AddCombination(Glb, ref regions) => {
|
||||
self.glbs.borrow_mut().remove(regions);
|
||||
}
|
||||
@ -289,13 +358,14 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.values.borrow().is_none()
|
||||
}
|
||||
|
||||
pub fn add_constraint(&self,
|
||||
constraint: Constraint,
|
||||
origin: SubregionOrigin) {
|
||||
fn add_constraint(&self,
|
||||
constraint: Constraint,
|
||||
origin: SubregionOrigin) {
|
||||
// cannot add constraints once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
debug!("RegionVarBindings: add_constraint({:?})", constraint);
|
||||
debug!("RegionVarBindings: add_constraint({})",
|
||||
constraint.repr(self.tcx));
|
||||
|
||||
if self.constraints.borrow_mut().insert(constraint, origin) {
|
||||
if self.in_snapshot() {
|
||||
@ -304,6 +374,38 @@ impl<'a> RegionVarBindings<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_verify(&self,
|
||||
verify: Verify) {
|
||||
// cannot add verifys once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
debug!("RegionVarBindings: add_verify({})",
|
||||
verify.repr(self.tcx));
|
||||
|
||||
let mut verifys = self.verifys.borrow_mut();
|
||||
let index = verifys.len();
|
||||
verifys.push(verify);
|
||||
if self.in_snapshot() {
|
||||
self.undo_log.borrow_mut().push(AddVerify(index));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_given(&self,
|
||||
sub: ty::FreeRegion,
|
||||
sup: ty::RegionVid) {
|
||||
// cannot add givens once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
let mut givens = self.givens.borrow_mut();
|
||||
if givens.insert((sub, sup)) {
|
||||
debug!("add_given({} <= {})",
|
||||
sub.repr(self.tcx),
|
||||
sup);
|
||||
|
||||
self.undo_log.borrow_mut().push(AddGiven(sub, sup));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_subregion(&self,
|
||||
origin: SubregionOrigin,
|
||||
sub: Region,
|
||||
@ -320,7 +422,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||
(ReEarlyBound(..), ReEarlyBound(..)) => {
|
||||
// This case is used only to make sure that explicitly-specified
|
||||
// `Self` types match the real self type in implementations.
|
||||
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
|
||||
//
|
||||
// FIXME(NDM) -- we really shouldn't be comparing bound things
|
||||
self.add_verify(VerifyRegSubReg(origin, sub, sup));
|
||||
}
|
||||
(ReEarlyBound(..), _) |
|
||||
(ReLateBound(..), _) |
|
||||
@ -345,11 +449,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
|
||||
}
|
||||
_ => {
|
||||
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
|
||||
self.add_verify(VerifyRegSubReg(origin, sub, sup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_param_bound(&self,
|
||||
origin: SubregionOrigin,
|
||||
param_ty: ty::ParamTy,
|
||||
sub: Region,
|
||||
sups: Vec<Region>) {
|
||||
self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
|
||||
}
|
||||
|
||||
pub fn lub_regions(&self,
|
||||
origin: SubregionOrigin,
|
||||
a: Region,
|
||||
@ -358,7 +470,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||
// cannot add constraints once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
|
||||
debug!("RegionVarBindings: lub_regions({}, {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx));
|
||||
match (a, b) {
|
||||
(ReStatic, _) | (_, ReStatic) => {
|
||||
ReStatic // nothing lives longer than static
|
||||
@ -381,7 +495,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||
// cannot add constraints once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
|
||||
debug!("RegionVarBindings: glb_regions({}, {})",
|
||||
a.repr(self.tcx),
|
||||
b.repr(self.tcx));
|
||||
match (a, b) {
|
||||
(ReStatic, r) | (r, ReStatic) => {
|
||||
// static lives longer than everything else
|
||||
@ -397,30 +513,29 @@ impl<'a> RegionVarBindings<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_regions(&self,
|
||||
a: Region,
|
||||
b: Region)
|
||||
-> Option<Region>
|
||||
{
|
||||
match self.glb_concrete_regions(a, b) {
|
||||
Ok(r) => Some(r),
|
||||
Err(_) => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
|
||||
let v = match *self.values.borrow() {
|
||||
match *self.values.borrow() {
|
||||
None => {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins.borrow().get(rid.index).span(),
|
||||
"attempt to resolve region variable before values have \
|
||||
been computed!")
|
||||
}
|
||||
Some(ref values) => *values.get(rid.index)
|
||||
};
|
||||
|
||||
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
|
||||
rid, rid.index, v);
|
||||
match v {
|
||||
Value(r) => r,
|
||||
|
||||
NoValue => {
|
||||
// No constraints, return ty::ReEmpty
|
||||
ReEmpty
|
||||
}
|
||||
|
||||
ErrorValue => {
|
||||
// An error that has previously been reported.
|
||||
ReStatic
|
||||
Some(ref values) => {
|
||||
let r = lookup(values, rid);
|
||||
debug!("resolve_var({}) = {}", rid, r.repr(self.tcx));
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -456,7 +571,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
}
|
||||
relate(self, a, ReInfer(ReVar(c)));
|
||||
relate(self, b, ReInfer(ReVar(c)));
|
||||
debug!("combine_vars() c={:?}", c);
|
||||
debug!("combine_vars() c={}", c);
|
||||
ReInfer(ReVar(c))
|
||||
}
|
||||
|
||||
@ -493,40 +608,53 @@ impl<'a> RegionVarBindings<'a> {
|
||||
while result_index < result_set.len() {
|
||||
// nb: can't use uint::range() here because result_set grows
|
||||
let r = *result_set.get(result_index);
|
||||
debug!("result_index={}, r={:?}", result_index, r);
|
||||
debug!("result_index={}, r={}", result_index, r);
|
||||
|
||||
for undo_entry in
|
||||
self.undo_log.borrow().slice_from(mark.length).iter()
|
||||
{
|
||||
let regs = match undo_entry {
|
||||
&AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
|
||||
Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
|
||||
match undo_entry {
|
||||
&AddConstraint(ConstrainVarSubVar(a, b)) => {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
ReInfer(ReVar(a)), ReInfer(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
|
||||
Some((*a, ReInfer(ReVar(*b))))
|
||||
&AddConstraint(ConstrainRegSubVar(a, b)) => {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
a, ReInfer(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
|
||||
Some((ReInfer(ReVar(*a)), *b))
|
||||
&AddConstraint(ConstrainVarSubReg(a, b)) => {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
ReInfer(ReVar(a)), b);
|
||||
}
|
||||
&AddConstraint(ConstrainRegSubReg(a, b)) => {
|
||||
Some((a, b))
|
||||
&AddGiven(a, b) => {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
ReFree(a), ReInfer(ReVar(b)));
|
||||
}
|
||||
&AddVerify(i) => {
|
||||
match self.verifys.borrow().get(i) {
|
||||
&VerifyRegSubReg(_, a, b) => {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
a, b);
|
||||
}
|
||||
&VerifyParamBound(_, _, a, ref bs) => {
|
||||
for &b in bs.iter() {
|
||||
consider_adding_bidirectional_edges(
|
||||
&mut result_set, r,
|
||||
a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&AddCombination(..) |
|
||||
&Mark |
|
||||
&AddVar(..) |
|
||||
&OpenSnapshot |
|
||||
&CommitedSnapshot => {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match regs {
|
||||
None => {}
|
||||
Some((r1, r2)) => {
|
||||
result_set =
|
||||
consider_adding_edge(result_set, r, r1, r2);
|
||||
result_set =
|
||||
consider_adding_edge(result_set, r, r2, r1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -536,17 +664,24 @@ impl<'a> RegionVarBindings<'a> {
|
||||
|
||||
return result_set;
|
||||
|
||||
fn consider_adding_edge(result_set: Vec<Region> ,
|
||||
r: Region,
|
||||
r1: Region,
|
||||
r2: Region) -> Vec<Region> {
|
||||
let mut result_set = result_set;
|
||||
if r == r1 { // Clearly, this is potentially inefficient.
|
||||
fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
|
||||
r: Region,
|
||||
r1: Region,
|
||||
r2: Region) {
|
||||
consider_adding_directed_edge(result_set, r, r1, r2);
|
||||
consider_adding_directed_edge(result_set, r, r2, r1);
|
||||
}
|
||||
|
||||
fn consider_adding_directed_edge(result_set: &mut Vec<Region>,
|
||||
r: Region,
|
||||
r1: Region,
|
||||
r2: Region) {
|
||||
if r == r1 {
|
||||
// Clearly, this is potentially inefficient.
|
||||
if !result_set.iter().any(|x| *x == r2) {
|
||||
result_set.push(r2);
|
||||
}
|
||||
}
|
||||
return result_set;
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,7 +730,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins.borrow().get(v_id.index).span(),
|
||||
format!("lub_concrete_regions invoked with \
|
||||
non-concrete regions: {:?}, {:?}",
|
||||
non-concrete regions: {}, {}",
|
||||
a,
|
||||
b).as_slice());
|
||||
}
|
||||
@ -675,7 +810,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
a: Region,
|
||||
b: Region)
|
||||
-> cres<Region> {
|
||||
debug!("glb_concrete_regions({:?}, {:?})", a, b);
|
||||
debug!("glb_concrete_regions({}, {})", a, b);
|
||||
match (a, b) {
|
||||
(ReLateBound(..), _) |
|
||||
(_, ReLateBound(..)) |
|
||||
@ -702,7 +837,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins.borrow().get(v_id.index).span(),
|
||||
format!("glb_concrete_regions invoked with \
|
||||
non-concrete regions: {:?}, {:?}",
|
||||
non-concrete regions: {}, {}",
|
||||
a,
|
||||
b).as_slice());
|
||||
}
|
||||
@ -783,7 +918,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
// scopes or two free regions. So, if one of
|
||||
// these scopes is a subscope of the other, return
|
||||
// it. Otherwise fail.
|
||||
debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
|
||||
debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})",
|
||||
scope_a, scope_b, region_a, region_b);
|
||||
match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
|
||||
Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
|
||||
@ -815,12 +950,16 @@ type RegionGraph = graph::Graph<(), Constraint>;
|
||||
impl<'a> RegionVarBindings<'a> {
|
||||
fn infer_variable_values(&self,
|
||||
errors: &mut Vec<RegionResolutionError>)
|
||||
-> Vec<VarValue> {
|
||||
-> Vec<VarValue>
|
||||
{
|
||||
let mut var_data = self.construct_var_data();
|
||||
self.expansion(var_data.as_mut_slice());
|
||||
self.contraction(var_data.as_mut_slice());
|
||||
self.collect_concrete_region_errors(&mut *errors);
|
||||
self.extract_values_and_collect_conflicts(var_data.as_slice(), errors)
|
||||
let values =
|
||||
self.extract_values_and_collect_conflicts(var_data.as_slice(),
|
||||
errors);
|
||||
self.collect_concrete_region_errors(&values, errors);
|
||||
values
|
||||
}
|
||||
|
||||
fn construct_var_data(&self) -> Vec<VarData> {
|
||||
@ -838,6 +977,12 @@ impl<'a> RegionVarBindings<'a> {
|
||||
|
||||
fn expansion(&self, var_data: &mut [VarData]) {
|
||||
self.iterate_until_fixed_point("Expansion", |constraint| {
|
||||
debug!("expansion: constraint={} origin={}",
|
||||
constraint.repr(self.tcx),
|
||||
self.constraints.borrow()
|
||||
.find(constraint)
|
||||
.unwrap()
|
||||
.repr(self.tcx));
|
||||
match *constraint {
|
||||
ConstrainRegSubVar(a_region, b_vid) => {
|
||||
let b_data = &mut var_data[b_vid.index];
|
||||
@ -856,10 +1001,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||
// This is a contraction constraint. Ignore it.
|
||||
false
|
||||
}
|
||||
ConstrainRegSubReg(..) => {
|
||||
// No region variables involved. Ignore.
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -868,14 +1009,29 @@ impl<'a> RegionVarBindings<'a> {
|
||||
a_region: Region,
|
||||
b_vid: RegionVid,
|
||||
b_data: &mut VarData)
|
||||
-> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})",
|
||||
a_region, b_vid, b_data.value);
|
||||
-> bool
|
||||
{
|
||||
debug!("expand_node({}, {} == {})",
|
||||
a_region.repr(self.tcx),
|
||||
b_vid,
|
||||
b_data.value.repr(self.tcx));
|
||||
|
||||
// Check if this relationship is implied by a given.
|
||||
match a_region {
|
||||
ty::ReFree(fr) => {
|
||||
if self.givens.borrow().contains(&(fr, b_vid)) {
|
||||
debug!("given");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
b_data.classification = Expanding;
|
||||
match b_data.value {
|
||||
NoValue => {
|
||||
debug!("Setting initial value of {:?} to {:?}", b_vid, a_region);
|
||||
debug!("Setting initial value of {} to {}",
|
||||
b_vid, a_region.repr(self.tcx));
|
||||
|
||||
b_data.value = Value(a_region);
|
||||
return true;
|
||||
@ -887,8 +1043,10 @@ impl<'a> RegionVarBindings<'a> {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug!("Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid, cur_region, lub);
|
||||
debug!("Expanding value of {} from {} to {}",
|
||||
b_vid,
|
||||
cur_region.repr(self.tcx),
|
||||
lub.repr(self.tcx));
|
||||
|
||||
b_data.value = Value(lub);
|
||||
return true;
|
||||
@ -903,6 +1061,12 @@ impl<'a> RegionVarBindings<'a> {
|
||||
fn contraction(&self,
|
||||
var_data: &mut [VarData]) {
|
||||
self.iterate_until_fixed_point("Contraction", |constraint| {
|
||||
debug!("contraction: constraint={} origin={}",
|
||||
constraint.repr(self.tcx),
|
||||
self.constraints.borrow()
|
||||
.find(constraint)
|
||||
.unwrap()
|
||||
.repr(self.tcx));
|
||||
match *constraint {
|
||||
ConstrainRegSubVar(..) => {
|
||||
// This is an expansion constraint. Ignore.
|
||||
@ -921,10 +1085,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||
let a_data = &mut var_data[a_vid.index];
|
||||
self.contract_node(a_vid, a_data, b_region)
|
||||
}
|
||||
ConstrainRegSubReg(..) => {
|
||||
// No region variables involved. Ignore.
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -934,8 +1094,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||
a_data: &mut VarData,
|
||||
b_region: Region)
|
||||
-> bool {
|
||||
debug!("contract_node({:?} == {:?}/{:?}, {:?})",
|
||||
a_vid, a_data.value, a_data.classification, b_region);
|
||||
debug!("contract_node({} == {}/{}, {})",
|
||||
a_vid, a_data.value.repr(self.tcx),
|
||||
a_data.classification, b_region.repr(self.tcx));
|
||||
|
||||
return match a_data.value {
|
||||
NoValue => {
|
||||
@ -967,8 +1128,10 @@ impl<'a> RegionVarBindings<'a> {
|
||||
b_region: Region)
|
||||
-> bool {
|
||||
if !this.is_subregion_of(a_region, b_region) {
|
||||
debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
|
||||
a_vid, a_region, b_region);
|
||||
debug!("Setting {} to ErrorValue: {} not subregion of {}",
|
||||
a_vid,
|
||||
a_region.repr(this.tcx),
|
||||
b_region.repr(this.tcx));
|
||||
a_data.value = ErrorValue;
|
||||
}
|
||||
false
|
||||
@ -985,15 +1148,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||
if glb == a_region {
|
||||
false
|
||||
} else {
|
||||
debug!("Contracting value of {:?} from {:?} to {:?}",
|
||||
a_vid, a_region, glb);
|
||||
debug!("Contracting value of {} from {} to {}",
|
||||
a_vid,
|
||||
a_region.repr(this.tcx),
|
||||
glb.repr(this.tcx));
|
||||
a_data.value = Value(glb);
|
||||
true
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
|
||||
a_vid, a_region, b_region);
|
||||
debug!("Setting {} to ErrorValue: no glb of {}, {}",
|
||||
a_vid,
|
||||
a_region.repr(this.tcx),
|
||||
b_region.repr(this.tcx));
|
||||
a_data.value = ErrorValue;
|
||||
false
|
||||
}
|
||||
@ -1001,30 +1168,44 @@ impl<'a> RegionVarBindings<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_concrete_region_errors(
|
||||
&self,
|
||||
errors: &mut Vec<RegionResolutionError>)
|
||||
fn collect_concrete_region_errors(&self,
|
||||
values: &Vec<VarValue>,
|
||||
errors: &mut Vec<RegionResolutionError>)
|
||||
{
|
||||
for (constraint, _) in self.constraints.borrow().iter() {
|
||||
let (sub, sup) = match *constraint {
|
||||
ConstrainVarSubVar(..) |
|
||||
ConstrainRegSubVar(..) |
|
||||
ConstrainVarSubReg(..) => {
|
||||
continue;
|
||||
}
|
||||
ConstrainRegSubReg(sub, sup) => {
|
||||
(sub, sup)
|
||||
}
|
||||
};
|
||||
let mut reg_reg_dups = HashSet::new();
|
||||
for verify in self.verifys.borrow().iter() {
|
||||
match *verify {
|
||||
VerifyRegSubReg(ref origin, sub, sup) => {
|
||||
if self.is_subregion_of(sub, sup) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.is_subregion_of(sub, sup) {
|
||||
continue;
|
||||
if !reg_reg_dups.insert((sub, sup)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
|
||||
sub.repr(self.tcx),
|
||||
sup.repr(self.tcx));
|
||||
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
|
||||
}
|
||||
|
||||
VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => {
|
||||
let sub = normalize(values, sub);
|
||||
if sups.iter()
|
||||
.map(|&sup| normalize(values, sup))
|
||||
.any(|sup| self.is_subregion_of(sub, sup))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let sups = sups.iter().map(|&sup| normalize(values, sup))
|
||||
.collect();
|
||||
errors.push(
|
||||
ParamBoundFailure(
|
||||
(*origin).clone(), *param_ty, sub, sups));
|
||||
}
|
||||
}
|
||||
|
||||
debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
|
||||
sub, sup);
|
||||
let origin = self.constraints.borrow().get_copy(constraint);
|
||||
errors.push(ConcreteFailure(origin, sub, sup));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1032,7 +1213,8 @@ impl<'a> RegionVarBindings<'a> {
|
||||
&self,
|
||||
var_data: &[VarData],
|
||||
errors: &mut Vec<RegionResolutionError>)
|
||||
-> Vec<VarValue> {
|
||||
-> Vec<VarValue>
|
||||
{
|
||||
debug!("extract_values_and_collect_conflicts()");
|
||||
|
||||
// This is the best way that I have found to suppress
|
||||
@ -1141,10 +1323,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||
dummy_idx,
|
||||
*constraint);
|
||||
}
|
||||
ConstrainRegSubReg(..) => {
|
||||
// Relations between two concrete regions do not
|
||||
// require an edge in the graph.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1206,16 +1384,10 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins.borrow().get(node_idx.index).span(),
|
||||
format!("collect_error_for_expanding_node() could not find error \
|
||||
for var {:?}, lower_bounds={}, upper_bounds={}",
|
||||
node_idx,
|
||||
lower_bounds.iter()
|
||||
.map(|x| x.region)
|
||||
.collect::<Vec<ty::Region>>()
|
||||
.repr(self.tcx),
|
||||
upper_bounds.iter()
|
||||
.map(|x| x.region)
|
||||
.collect::<Vec<ty::Region>>()
|
||||
.repr(self.tcx)).as_slice());
|
||||
for var {}, lower_bounds={}, upper_bounds={}",
|
||||
node_idx,
|
||||
lower_bounds.repr(self.tcx),
|
||||
upper_bounds.repr(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
fn collect_error_for_contracting_node(
|
||||
@ -1257,12 +1429,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||
self.tcx.sess.span_bug(
|
||||
self.var_origins.borrow().get(node_idx.index).span(),
|
||||
format!("collect_error_for_contracting_node() could not find error \
|
||||
for var {:?}, upper_bounds={}",
|
||||
node_idx,
|
||||
upper_bounds.iter()
|
||||
.map(|x| x.region)
|
||||
.collect::<Vec<ty::Region>>()
|
||||
.repr(self.tcx)).as_slice());
|
||||
for var {}, upper_bounds={}",
|
||||
node_idx,
|
||||
upper_bounds.repr(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
fn collect_concrete_regions(&self,
|
||||
@ -1301,8 +1470,8 @@ impl<'a> RegionVarBindings<'a> {
|
||||
state.dup_found = true;
|
||||
}
|
||||
|
||||
debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
|
||||
classification={:?})",
|
||||
debug!("collect_concrete_regions(orig_node_idx={}, node_idx={}, \
|
||||
classification={})",
|
||||
orig_node_idx, node_idx, classification);
|
||||
|
||||
// figure out the direction from which this node takes its
|
||||
@ -1323,7 +1492,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||
graph: &RegionGraph,
|
||||
source_vid: RegionVid,
|
||||
dir: Direction) {
|
||||
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
|
||||
debug!("process_edges(source_vid={}, dir={})", source_vid, dir);
|
||||
|
||||
let source_node_index = NodeIndex(source_vid.index);
|
||||
graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
|
||||
@ -1343,8 +1512,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||
origin: this.constraints.borrow().get_copy(&edge.data)
|
||||
});
|
||||
}
|
||||
|
||||
ConstrainRegSubReg(..) => {}
|
||||
}
|
||||
true
|
||||
});
|
||||
@ -1386,9 +1553,53 @@ impl Repr for Constraint {
|
||||
ConstrainVarSubReg(a, b) => {
|
||||
format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
|
||||
}
|
||||
ConstrainRegSubReg(a, b) => {
|
||||
format!("ConstrainRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for Verify {
|
||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||
match *self {
|
||||
VerifyRegSubReg(_, ref a, ref b) => {
|
||||
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
|
||||
}
|
||||
VerifyParamBound(_, ref p, ref a, ref bs) => {
|
||||
format!("VerifyParamBound({}, {}, {})",
|
||||
p.repr(tcx), a.repr(tcx), bs.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
|
||||
match r {
|
||||
ty::ReInfer(ReVar(rid)) => lookup(values, rid),
|
||||
_ => r
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
|
||||
match *values.get(rid.index) {
|
||||
Value(r) => r,
|
||||
NoValue => ReEmpty, // No constraints, return ty::ReEmpty
|
||||
ErrorValue => ReStatic, // Previously reported error.
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for VarValue {
|
||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||
match *self {
|
||||
NoValue => format!("NoValue"),
|
||||
Value(r) => format!("Value({})", r.repr(tcx)),
|
||||
ErrorValue => format!("ErrorValue"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for RegionAndOrigin {
|
||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||
format!("RegionAndOrigin({},{})",
|
||||
self.region.repr(tcx),
|
||||
self.origin.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,8 @@ impl<'f> Combine for Sub<'f> {
|
||||
})
|
||||
}
|
||||
|
||||
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
|
||||
fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
|
||||
-> cres<BuiltinBounds> {
|
||||
// More bounds is a subtype of fewer bounds.
|
||||
//
|
||||
// e.g., fn:Copy() <: fn(), because the former is a function
|
||||
|
@ -555,3 +555,12 @@ impl SimplyUnifiable for ast::FloatTy {
|
||||
return ty::terr_float_mismatch(err);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K:Repr,V:Repr> Repr for VarValue<K,V> {
|
||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||
match *self {
|
||||
Redirect(ref k) => format!("Redirect({})", k.repr(tcx)),
|
||||
Root(ref v, r) => format!("Root({}, {})", v.repr(tcx), r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,12 +30,19 @@ pub trait RegionScope {
|
||||
span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region> , ()>;
|
||||
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
|
||||
}
|
||||
|
||||
// A scope in which all regions must be explicitly named
|
||||
// A scope in which all regions must be explicitly named. This is used
|
||||
// for types that appear in structs and so on.
|
||||
pub struct ExplicitRscope;
|
||||
|
||||
impl RegionScope for ExplicitRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
_count: uint)
|
||||
@ -44,6 +51,33 @@ impl RegionScope for ExplicitRscope {
|
||||
}
|
||||
}
|
||||
|
||||
// A scope in which any omitted region defaults to `default`. This is
|
||||
// used after the `->` in function signatures, but also for backwards
|
||||
// compatibility with object types. The latter use may go away.
|
||||
pub struct SpecificRscope {
|
||||
default: ty::Region
|
||||
}
|
||||
|
||||
impl SpecificRscope {
|
||||
pub fn new(r: ty::Region) -> SpecificRscope {
|
||||
SpecificRscope { default: r }
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for SpecificRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
Some(self.default)
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
_span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region> , ()>
|
||||
{
|
||||
Ok(Vec::from_elem(count, self.default))
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope in which we generate anonymous, late-bound regions for
|
||||
/// omitted regions. This occurs in function signatures.
|
||||
pub struct BindingRscope {
|
||||
@ -58,30 +92,26 @@ impl BindingRscope {
|
||||
anon_bindings: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_region(&self) -> ty::Region {
|
||||
let idx = self.anon_bindings.get();
|
||||
self.anon_bindings.set(idx + 1);
|
||||
ty::ReLateBound(self.binder_id, ty::BrAnon(idx))
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for BindingRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
|
||||
{
|
||||
Some(self.next_region())
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
_: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region>, ()> {
|
||||
let idx = self.anon_bindings.get();
|
||||
self.anon_bindings.set(idx + count);
|
||||
Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
|
||||
ty::BrAnon(idx + i))))
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope in which we generate one specific region. This occurs after the
|
||||
/// `->` (i.e. in the return type) of function signatures.
|
||||
pub struct ImpliedSingleRscope {
|
||||
pub region: ty::Region,
|
||||
}
|
||||
|
||||
impl RegionScope for ImpliedSingleRscope {
|
||||
fn anon_regions(&self, _: Span, count: uint)
|
||||
-> Result<Vec<ty::Region>,()> {
|
||||
Ok(Vec::from_elem(count, self.region.clone()))
|
||||
-> Result<Vec<ty::Region> , ()>
|
||||
{
|
||||
Ok(Vec::from_fn(count, |_| self.next_region()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::HashMap;
|
||||
use syntax::ast;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
@ -105,3 +107,51 @@ pub fn block_query(b: ast::P<ast::Block>, p: |&ast::Expr| -> bool) -> bool {
|
||||
visit::walk_block(&mut v, &*b, ());
|
||||
return v.flag;
|
||||
}
|
||||
|
||||
// K: Eq + Hash<S>, V, S, H: Hasher<S>
|
||||
pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>(
|
||||
edges_map: &HashMap<T,Vec<T>,H>,
|
||||
source: T,
|
||||
destination: T)
|
||||
-> bool
|
||||
{
|
||||
/*!
|
||||
* Determines whether there exists a path from `source` to
|
||||
* `destination`. The graph is defined by the `edges_map`, which
|
||||
* maps from a node `S` to a list of its adjacent nodes `T`.
|
||||
*
|
||||
* Efficiency note: This is implemented in an inefficient way
|
||||
* because it is typically invoked on very small graphs. If the graphs
|
||||
* become larger, a more efficient graph representation and algorithm
|
||||
* would probably be advised.
|
||||
*/
|
||||
|
||||
if source == destination {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do a little breadth-first-search here. The `queue` list
|
||||
// doubles as a way to detect if we've seen a particular FR
|
||||
// before. Note that we expect this graph to be an *extremely
|
||||
// shallow* tree.
|
||||
let mut queue = vec!(source);
|
||||
let mut i = 0;
|
||||
while i < queue.len() {
|
||||
match edges_map.find(queue.get(i)) {
|
||||
Some(edges) => {
|
||||
for target in edges.iter() {
|
||||
if *target == destination {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !queue.iter().any(|x| x == target) {
|
||||
queue.push((*target).clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -23,11 +23,9 @@ use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
|
||||
use middle::ty::{ty_unboxed_closure};
|
||||
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::region_inference;
|
||||
use middle::typeck::infer::unify::VarValue as VV;
|
||||
use middle::typeck::infer::unify;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck;
|
||||
use middle::typeck::check::regionmanip;
|
||||
use middle::typeck::infer;
|
||||
|
||||
use std::gc::Gc;
|
||||
use std::rc::Rc;
|
||||
@ -66,6 +64,22 @@ pub fn note_and_explain_region(cx: &ctxt,
|
||||
}
|
||||
}
|
||||
|
||||
fn item_scope_tag(item: &ast::Item) -> &'static str {
|
||||
/*!
|
||||
* When a free region is associated with `item`, how should we describe
|
||||
* the item in the error message.
|
||||
*/
|
||||
|
||||
match item.node {
|
||||
ast::ItemImpl(..) => "impl",
|
||||
ast::ItemStruct(..) => "struct",
|
||||
ast::ItemEnum(..) => "enum",
|
||||
ast::ItemTrait(..) => "trait",
|
||||
ast::ItemFn(..) => "function body",
|
||||
_ => "item"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||
-> (String, Option<Span>) {
|
||||
return match region {
|
||||
@ -87,9 +101,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||
Some(ast_map::NodeStmt(stmt)) => {
|
||||
explain_span(cx, "statement", stmt.span)
|
||||
}
|
||||
Some(ast_map::NodeItem(it)) if (match it.node {
|
||||
ast::ItemFn(..) => true, _ => false}) => {
|
||||
explain_span(cx, "function body", it.span)
|
||||
Some(ast_map::NodeItem(it)) => {
|
||||
let tag = item_scope_tag(&*it);
|
||||
explain_span(cx, tag, it.span)
|
||||
}
|
||||
Some(_) | None => {
|
||||
// this really should not happen
|
||||
@ -112,17 +126,17 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||
|
||||
match cx.map.find(fr.scope_id) {
|
||||
Some(ast_map::NodeBlock(ref blk)) => {
|
||||
let (msg, opt_span) = explain_span(cx, "block", blk.span);
|
||||
(format!("{} {}", prefix, msg), opt_span)
|
||||
let (msg, opt_span) = explain_span(cx, "block", blk.span);
|
||||
(format!("{} {}", prefix, msg), opt_span)
|
||||
}
|
||||
Some(ast_map::NodeItem(it)) if match it.node {
|
||||
ast::ItemImpl(..) => true, _ => false} => {
|
||||
let (msg, opt_span) = explain_span(cx, "impl", it.span);
|
||||
(format!("{} {}", prefix, msg), opt_span)
|
||||
Some(ast_map::NodeItem(it)) => {
|
||||
let tag = item_scope_tag(&*it);
|
||||
let (msg, opt_span) = explain_span(cx, tag, it.span);
|
||||
(format!("{} {}", prefix, msg), opt_span)
|
||||
}
|
||||
Some(_) | None => {
|
||||
// this really should not happen
|
||||
(format!("{} node {}", prefix, fr.scope_id), None)
|
||||
// this really should not happen
|
||||
(format!("{} node {}", prefix, fr.scope_id), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,7 +157,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||
};
|
||||
|
||||
fn explain_span(cx: &ctxt, heading: &str, span: Span)
|
||||
-> (String, Option<Span>) {
|
||||
-> (String, Option<Span>) {
|
||||
let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
|
||||
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()),
|
||||
Some(span))
|
||||
@ -273,7 +287,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
_ => { }
|
||||
}
|
||||
|
||||
push_sig_to_string(cx, &mut s, '(', ')', sig);
|
||||
push_sig_to_string(cx, &mut s, '(', ')', sig, "");
|
||||
|
||||
s
|
||||
}
|
||||
@ -296,34 +310,34 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
}
|
||||
};
|
||||
|
||||
let bounds_str = cty.bounds.user_string(cx);
|
||||
|
||||
match cty.store {
|
||||
ty::UniqTraitStore => {
|
||||
assert_eq!(cty.onceness, ast::Once);
|
||||
s.push_str("proc");
|
||||
push_sig_to_string(cx, &mut s, '(', ')', &cty.sig);
|
||||
push_sig_to_string(cx, &mut s, '(', ')', &cty.sig,
|
||||
bounds_str.as_slice());
|
||||
}
|
||||
ty::RegionTraitStore(..) => {
|
||||
match cty.onceness {
|
||||
ast::Many => {}
|
||||
ast::Once => s.push_str("once ")
|
||||
}
|
||||
push_sig_to_string(cx, &mut s, '|', '|', &cty.sig);
|
||||
push_sig_to_string(cx, &mut s, '|', '|', &cty.sig,
|
||||
bounds_str.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
if !cty.bounds.is_empty() {
|
||||
s.push_str(":");
|
||||
s.push_str(cty.bounds.repr(cx).as_slice());
|
||||
}
|
||||
|
||||
s
|
||||
s.into_owned()
|
||||
}
|
||||
|
||||
fn push_sig_to_string(cx: &ctxt,
|
||||
s: &mut String,
|
||||
bra: char,
|
||||
ket: char,
|
||||
sig: &ty::FnSig) {
|
||||
sig: &ty::FnSig,
|
||||
bounds: &str) {
|
||||
s.push_char(bra);
|
||||
let strs: Vec<String> = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect();
|
||||
s.push_str(strs.connect(", ").as_slice());
|
||||
@ -332,6 +346,11 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
}
|
||||
s.push_char(ket);
|
||||
|
||||
if !bounds.is_empty() {
|
||||
s.push_str(":");
|
||||
s.push_str(bounds);
|
||||
}
|
||||
|
||||
if ty::get(sig.output).sty != ty_nil {
|
||||
s.push_str(" -> ");
|
||||
if ty::type_is_bot(sig.output) {
|
||||
@ -383,18 +402,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
}
|
||||
ty_infer(infer_ty) => infer_ty.to_string(),
|
||||
ty_err => "[type error]".to_string(),
|
||||
ty_param(ParamTy {idx: id, def_id: did, ..}) => {
|
||||
let ident = match cx.ty_param_defs.borrow().find(&did.node) {
|
||||
Some(def) => token::get_ident(def.ident).get().to_string(),
|
||||
// This can only happen when a type mismatch error happens and
|
||||
// the actual type has more type parameters than the expected one.
|
||||
None => format!("<generic #{}>", id),
|
||||
};
|
||||
if !cx.sess.verbose() {
|
||||
ident
|
||||
} else {
|
||||
format!("{}:{:?}", ident, did)
|
||||
}
|
||||
ty_param(ref param_ty) => {
|
||||
param_ty.repr(cx)
|
||||
}
|
||||
ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
|
||||
let base = ty::item_path_str(cx, did);
|
||||
@ -408,8 +417,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
let trait_def = ty::lookup_trait_def(cx, did);
|
||||
let ty = parameterized(cx, base.as_slice(),
|
||||
substs, &trait_def.generics);
|
||||
let bound_sep = if bounds.is_empty() { "" } else { "+" };
|
||||
let bound_str = bounds.repr(cx);
|
||||
let bound_str = bounds.user_string(cx);
|
||||
let bound_sep = if bound_str.is_empty() { "" } else { "+" };
|
||||
format!("{}{}{}",
|
||||
ty,
|
||||
bound_sep,
|
||||
@ -573,6 +582,14 @@ impl<T:Repr> Repr for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:UserString> UserString for Vec<T> {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
let strs: Vec<String> =
|
||||
self.iter().map(|t| t.user_string(tcx)).collect();
|
||||
strs.connect(", ")
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for def::Def {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("{:?}", *self)
|
||||
@ -581,16 +598,18 @@ impl Repr for def::Def {
|
||||
|
||||
impl Repr for ty::TypeParameterDef {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("TypeParameterDef({:?}, {})", self.def_id,
|
||||
format!("TypeParameterDef({}, {})",
|
||||
self.def_id.repr(tcx),
|
||||
self.bounds.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::RegionParameterDef {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("RegionParameterDef({}, {:?})",
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("RegionParameterDef(name={}, def_id={}, bounds={})",
|
||||
token::get_name(self.name),
|
||||
self.def_id)
|
||||
self.def_id.repr(tcx),
|
||||
self.bounds.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
@ -638,18 +657,31 @@ impl Repr for subst::RegionSubsts {
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::BuiltinBounds {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
let mut res = Vec::new();
|
||||
for b in self.iter() {
|
||||
res.push(match b {
|
||||
ty::BoundSend => "Send".to_owned(),
|
||||
ty::BoundSized => "Sized".to_owned(),
|
||||
ty::BoundCopy => "Copy".to_owned(),
|
||||
ty::BoundSync => "Sync".to_owned(),
|
||||
});
|
||||
}
|
||||
res.connect("+")
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::ExistentialBounds {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
self.user_string(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::ParamBounds {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
let mut res = Vec::new();
|
||||
for b in self.builtin_bounds.iter() {
|
||||
res.push(match b {
|
||||
ty::BoundStatic => "'static".to_string(),
|
||||
ty::BoundSend => "Send".to_string(),
|
||||
ty::BoundSized => "Sized".to_string(),
|
||||
ty::BoundCopy => "Copy".to_string(),
|
||||
ty::BoundSync => "Sync".to_string(),
|
||||
});
|
||||
}
|
||||
res.push(self.builtin_bounds.repr(tcx));
|
||||
for t in self.trait_bounds.iter() {
|
||||
res.push(t.repr(tcx));
|
||||
}
|
||||
@ -663,6 +695,15 @@ impl Repr for ty::TraitRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::TraitDef {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("TraitDef(generics={}, bounds={}, trait_ref={})",
|
||||
self.generics.repr(tcx),
|
||||
self.bounds.repr(tcx),
|
||||
self.trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Expr {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("expr({}: {})", self.id, pprust::expr_to_string(self))
|
||||
@ -675,12 +716,24 @@ impl Repr for ast::Path {
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ast::Path {
|
||||
fn user_string(&self, _tcx: &ctxt) -> String {
|
||||
pprust::path_to_string(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Item {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("item({})", tcx.map.node_to_string(self.id))
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Lifetime {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Stmt {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("stmt({}: {})",
|
||||
@ -724,11 +777,7 @@ impl Repr for ty::Region {
|
||||
bound_region.repr(tcx))
|
||||
}
|
||||
|
||||
ty::ReFree(ref fr) => {
|
||||
format!("ReFree({}, {})",
|
||||
fr.scope_id,
|
||||
fr.bound_region.repr(tcx))
|
||||
}
|
||||
ty::ReFree(ref fr) => fr.repr(tcx),
|
||||
|
||||
ty::ReScope(id) => {
|
||||
format!("ReScope({})", id)
|
||||
@ -753,6 +802,20 @@ impl Repr for ty::Region {
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ty::Region {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
region_to_string(tcx, "", false, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::FreeRegion {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("ReFree({}, {})",
|
||||
self.scope_id,
|
||||
self.bound_region.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::DefId {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
// Unfortunately, there seems to be no way to attempt to print
|
||||
@ -833,6 +896,12 @@ impl Repr for ast::Name {
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ast::Name {
|
||||
fn user_string(&self, _tcx: &ctxt) -> String {
|
||||
token::get_name(*self).get().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Ident {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
token::get_ident(*self).get().to_string()
|
||||
@ -928,21 +997,14 @@ impl Repr for ty::BuiltinBound {
|
||||
impl UserString for ty::BuiltinBound {
|
||||
fn user_string(&self, _tcx: &ctxt) -> String {
|
||||
match *self {
|
||||
ty::BoundStatic => "'static".to_string(),
|
||||
ty::BoundSend => "Send".to_string(),
|
||||
ty::BoundSized => "Sized".to_string(),
|
||||
ty::BoundCopy => "Copy".to_string(),
|
||||
ty::BoundSync => "Sync".to_string(),
|
||||
ty::BoundSend => "Send".to_owned(),
|
||||
ty::BoundSized => "Sized".to_owned(),
|
||||
ty::BoundCopy => "Copy".to_owned(),
|
||||
ty::BoundSync => "Sync".to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::BuiltinBounds {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
self.user_string(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for Span {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
tcx.sess.codemap().span_to_string(*self).to_string()
|
||||
@ -956,6 +1018,43 @@ impl<A:UserString> UserString for Rc<A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ty::ParamBounds {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
let mut result = Vec::new();
|
||||
let s = self.builtin_bounds.user_string(tcx);
|
||||
if !s.is_empty() {
|
||||
result.push(s);
|
||||
}
|
||||
for n in self.trait_bounds.iter() {
|
||||
result.push(n.user_string(tcx));
|
||||
}
|
||||
result.connect("+")
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ty::ExistentialBounds {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
if self.builtin_bounds.contains_elem(ty::BoundSend) &&
|
||||
self.region_bound == ty::ReStatic
|
||||
{ // Region bound is implied by builtin bounds:
|
||||
return self.builtin_bounds.repr(tcx);
|
||||
}
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
let region_str = self.region_bound.user_string(tcx);
|
||||
if !region_str.is_empty() {
|
||||
res.push(region_str);
|
||||
}
|
||||
|
||||
for bound in self.builtin_bounds.iter() {
|
||||
res.push(bound.user_string(tcx));
|
||||
}
|
||||
|
||||
res.connect("+")
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ty::BuiltinBounds {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
self.iter()
|
||||
@ -1083,33 +1182,55 @@ impl<T:Repr> Repr for infer::Bounds<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K:Repr,V:Repr> Repr for VV<K,V> {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
match *self {
|
||||
unify::Redirect(ref k) =>
|
||||
format!("Redirect({})", k.repr(tcx)),
|
||||
unify::Root(ref v, r) =>
|
||||
format!("Root({}, {})", v.repr(tcx), r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for region_inference::VarValue {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
match *self {
|
||||
infer::region_inference::NoValue =>
|
||||
format!("NoValue"),
|
||||
infer::region_inference::Value(r) =>
|
||||
format!("Value({})", r.repr(tcx)),
|
||||
infer::region_inference::ErrorValue =>
|
||||
format!("ErrorValue"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::ExplicitSelfCategory {
|
||||
fn repr(&self, _: &ctxt) -> String {
|
||||
explicit_self_category_to_str(self).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Repr for regionmanip::WfConstraint {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
match *self {
|
||||
regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => {
|
||||
format!("RegionSubRegionConstraint({}, {})",
|
||||
r_a.repr(tcx),
|
||||
r_b.repr(tcx))
|
||||
}
|
||||
|
||||
regionmanip::RegionSubParamConstraint(_, r, p) => {
|
||||
format!("RegionSubParamConstraint({}, {})",
|
||||
r.repr(tcx),
|
||||
p.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserString for ParamTy {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
let id = self.idx;
|
||||
let did = self.def_id;
|
||||
let ident = match tcx.ty_param_defs.borrow().find(&did.node) {
|
||||
Some(def) => token::get_ident(def.ident).get().to_string(),
|
||||
|
||||
// This can only happen when a type mismatch error happens and
|
||||
// the actual type has more type parameters than the expected one.
|
||||
None => format!("<generic #{}>", id),
|
||||
};
|
||||
ident
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ParamTy {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
self.user_string(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A:Repr,B:Repr> Repr for (A,B) {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
let &(ref a, ref b) = self;
|
||||
format!("({},{})", a.repr(tcx), b.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ impl AttrHelper for SpecialAttribute {
|
||||
}
|
||||
|
||||
pub struct AttrBuilder {
|
||||
attrs: Vec<(uint, Box<AttrHelper>)>
|
||||
attrs: Vec<(uint, Box<AttrHelper+'static>)>
|
||||
}
|
||||
|
||||
impl AttrBuilder {
|
||||
@ -203,12 +203,12 @@ impl AttrBuilder {
|
||||
}
|
||||
|
||||
pub fn arg<'a, T: AttrHelper + 'static>(&'a mut self, idx: uint, a: T) -> &'a mut AttrBuilder {
|
||||
self.attrs.push((idx, box a as Box<AttrHelper>));
|
||||
self.attrs.push((idx, box a as Box<AttrHelper+'static>));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder {
|
||||
self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper>));
|
||||
self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper+'static>));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -159,18 +159,12 @@ pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
|
||||
clean::RequiredMethod(trait_item)
|
||||
}
|
||||
});
|
||||
let supertraits = ty::trait_supertraits(tcx, did);
|
||||
let mut parents = supertraits.iter().map(|i| {
|
||||
match i.clean() {
|
||||
clean::TraitBound(ty) => ty,
|
||||
clean::RegionBound => unreachable!()
|
||||
}
|
||||
});
|
||||
|
||||
let trait_def = ty::lookup_trait_def(tcx, did);
|
||||
let bounds = trait_def.bounds.clean();
|
||||
clean::Trait {
|
||||
generics: (&def.generics, subst::TypeSpace).clean(),
|
||||
items: items.collect(),
|
||||
parents: parents.collect()
|
||||
bounds: bounds,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,15 +481,14 @@ impl Clean<TyParam> for ty::TypeParameterDef {
|
||||
|
||||
#[deriving(Clone, Encodable, Decodable, PartialEq)]
|
||||
pub enum TyParamBound {
|
||||
RegionBound,
|
||||
RegionBound, // FIXME(#16518) -- need to include name of actual region
|
||||
TraitBound(Type)
|
||||
}
|
||||
|
||||
impl Clean<TyParamBound> for ast::TyParamBound {
|
||||
fn clean(&self) -> TyParamBound {
|
||||
match *self {
|
||||
ast::StaticRegionTyParamBound => RegionBound,
|
||||
ast::OtherRegionTyParamBound(_) => RegionBound,
|
||||
ast::RegionTyParamBound(_) => RegionBound,
|
||||
ast::UnboxedFnTyParamBound(_) => {
|
||||
// FIXME(pcwalton): Wrong.
|
||||
RegionBound
|
||||
@ -499,6 +498,16 @@ impl Clean<TyParamBound> for ast::TyParamBound {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Vec<TyParamBound>> for ty::ExistentialBounds {
|
||||
fn clean(&self) -> Vec<TyParamBound> {
|
||||
let mut vec = vec!(RegionBound);
|
||||
for bb in self.builtin_bounds.iter() {
|
||||
vec.push(bb.clean());
|
||||
}
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
fn external_path(name: &str, substs: &subst::Substs) -> Path {
|
||||
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
|
||||
.iter()
|
||||
@ -525,7 +534,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
|
||||
};
|
||||
let empty = subst::Substs::empty();
|
||||
let (did, path) = match *self {
|
||||
ty::BoundStatic => return RegionBound,
|
||||
ty::BoundSend =>
|
||||
(tcx.lang_items.send_trait().unwrap(),
|
||||
external_path("Send", &empty)),
|
||||
@ -810,10 +818,7 @@ impl Clean<ClosureDecl> for ast::ClosureTy {
|
||||
decl: self.decl.clean(),
|
||||
onceness: self.onceness,
|
||||
fn_style: self.fn_style,
|
||||
bounds: match self.bounds {
|
||||
Some(ref x) => x.clean(),
|
||||
None => Vec::new()
|
||||
},
|
||||
bounds: self.bounds.clean()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -909,7 +914,7 @@ impl Clean<RetStyle> for ast::RetStyle {
|
||||
pub struct Trait {
|
||||
pub items: Vec<TraitItem>,
|
||||
pub generics: Generics,
|
||||
pub parents: Vec<Type>,
|
||||
pub bounds: Vec<TyParamBound>,
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Trait {
|
||||
@ -924,7 +929,7 @@ impl Clean<Item> for doctree::Trait {
|
||||
inner: TraitItem(Trait {
|
||||
items: self.items.clean(),
|
||||
generics: self.generics.clean(),
|
||||
parents: self.parents.clean(),
|
||||
bounds: self.bounds.clean(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -1060,7 +1065,7 @@ pub enum Type {
|
||||
Self(ast::DefId),
|
||||
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
|
||||
Primitive(Primitive),
|
||||
Closure(Box<ClosureDecl>, Option<Lifetime>),
|
||||
Closure(Box<ClosureDecl>),
|
||||
Proc(Box<ClosureDecl>),
|
||||
/// extern "ABI" fn
|
||||
BareFunction(Box<BareFunctionDecl>),
|
||||
@ -1208,7 +1213,7 @@ impl Clean<Type> for ast::Ty {
|
||||
tpbs.clean().map(|x| x),
|
||||
id)
|
||||
}
|
||||
TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
|
||||
TyClosure(ref c) => Closure(box c.clean()),
|
||||
TyProc(ref c) => Proc(box c.clean()),
|
||||
TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
|
||||
TyParen(ref ty) => ty.clean(),
|
||||
@ -1273,11 +1278,11 @@ impl Clean<Type> for ty::t {
|
||||
decl: (ast_util::local_def(0), &fty.sig).clean(),
|
||||
onceness: fty.onceness,
|
||||
fn_style: fty.fn_style,
|
||||
bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
|
||||
bounds: fty.bounds.clean(),
|
||||
};
|
||||
match fty.store {
|
||||
ty::UniqTraitStore => Proc(decl),
|
||||
ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
|
||||
ty::RegionTraitStore(..) => Closure(decl),
|
||||
}
|
||||
}
|
||||
ty::ty_struct(did, ref substs) |
|
||||
|
@ -156,7 +156,7 @@ pub struct Trait {
|
||||
pub name: Ident,
|
||||
pub items: Vec<ast::TraitItem>, //should be TraitItem
|
||||
pub generics: ast::Generics,
|
||||
pub parents: Vec<ast::TraitRef>,
|
||||
pub bounds: Vec<ast::TyParamBound>,
|
||||
pub attrs: Vec<ast::Attribute>,
|
||||
pub id: ast::NodeId,
|
||||
pub whence: Span,
|
||||
|
@ -355,7 +355,7 @@ impl fmt::Show for clean::Type {
|
||||
}
|
||||
clean::Self(..) => f.write("Self".as_bytes()),
|
||||
clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
|
||||
clean::Closure(ref decl, ref region) => {
|
||||
clean::Closure(ref decl) => {
|
||||
write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
|
||||
style = FnStyleSpace(decl.fn_style),
|
||||
lifetimes = if decl.lifetimes.len() == 0 {
|
||||
@ -370,13 +370,6 @@ impl fmt::Show for clean::Type {
|
||||
},
|
||||
bounds = {
|
||||
let mut ret = String::new();
|
||||
match *region {
|
||||
Some(ref lt) => {
|
||||
ret.push_str(format!(": {}",
|
||||
*lt).as_slice());
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
for bound in decl.bounds.iter() {
|
||||
match *bound {
|
||||
clean::RegionBound => {}
|
||||
|
@ -1610,12 +1610,12 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
|
||||
fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
t: &clean::Trait) -> fmt::Result {
|
||||
let mut parents = String::new();
|
||||
if t.parents.len() > 0 {
|
||||
parents.push_str(": ");
|
||||
for (i, p) in t.parents.iter().enumerate() {
|
||||
if i > 0 { parents.push_str(" + "); }
|
||||
parents.push_str(format!("{}", *p).as_slice());
|
||||
let mut bounds = String::new();
|
||||
if t.bounds.len() > 0 {
|
||||
bounds.push_str(": ");
|
||||
for (i, p) in t.bounds.iter().enumerate() {
|
||||
if i > 0 { bounds.push_str(" + "); }
|
||||
bounds.push_str(format!("{}", *p).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1624,7 +1624,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
VisSpace(it.visibility),
|
||||
it.name.get_ref().as_slice(),
|
||||
t.generics,
|
||||
parents));
|
||||
bounds));
|
||||
let required = t.items.iter()
|
||||
.filter(|m| {
|
||||
match **m {
|
||||
|
@ -317,12 +317,12 @@ impl<'a> RustdocVisitor<'a> {
|
||||
};
|
||||
om.statics.push(s);
|
||||
},
|
||||
ast::ItemTrait(ref gen, _, ref tr, ref items) => {
|
||||
ast::ItemTrait(ref gen, _, ref b, ref items) => {
|
||||
let t = Trait {
|
||||
name: item.ident,
|
||||
items: items.iter().map(|x| (*x).clone()).collect(),
|
||||
generics: gen.clone(),
|
||||
parents: tr.iter().map(|x| (*x).clone()).collect(),
|
||||
bounds: b.iter().map(|x| (*x).clone()).collect(),
|
||||
id: item.id,
|
||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||
whence: item.span,
|
||||
|
@ -26,7 +26,8 @@ pub struct Exclusive<T> {
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
/// An RAII guard returned via `lock`
|
||||
/// stage0 only
|
||||
#[cfg(stage0)]
|
||||
pub struct ExclusiveGuard<'a, T> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
@ -34,6 +35,15 @@ pub struct ExclusiveGuard<'a, T> {
|
||||
_guard: mutex::LockGuard<'a>,
|
||||
}
|
||||
|
||||
/// An RAII guard returned via `lock`
|
||||
#[cfg(not(stage0))]
|
||||
pub struct ExclusiveGuard<'a, T:'a> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_data: &'a mut T,
|
||||
_guard: mutex::LockGuard<'a>,
|
||||
}
|
||||
|
||||
impl<T: Send> Exclusive<T> {
|
||||
/// Creates a new `Exclusive` which will protect the data provided.
|
||||
pub fn new(user_data: T) -> Exclusive<T> {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
|
||||
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
|
||||
#![feature(import_shadowing)]
|
||||
#![feature(issue_5723_bootstrap)]
|
||||
#![no_std]
|
||||
#![experimental]
|
||||
|
||||
@ -98,7 +99,7 @@ pub trait Runtime {
|
||||
fn can_block(&self) -> bool;
|
||||
|
||||
// FIXME: This is a serious code smell and this should not exist at all.
|
||||
fn wrap(self: Box<Self>) -> Box<Any>;
|
||||
fn wrap(self: Box<Self>) -> Box<Any+'static>;
|
||||
}
|
||||
|
||||
/// The default error code of the rust runtime if the main task fails instead
|
||||
|
@ -144,6 +144,16 @@ unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
|
||||
///
|
||||
/// The task-local data can be accessed through this value, and when this
|
||||
/// structure is dropped it will return the borrow on the data.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Ref<T:'static> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_inner: &'static TLDValueBox<T>,
|
||||
_marker: marker::NoSend
|
||||
}
|
||||
|
||||
/// stage0 only
|
||||
#[cfg(stage0)]
|
||||
pub struct Ref<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
|
@ -120,7 +120,7 @@ pub struct ProcessConfig<'a> {
|
||||
}
|
||||
|
||||
pub struct LocalIo<'a> {
|
||||
factory: &'a mut IoFactory,
|
||||
factory: &'a mut IoFactory+'a,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
@ -174,7 +174,7 @@ impl<'a> LocalIo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> {
|
||||
pub fn new<'a>(io: &'a mut IoFactory+'a) -> LocalIo<'a> {
|
||||
LocalIo { factory: io }
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ pub struct Task {
|
||||
pub name: Option<SendStr>,
|
||||
|
||||
state: TaskState,
|
||||
imp: Option<Box<Runtime + Send>>,
|
||||
imp: Option<Box<Runtime + Send + 'static>>,
|
||||
}
|
||||
|
||||
// Once a task has entered the `Armed` state it must be destroyed via `drop`,
|
||||
@ -353,14 +353,14 @@ impl Task {
|
||||
/// Inserts a runtime object into this task, transferring ownership to the
|
||||
/// task. It is illegal to replace a previous runtime object in this task
|
||||
/// with this argument.
|
||||
pub fn put_runtime(&mut self, ops: Box<Runtime + Send>) {
|
||||
pub fn put_runtime(&mut self, ops: Box<Runtime + Send + 'static>) {
|
||||
assert!(self.imp.is_none());
|
||||
self.imp = Some(ops);
|
||||
}
|
||||
|
||||
/// Removes the runtime from this task, transferring ownership to the
|
||||
/// caller.
|
||||
pub fn take_runtime(&mut self) -> Box<Runtime + Send> {
|
||||
pub fn take_runtime(&mut self) -> Box<Runtime + Send + 'static> {
|
||||
assert!(self.imp.is_some());
|
||||
self.imp.take().unwrap()
|
||||
}
|
||||
@ -390,7 +390,7 @@ impl Task {
|
||||
Ok(t) => Some(t),
|
||||
Err(t) => {
|
||||
let data = mem::transmute::<_, raw::TraitObject>(t).data;
|
||||
let obj: Box<Runtime + Send> =
|
||||
let obj: Box<Runtime + Send + 'static> =
|
||||
mem::transmute(raw::TraitObject {
|
||||
vtable: vtable,
|
||||
data: data,
|
||||
|
@ -26,11 +26,18 @@ pub struct Access<T> {
|
||||
inner: Arc<UnsafeCell<Inner<T>>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub struct Guard<'a, T> {
|
||||
access: &'a mut Access<T>,
|
||||
missile: Option<HomingMissile>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Guard<'a, T:'static> {
|
||||
access: &'a mut Access<T>,
|
||||
missile: Option<HomingMissile>,
|
||||
}
|
||||
|
||||
struct Inner<T> {
|
||||
queue: Vec<(BlockedTask, uint)>,
|
||||
held: bool,
|
||||
|
@ -28,12 +28,20 @@ pub struct AccessTimeout<T> {
|
||||
pub access: access::Access<T>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub struct Guard<'a, T> {
|
||||
state: &'a mut TimeoutState,
|
||||
pub access: access::Guard<'a, T>,
|
||||
pub can_timeout: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Guard<'a, T:'static> {
|
||||
state: &'a mut TimeoutState,
|
||||
pub access: access::Guard<'a, T>,
|
||||
pub can_timeout: bool,
|
||||
}
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
enum TimeoutState {
|
||||
NoTimeout,
|
||||
|
@ -382,7 +382,7 @@ fn fmt_number_or_null(v: f64) -> String {
|
||||
|
||||
/// A structure for implementing serialization to JSON.
|
||||
pub struct Encoder<'a> {
|
||||
writer: &'a mut io::Writer,
|
||||
writer: &'a mut io::Writer+'a,
|
||||
}
|
||||
|
||||
impl<'a> Encoder<'a> {
|
||||
@ -594,7 +594,7 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
|
||||
/// Another encoder for JSON, but prints out human-readable JSON instead of
|
||||
/// compact data
|
||||
pub struct PrettyEncoder<'a> {
|
||||
writer: &'a mut io::Writer,
|
||||
writer: &'a mut io::Writer+'a,
|
||||
curr_indent: uint,
|
||||
indent: uint,
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ Core encoding and decoding interfaces.
|
||||
html_root_url = "http://doc.rust-lang.org/master/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
|
||||
#![feature(issue_5723_bootstrap)]
|
||||
|
||||
// test harness access
|
||||
#[cfg(test)]
|
||||
|
@ -409,20 +409,38 @@ mod table {
|
||||
assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
|
||||
}
|
||||
|
||||
/// Iterator over shared references to entries in a table.
|
||||
/// Note: stage0-specific version that lacks bound.
|
||||
#[cfg(stage0)]
|
||||
pub struct Entries<'a, K, V> {
|
||||
table: &'a RawTable<K, V>,
|
||||
idx: uint,
|
||||
elems_seen: uint,
|
||||
}
|
||||
|
||||
/// Iterator over mutable references to entries in a table.
|
||||
/// Iterator over shared references to entries in a table.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Entries<'a, K:'a, V:'a> {
|
||||
table: &'a RawTable<K, V>,
|
||||
idx: uint,
|
||||
elems_seen: uint,
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound.
|
||||
#[cfg(stage0)]
|
||||
pub struct MutEntries<'a, K, V> {
|
||||
table: &'a mut RawTable<K, V>,
|
||||
idx: uint,
|
||||
elems_seen: uint,
|
||||
}
|
||||
|
||||
/// Iterator over mutable references to entries in a table.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct MutEntries<'a, K:'a, V:'a> {
|
||||
table: &'a mut RawTable<K, V>,
|
||||
idx: uint,
|
||||
elems_seen: uint,
|
||||
}
|
||||
|
||||
/// Iterator over the entries in a table, consuming the table.
|
||||
pub struct MoveEntries<K, V> {
|
||||
table: RawTable<K, V>,
|
||||
|
@ -37,10 +37,29 @@ use ptr::RawPtr;
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(stage0)]
|
||||
pub struct Bytes<'r, T> {
|
||||
reader: &'r mut T,
|
||||
}
|
||||
|
||||
/// An iterator that reads a single byte on each iteration,
|
||||
/// until `.read_byte()` returns `EndOfFile`.
|
||||
///
|
||||
/// # Notes about the Iteration Protocol
|
||||
///
|
||||
/// The `Bytes` may yield `None` and thus terminate
|
||||
/// an iteration, but continue to yield elements if iteration
|
||||
/// is attempted again.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Bytes<'r, T:'r> {
|
||||
reader: &'r mut T,
|
||||
}
|
||||
|
||||
impl<'r, R: Reader> Bytes<'r, R> {
|
||||
/// Constructs a new byte iterator from the given Reader instance.
|
||||
pub fn new(r: &'r mut R) -> Bytes<'r, R> {
|
||||
|
@ -945,11 +945,11 @@ pub trait Reader {
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for Box<Reader> {
|
||||
impl Reader for Box<Reader+'static> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
|
||||
}
|
||||
|
||||
impl<'a> Reader for &'a mut Reader {
|
||||
impl<'a> Reader for &'a mut Reader+'a {
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
|
||||
}
|
||||
|
||||
@ -976,6 +976,13 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
|
||||
})
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound.
|
||||
#[cfg(stage0)]
|
||||
pub struct RefReader<'a, R> {
|
||||
/// The underlying reader which this is referencing
|
||||
inner: &'a mut R
|
||||
}
|
||||
|
||||
/// A `RefReader` is a struct implementing `Reader` which contains a reference
|
||||
/// to another reader. This is often useful when composing streams.
|
||||
///
|
||||
@ -1000,7 +1007,8 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
|
||||
///
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct RefReader<'a, R> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RefReader<'a, R:'a> {
|
||||
/// The underlying reader which this is referencing
|
||||
inner: &'a mut R
|
||||
}
|
||||
@ -1058,12 +1066,21 @@ pub trait Writer {
|
||||
///
|
||||
/// This function will return any I/O error reported while formatting.
|
||||
fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
|
||||
// Create a shim which translates a Writer to a FormatWriter and saves
|
||||
// off I/O errors. instead of discarding them
|
||||
// Note: stage0-specific version that lacks bound.
|
||||
#[cfg(stage0)]
|
||||
struct Adaptor<'a, T> {
|
||||
inner: &'a mut T,
|
||||
error: IoResult<()>,
|
||||
}
|
||||
|
||||
// Create a shim which translates a Writer to a FormatWriter and saves
|
||||
// off I/O errors. instead of discarding them
|
||||
#[cfg(not(stage0))]
|
||||
struct Adaptor<'a, T:'a> {
|
||||
inner: &'a mut T,
|
||||
error: IoResult<()>,
|
||||
}
|
||||
|
||||
impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
|
||||
fn write(&mut self, bytes: &[u8]) -> fmt::Result {
|
||||
match self.inner.write(bytes) {
|
||||
@ -1278,7 +1295,7 @@ pub trait Writer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Writer for Box<Writer> {
|
||||
impl Writer for Box<Writer+'static> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
|
||||
|
||||
@ -1286,7 +1303,7 @@ impl Writer for Box<Writer> {
|
||||
fn flush(&mut self) -> IoResult<()> { self.flush() }
|
||||
}
|
||||
|
||||
impl<'a> Writer for &'a mut Writer {
|
||||
impl<'a> Writer for &'a mut Writer+'a {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
|
||||
|
||||
@ -1318,11 +1335,42 @@ impl<'a> Writer for &'a mut Writer {
|
||||
/// println!("input processed: {}", output.unwrap());
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(stage0)]
|
||||
pub struct RefWriter<'a, W> {
|
||||
/// The underlying writer which this is referencing
|
||||
inner: &'a mut W
|
||||
}
|
||||
|
||||
/// A `RefWriter` is a struct implementing `Writer` which contains a reference
|
||||
/// to another writer. This is often useful when composing streams.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() {}
|
||||
/// # fn process_input<R: Reader>(r: R) {}
|
||||
/// # fn foo () {
|
||||
/// use std::io::util::TeeReader;
|
||||
/// use std::io::{stdin, MemWriter};
|
||||
///
|
||||
/// let mut output = MemWriter::new();
|
||||
///
|
||||
/// {
|
||||
/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a
|
||||
/// // handle to it in the outer scope
|
||||
/// let mut tee = TeeReader::new(stdin(), output.by_ref());
|
||||
/// process_input(tee);
|
||||
/// }
|
||||
///
|
||||
/// println!("input processed: {}", output.unwrap());
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(stage0))]
|
||||
pub struct RefWriter<'a, W:'a> {
|
||||
/// The underlying writer which this is referencing
|
||||
inner: &'a mut W
|
||||
}
|
||||
|
||||
impl<'a, W: Writer> Writer for RefWriter<'a, W> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
|
||||
@ -1351,10 +1399,29 @@ impl<T: Reader + Writer> Stream for T {}
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(stage0)]
|
||||
pub struct Lines<'r, T> {
|
||||
buffer: &'r mut T,
|
||||
}
|
||||
|
||||
/// An iterator that reads a line on each iteration,
|
||||
/// until `.read_line()` encounters `EndOfFile`.
|
||||
///
|
||||
/// # Notes about the Iteration Protocol
|
||||
///
|
||||
/// The `Lines` may yield `None` and thus terminate
|
||||
/// an iteration, but continue to yield elements if iteration
|
||||
/// is attempted again.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Lines<'r, T:'r> {
|
||||
buffer: &'r mut T,
|
||||
}
|
||||
|
||||
impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
|
||||
fn next(&mut self) -> Option<IoResult<String>> {
|
||||
match self.buffer.read_line() {
|
||||
@ -1378,10 +1445,29 @@ impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(stage0)]
|
||||
pub struct Chars<'r, T> {
|
||||
buffer: &'r mut T
|
||||
}
|
||||
|
||||
/// An iterator that reads a utf8-encoded character on each iteration,
|
||||
/// until `.read_char()` encounters `EndOfFile`.
|
||||
///
|
||||
/// # Notes about the Iteration Protocol
|
||||
///
|
||||
/// The `Chars` may yield `None` and thus terminate
|
||||
/// an iteration, but continue to yield elements if iteration
|
||||
/// is attempted again.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||
/// is returned by the iterator and should be handled by the caller.
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Chars<'r, T:'r> {
|
||||
buffer: &'r mut T
|
||||
}
|
||||
|
||||
impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
|
||||
fn next(&mut self) -> Option<IoResult<char>> {
|
||||
match self.buffer.read_char() {
|
||||
@ -1611,6 +1697,12 @@ pub trait Acceptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: stage0-specific version that lacks bound on A.
|
||||
#[cfg(stage0)]
|
||||
pub struct IncomingConnections<'a, A> {
|
||||
inc: &'a mut A,
|
||||
}
|
||||
|
||||
/// An infinite iterator over incoming connection attempts.
|
||||
/// Calling `next` will block the task until a connection is attempted.
|
||||
///
|
||||
@ -1618,7 +1710,8 @@ pub trait Acceptor<T> {
|
||||
/// `Some`. The `Some` contains the `IoResult` representing whether the
|
||||
/// connection attempt was successful. A successful connection will be wrapped
|
||||
/// in `Ok`. A failed connection is represented as an `Err`.
|
||||
pub struct IncomingConnections<'a, A> {
|
||||
#[cfg(not(stage0))]
|
||||
pub struct IncomingConnections<'a, A:'a> {
|
||||
inc: &'a mut A,
|
||||
}
|
||||
|
||||
|
@ -126,12 +126,12 @@ impl Buffer for NullReader {
|
||||
/// The `Writer`s are delegated to in order. If any `Writer` returns an error,
|
||||
/// that error is returned immediately and remaining `Writer`s are not called.
|
||||
pub struct MultiWriter {
|
||||
writers: Vec<Box<Writer>>
|
||||
writers: Vec<Box<Writer+'static>>
|
||||
}
|
||||
|
||||
impl MultiWriter {
|
||||
/// Creates a new `MultiWriter`
|
||||
pub fn new(writers: Vec<Box<Writer>>) -> MultiWriter {
|
||||
pub fn new(writers: Vec<Box<Writer+'static>>) -> MultiWriter {
|
||||
MultiWriter { writers: writers }
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,7 @@
|
||||
#![feature(macro_rules, globs, managed_boxes, linkage)]
|
||||
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
||||
#![feature(import_shadowing)]
|
||||
#![feature(issue_5723_bootstrap)]
|
||||
|
||||
// Don't link to std. We are std.
|
||||
#![no_std]
|
||||
|
@ -825,12 +825,20 @@ pub trait GenericPathUnsafe {
|
||||
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
|
||||
}
|
||||
|
||||
/// Helper struct for printing paths with format!()
|
||||
/// Note: stage0-specific version that lacks bound.
|
||||
#[cfg(stage0)]
|
||||
pub struct Display<'a, P> {
|
||||
path: &'a P,
|
||||
filename: bool
|
||||
}
|
||||
|
||||
/// Helper struct for printing paths with format!()
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Display<'a, P:'a> {
|
||||
path: &'a P,
|
||||
filename: bool
|
||||
}
|
||||
|
||||
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.as_maybe_owned().as_slice().fmt(f)
|
||||
|
@ -291,7 +291,7 @@ mod imp {
|
||||
|
||||
struct Context<'a> {
|
||||
idx: int,
|
||||
writer: &'a mut Writer,
|
||||
writer: &'a mut Writer+'a,
|
||||
last_error: Option<IoError>,
|
||||
}
|
||||
|
||||
|
@ -386,6 +386,14 @@ pub struct Receiver<T> {
|
||||
/// whenever `next` is called, waiting for a new message, and `None` will be
|
||||
/// returned when the corresponding channel has hung up.
|
||||
#[unstable]
|
||||
#[cfg(not(stage0))]
|
||||
pub struct Messages<'a, T:'a> {
|
||||
rx: &'a Receiver<T>
|
||||
}
|
||||
|
||||
/// Stage0 only
|
||||
#[cfg(stage0)]
|
||||
#[unstable]
|
||||
pub struct Messages<'a, T> {
|
||||
rx: &'a Receiver<T>
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user