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]
|
#[stable]
|
||||||
impl BoxAny for Box<Any> {
|
impl BoxAny for Box<Any+'static> {
|
||||||
#[inline]
|
#[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>() {
|
if self.is::<T>() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Get the raw representation of the trait object
|
// 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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.pad("Box<Any>")
|
f.pad("Box<Any>")
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,19 +49,29 @@ struct Node<T> {
|
||||||
value: 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> {
|
pub struct Items<'a, T> {
|
||||||
head: &'a Link<T>,
|
head: &'a Link<T>,
|
||||||
tail: Rawlink<Node<T>>,
|
tail: Rawlink<Node<T>>,
|
||||||
nelem: uint,
|
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.
|
// FIXME #11820: the &'a Option<> of the Link stops clone working.
|
||||||
impl<'a, T> Clone for Items<'a, T> {
|
impl<'a, T> Clone for Items<'a, T> {
|
||||||
fn clone(&self) -> Items<'a, T> { *self }
|
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> {
|
pub struct MutItems<'a, T> {
|
||||||
list: &'a mut DList<T>,
|
list: &'a mut DList<T>,
|
||||||
head: Rawlink<Node<T>>,
|
head: Rawlink<Node<T>>,
|
||||||
|
@ -69,7 +79,16 @@ pub struct MutItems<'a, T> {
|
||||||
nelem: uint,
|
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)]
|
#[deriving(Clone)]
|
||||||
pub struct MoveItems<T> {
|
pub struct MoveItems<T> {
|
||||||
list: DList<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> {
|
pub struct Items <'a, T> {
|
||||||
iter: slice::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> {
|
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<(&'a T)> { self.iter.next() }
|
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> {
|
pub struct Items<'a, T> {
|
||||||
lo: uint,
|
lo: uint,
|
||||||
index: uint,
|
index: uint,
|
||||||
|
@ -301,6 +302,15 @@ pub struct Items<'a, T> {
|
||||||
elts: &'a [Option<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> {
|
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<&'a T> {
|
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> {
|
pub struct MutItems<'a, T> {
|
||||||
remaining1: &'a mut [Option<T>],
|
remaining1: &'a mut [Option<T>],
|
||||||
remaining2: &'a mut [Option<T>],
|
remaining2: &'a mut [Option<T>],
|
||||||
nelts: uint,
|
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> {
|
impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(deprecated)] // mut_shift_ref
|
#[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> {
|
pub struct Entries<'a, T> {
|
||||||
front: uint,
|
front: uint,
|
||||||
back: uint,
|
back: uint,
|
||||||
iter: slice::Items<'a, Option<T>>
|
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)
|
iterator!(impl Entries -> (uint, &'a T), get_ref)
|
||||||
double_ended_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
|
/// Forward iterator over the key-value pairs of a map, with the
|
||||||
/// values being mutable.
|
/// values being mutable.
|
||||||
pub struct MutEntries<'a, T> {
|
#[cfg(not(stage0))]
|
||||||
|
pub struct MutEntries<'a, T:'a> {
|
||||||
front: uint,
|
front: uint,
|
||||||
back: uint,
|
back: uint,
|
||||||
iter: slice::MutItems<'a, Option<T>>
|
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> {
|
pub struct Entries<'a, K, V> {
|
||||||
stack: Vec<&'a TreeNode<K, V>>,
|
stack: Vec<&'a TreeNode<K, V>>,
|
||||||
// See the comment on MutEntries; this is just to allow
|
// See the comment on MutEntries; this is just to allow
|
||||||
|
@ -679,13 +680,32 @@ pub struct Entries<'a, K, V> {
|
||||||
remaining_max: uint
|
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> {
|
pub struct RevEntries<'a, K, V> {
|
||||||
iter: Entries<'a, K, V>,
|
iter: Entries<'a, K, V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A lazy forward iterator over a map that allows for the mutation of
|
/// Lazy backward iterator over a map
|
||||||
/// the values.
|
#[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> {
|
pub struct MutEntries<'a, K, V> {
|
||||||
stack: Vec<&'a mut TreeNode<K, V>>,
|
stack: Vec<&'a mut TreeNode<K, V>>,
|
||||||
// Unfortunately, we require some unsafe-ness to get around the
|
// Unfortunately, we require some unsafe-ness to get around the
|
||||||
|
@ -712,11 +732,46 @@ pub struct MutEntries<'a, K, V> {
|
||||||
remaining_max: uint
|
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> {
|
pub struct RevMutEntries<'a, K, V> {
|
||||||
iter: MutEntries<'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.
|
/// TreeMap keys iterator.
|
||||||
pub type Keys<'a, K, V> =
|
pub type Keys<'a, K, V> =
|
||||||
|
@ -885,9 +940,7 @@ fn mut_deref<K, V>(x: &mut Option<Box<TreeNode<K, V>>>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lazy forward iterator over a map that consumes the map while iterating
|
||||||
|
|
||||||
/// A lazy forward iterator over a map that consumes the map while iterating.
|
|
||||||
pub struct MoveEntries<K, V> {
|
pub struct MoveEntries<K, V> {
|
||||||
stack: Vec<TreeNode<K, V>>,
|
stack: Vec<TreeNode<K, V>>,
|
||||||
remaining: uint
|
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> {
|
pub struct SetItems<'a, T> {
|
||||||
iter: Entries<'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> {
|
pub struct RevSetItems<'a, T> {
|
||||||
iter: RevEntries<'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.
|
/// A lazy forward iterator over a set that consumes the set while iterating.
|
||||||
pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
|
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> {
|
pub struct DifferenceItems<'a, T> {
|
||||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||||
b: 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> {
|
pub struct SymDifferenceItems<'a, T> {
|
||||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||||
b: 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> {
|
pub struct IntersectionItems<'a, T> {
|
||||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||||
b: 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> {
|
pub struct UnionItems<'a, T> {
|
||||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||||
b: 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
|
/// A lazy iterator producing elements in the set union (in-order).
|
||||||
/// `None`.
|
#[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>,
|
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
|
||||||
short: Ordering, long: Ordering) -> Ordering {
|
short: Ordering, long: Ordering) -> Ordering {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
|
|
|
@ -857,7 +857,8 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A forward iterator over a map.
|
/// Note: stage0-specific version that lacks bound on A.
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Entries<'a, T> {
|
pub struct Entries<'a, T> {
|
||||||
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
|
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
|
||||||
length: uint,
|
length: uint,
|
||||||
|
@ -865,9 +866,28 @@ pub struct Entries<'a, T> {
|
||||||
remaining_max: uint
|
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
|
/// A forward iterator over the key-value pairs of a map, with the
|
||||||
/// values being mutable.
|
/// 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],
|
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
|
||||||
length: uint,
|
length: uint,
|
||||||
remaining_min: uint,
|
remaining_min: uint,
|
||||||
|
|
|
@ -1620,9 +1620,13 @@ pub struct MoveItems<T> {
|
||||||
|
|
||||||
impl<T> Iterator<T> for MoveItems<T> {
|
impl<T> Iterator<T> for MoveItems<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<T> {
|
fn next<'a>(&'a mut self) -> Option<T> {
|
||||||
unsafe {
|
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> {
|
impl<T> DoubleEndedIterator<T> for MoveItems<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<T> {
|
fn next_back<'a>(&'a mut self) -> Option<T> {
|
||||||
unsafe {
|
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]
|
#[stable]
|
||||||
impl<'a> AnyRefExt<'a> for &'a Any {
|
impl<'a> AnyRefExt<'a> for &'a Any+'a {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable]
|
#[stable]
|
||||||
fn is<T: 'static>(self) -> bool {
|
fn is<T: 'static>(self) -> bool {
|
||||||
|
@ -181,7 +181,7 @@ pub trait AnyMutRefExt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable]
|
#[stable]
|
||||||
impl<'a> AnyMutRefExt<'a> for &'a mut Any {
|
impl<'a> AnyMutRefExt<'a> for &'a mut Any+'a {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable = "naming conventions around acquiring references may change"]
|
#[unstable = "naming conventions around acquiring references may change"]
|
||||||
fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
|
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.
|
/// Wraps a borrowed reference to a value in a `RefCell` box.
|
||||||
#[unstable]
|
#[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> {
|
pub struct Ref<'b, T> {
|
||||||
// FIXME #12808: strange name to try to avoid interfering with
|
// FIXME #12808: strange name to try to avoid interfering with
|
||||||
// field accesses of the contained type via Deref
|
// 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.
|
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
|
||||||
#[unstable]
|
#[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> {
|
pub struct RefMut<'b, T> {
|
||||||
// FIXME #12808: strange name to try to avoid interfering with
|
// FIXME #12808: strange name to try to avoid interfering with
|
||||||
// field accesses of the contained type via Deref
|
// 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)
|
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> {
|
struct Finallyalizer<'a,A> {
|
||||||
mutate: &'a mut A,
|
mutate: &'a mut A,
|
||||||
dtor: |&mut A|: 'a
|
dtor: |&mut A|: 'a
|
||||||
|
|
|
@ -92,7 +92,7 @@ pub struct Formatter<'a> {
|
||||||
/// Optionally specified precision for numeric types
|
/// Optionally specified precision for numeric types
|
||||||
pub precision: Option<uint>,
|
pub precision: Option<uint>,
|
||||||
|
|
||||||
buf: &'a mut FormatWriter,
|
buf: &'a mut FormatWriter+'a,
|
||||||
curarg: slice::Items<'a, Argument<'a>>,
|
curarg: slice::Items<'a, Argument<'a>>,
|
||||||
args: &'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 {
|
impl<'a, T: Show> Show for &'a mut T {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
|
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) }
|
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, }
|
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") }
|
fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -673,7 +673,7 @@ pub trait MutableDoubleEndedIterator {
|
||||||
fn reverse_(&mut self);
|
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`
|
// FIXME: #5898: should be called `reverse`
|
||||||
/// Use an iterator to reverse a container in-place
|
/// Use an iterator to reverse a container in-place
|
||||||
fn reverse_(&mut self) {
|
fn reverse_(&mut self) {
|
||||||
|
@ -777,18 +777,26 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
|
||||||
|
|
||||||
/// A mutable reference to an iterator
|
/// A mutable reference to an iterator
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[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> {
|
pub struct ByRef<'a, T> {
|
||||||
iter: &'a mut 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]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<A> { self.iter.next() }
|
fn next(&mut self) -> Option<A> { self.iter.next() }
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
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]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
|
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
|
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
|
||||||
#![feature(simd, unsafe_destructor)]
|
#![feature(simd, unsafe_destructor, issue_5723_bootstrap)]
|
||||||
#![deny(missing_doc)]
|
#![deny(missing_doc)]
|
||||||
|
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
|
@ -369,7 +369,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable = "this function may be removed in the future due to its \
|
#[unstable = "this function may be removed in the future due to its \
|
||||||
questionable utility"]
|
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)
|
transmute(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable = "this function may be removed in the future due to its \
|
#[unstable = "this function may be removed in the future due to its \
|
||||||
questionable utility"]
|
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 {
|
ptr: &mut T) -> &'a mut T {
|
||||||
transmute(ptr)
|
transmute(ptr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -996,9 +996,6 @@ impl<'a, T> Default for &'a [T] {
|
||||||
fn default() -> &'a [T] { &[] }
|
fn default() -> &'a [T] { &[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Iterators
|
// 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
|
/// An iterator over the slices of a vector separated by elements that
|
||||||
/// match a predicate function.
|
/// match a predicate function.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
#[experimental = "needs review"]
|
#[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> {
|
pub struct Splits<'a, T> {
|
||||||
v: &'a [T],
|
v: &'a [T],
|
||||||
pred: |t: &T|: 'a -> bool,
|
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
|
/// An iterator over the subslices of the vector which are separated
|
||||||
/// by elements that match `pred`.
|
/// by elements that match `pred`.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
#[experimental = "needs review"]
|
#[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> {
|
pub struct MutSplits<'a, T> {
|
||||||
v: &'a mut [T],
|
v: &'a mut [T],
|
||||||
pred: |t: &T|: 'a -> bool,
|
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
|
/// An iterator over the slices of a vector separated by elements that
|
||||||
/// match a predicate function, splitting at most a fixed number of times.
|
/// match a predicate function, splitting at most a fixed number of times.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
#[experimental = "needs review"]
|
#[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> {
|
pub struct SplitsN<'a, T> {
|
||||||
iter: Splits<'a, T>,
|
iter: Splits<'a, T>,
|
||||||
count: uint,
|
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
|
/// An iterator over the (overlapping) slices of length `size` within
|
||||||
/// a vector.
|
/// a vector.
|
||||||
|
#[cfg(stage0)]
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
#[experimental = "needs review"]
|
#[experimental = "needs review"]
|
||||||
pub struct Windows<'a, T> {
|
pub struct Windows<'a, T> {
|
||||||
|
@ -1298,7 +1323,16 @@ pub struct Windows<'a, T> {
|
||||||
size: uint
|
size: uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over the (overlapping) slices of length `size` within
|
||||||
|
/// a vector.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[deriving(Clone)]
|
||||||
#[experimental = "needs review"]
|
#[experimental = "needs review"]
|
||||||
|
pub struct Windows<'a, T:'a> {
|
||||||
|
v: &'a [T],
|
||||||
|
size: uint
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
|
impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<&'a [T]> {
|
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,
|
/// When the vector len is not evenly divided by the chunk size,
|
||||||
/// the last slice of the iteration will be the remainder.
|
/// the last slice of the iteration will be the remainder.
|
||||||
|
#[cfg(stage0)]
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
#[experimental = "needs review"]
|
#[experimental = "needs review"]
|
||||||
pub struct Chunks<'a, T> {
|
pub struct Chunks<'a, T> {
|
||||||
|
@ -1334,6 +1369,18 @@ pub struct Chunks<'a, T> {
|
||||||
size: uint
|
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"]
|
#[experimental = "needs review"]
|
||||||
impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
|
impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
|
||||||
#[inline]
|
#[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
|
/// 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 vector len is not evenly divided by the chunk size, the last slice of the iteration will be
|
||||||
/// the remainder.
|
/// the remainder.
|
||||||
|
#[cfg(not(stage0))]
|
||||||
#[experimental = "needs review"]
|
#[experimental = "needs review"]
|
||||||
|
pub struct MutChunks<'a, T:'a> {
|
||||||
|
v: &'a mut [T],
|
||||||
|
chunk_size: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dox.
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct MutChunks<'a, T> {
|
pub struct MutChunks<'a, T> {
|
||||||
v: &'a mut [T],
|
v: &'a mut [T],
|
||||||
chunk_size: uint
|
chunk_size: uint
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||||
#![experimental]
|
#![experimental]
|
||||||
#![feature(managed_boxes, macro_rules)]
|
#![feature(managed_boxes, macro_rules, issue_5723_bootstrap)]
|
||||||
#![allow(experimental)]
|
#![allow(experimental)]
|
||||||
|
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub struct ReprVisitor<'a> {
|
||||||
ptr: *const u8,
|
ptr: *const u8,
|
||||||
ptr_stk: Vec<*const u8>,
|
ptr_stk: Vec<*const u8>,
|
||||||
var_stk: Vec<VariantState>,
|
var_stk: Vec<VariantState>,
|
||||||
writer: &'a mut io::Writer,
|
writer: &'a mut io::Writer+'a,
|
||||||
last_err: Option<io::IoError>,
|
last_err: Option<io::IoError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
reg.register_macro("fourcc", expand_syntax_ext);
|
reg.register_macro("fourcc", expand_syntax_ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||||
-> Box<base::MacResult> {
|
-> Box<base::MacResult+'cx> {
|
||||||
let (expr, endian) = parse_tts(cx, tts);
|
let (expr, endian) = parse_tts(cx, tts);
|
||||||
|
|
||||||
let little = match endian {
|
let little = match endian {
|
||||||
|
|
|
@ -271,6 +271,7 @@ pub fn main() {
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
#![crate_type = "dylib"]
|
#![crate_type = "dylib"]
|
||||||
#![license = "MIT/ASL2"]
|
#![license = "MIT/ASL2"]
|
||||||
|
#![feature(issue_5723_bootstrap)]
|
||||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
#![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_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
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.
|
/// Renders directed graph `g` into the writer `w` in DOT syntax.
|
||||||
/// (Main entry point for the library.)
|
/// (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,
|
g: &'a G,
|
||||||
w: &mut W) -> io::IoResult<()>
|
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
|
/// 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
|
/// a slice; others will want to create the set on the fly and hand
|
||||||
/// off ownership, via `Growable`.
|
/// 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> {
|
pub enum MaybeOwnedVector<'a,T> {
|
||||||
Growable(Vec<T>),
|
Growable(Vec<T>),
|
||||||
Borrowed(&'a [T]),
|
Borrowed(&'a [T]),
|
||||||
|
@ -45,7 +53,7 @@ pub trait IntoMaybeOwnedVector<'a,T> {
|
||||||
fn into_maybe_owned(self) -> MaybeOwnedVector<'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]
|
#[inline]
|
||||||
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
|
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 local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
|
||||||
fn stack_bounds(&self) -> (uint, uint) { fail!() }
|
fn stack_bounds(&self) -> (uint, uint) { fail!() }
|
||||||
fn can_block(&self) -> bool { true }
|
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> {
|
pub fn task() -> Box<Task> {
|
||||||
|
|
|
@ -488,7 +488,9 @@ impl Runtime for GreenTask {
|
||||||
|
|
||||||
fn can_block(&self) -> bool { false }
|
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)]
|
#[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])
|
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 (expr, ty_lit) = parse_tts(cx, tts);
|
||||||
|
|
||||||
let ty = match ty_lit {
|
let ty = match ty_lit {
|
||||||
|
|
|
@ -145,8 +145,8 @@ impl rt::Runtime for Ops {
|
||||||
Local::put(cur_task);
|
Local::put(cur_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap(self: Box<Ops>) -> Box<Any> {
|
fn wrap(self: Box<Ops>) -> Box<Any+'static> {
|
||||||
self as Box<Any>
|
self as Box<Any+'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }
|
fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }
|
||||||
|
|
|
@ -79,6 +79,13 @@ pub struct Weighted<T> {
|
||||||
pub item: 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.
|
/// A distribution that selects from a finite collection of weighted items.
|
||||||
///
|
///
|
||||||
/// Each item has an associated weight that influences how likely it
|
/// 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));
|
/// 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>],
|
items: &'a mut [Weighted<T>],
|
||||||
weight_range: Range<uint>
|
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.
|
/// Iterator which will generate a stream of random items.
|
||||||
///
|
///
|
||||||
/// This iterator is created via the `gen_iter` method on `Rng`.
|
/// 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,
|
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.
|
/// Iterator which will continuously generate random ascii characters.
|
||||||
///
|
///
|
||||||
/// This iterator is created via the `gen_ascii_chars` method on `Rng`.
|
/// 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,
|
rng: &'a mut R,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
html_root_url = "http://doc.rust-lang.org/master/",
|
html_root_url = "http://doc.rust-lang.org/master/",
|
||||||
html_playground_url = "http://play.rust-lang.org/")]
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
#![feature(macro_rules, phase)]
|
#![feature(macro_rules, phase, issue_5723_bootstrap)]
|
||||||
#![allow(missing_doc)]
|
#![allow(missing_doc)]
|
||||||
|
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
@ -662,11 +662,19 @@ pub mod writer {
|
||||||
pub type EncodeResult = io::IoResult<()>;
|
pub type EncodeResult = io::IoResult<()>;
|
||||||
|
|
||||||
// rbml writing
|
// rbml writing
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Encoder<'a, W> {
|
pub struct Encoder<'a, W> {
|
||||||
pub writer: &'a mut W,
|
pub writer: &'a mut W,
|
||||||
size_positions: Vec<uint>,
|
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 {
|
fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
|
||||||
match size {
|
match size {
|
||||||
1u => w.write(&[0x80u8 | (n as u8)]),
|
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.
|
/// strategy is identical and vm.rs has comments and will be easier to follow.
|
||||||
#[allow(experimental)]
|
#[allow(experimental)]
|
||||||
fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
|
fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
|
||||||
-> Box<MacResult> {
|
-> Box<MacResult+'static> {
|
||||||
let regex = match parse(cx, tts) {
|
let regex = match parse(cx, tts) {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
// error is logged in 'parse' with cx.span_err
|
// 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 mut rdr = MemReader::new(src);
|
||||||
|
|
||||||
let out = match ofile {
|
let out = match ofile {
|
||||||
None => box io::stdout() as Box<Writer>,
|
None => box io::stdout() as Box<Writer+'static>,
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
let r = io::File::create(&p);
|
let r = io::File::create(&p);
|
||||||
match r {
|
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 {}",
|
Err(e) => fail!("print-print failed to open {} due to {}",
|
||||||
p.display(), e),
|
p.display(), e),
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
|
|
||||||
// A temporary feature gate used to enable parser extensions needed
|
// A temporary feature gate used to enable parser extensions needed
|
||||||
// to bootstrap fix for #5723.
|
// 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
|
// These are used to test this portion of the compiler, they don't actually
|
||||||
// mean anything
|
// mean anything
|
||||||
|
@ -97,7 +97,6 @@ enum Status {
|
||||||
/// A set of features to be used by later passes.
|
/// A set of features to be used by later passes.
|
||||||
pub struct Features {
|
pub struct Features {
|
||||||
pub default_type_params: Cell<bool>,
|
pub default_type_params: Cell<bool>,
|
||||||
pub issue_5723_bootstrap: Cell<bool>,
|
|
||||||
pub overloaded_calls: Cell<bool>,
|
pub overloaded_calls: Cell<bool>,
|
||||||
pub rustc_diagnostic_macros: Cell<bool>,
|
pub rustc_diagnostic_macros: Cell<bool>,
|
||||||
pub import_shadowing: Cell<bool>,
|
pub import_shadowing: Cell<bool>,
|
||||||
|
@ -107,7 +106,6 @@ impl Features {
|
||||||
pub fn new() -> Features {
|
pub fn new() -> Features {
|
||||||
Features {
|
Features {
|
||||||
default_type_params: Cell::new(false),
|
default_type_params: Cell::new(false),
|
||||||
issue_5723_bootstrap: Cell::new(false),
|
|
||||||
overloaded_calls: Cell::new(false),
|
overloaded_calls: Cell::new(false),
|
||||||
rustc_diagnostic_macros: Cell::new(false),
|
rustc_diagnostic_macros: Cell::new(false),
|
||||||
import_shadowing: 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, _: ()) {
|
fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
|
||||||
match t.node {
|
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,
|
self.gate_feature("once_fns", t.span,
|
||||||
"once functions are \
|
"once functions are \
|
||||||
experimental and likely to be removed");
|
experimental and likely to be removed");
|
||||||
|
@ -439,7 +437,6 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
|
||||||
sess.abort_if_errors();
|
sess.abort_if_errors();
|
||||||
|
|
||||||
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
|
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.overloaded_calls.set(cx.has_feature("overloaded_calls"));
|
||||||
sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
|
sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
|
||||||
sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));
|
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)]
|
#![allow(deprecated)]
|
||||||
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
|
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
|
||||||
#![feature(default_type_params, phase, unsafe_destructor)]
|
#![feature(default_type_params, phase, unsafe_destructor)]
|
||||||
|
#![feature(issue_5723_bootstrap)]
|
||||||
|
|
||||||
#![allow(unknown_features)] // NOTE: Remove after next snapshot
|
#![allow(unknown_features)] // NOTE: Remove after next snapshot
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![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_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_type: uint = 0x07;
|
||||||
|
|
||||||
pub static tag_items_data_item_symbol: uint = 0x08;
|
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_item_unnamed_field: uint = 0x75;
|
||||||
pub static tag_items_data_item_visibility: uint = 0x76;
|
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_tps: uint = 0x79;
|
||||||
pub static tag_item_method_fty: uint = 0x7a;
|
pub static tag_item_method_fty: uint = 0x7a;
|
||||||
|
@ -222,12 +219,6 @@ pub struct LinkMeta {
|
||||||
pub crate_hash: Svh,
|
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_closures: uint = 0x95;
|
||||||
pub static tag_unboxed_closure: uint = 0x96;
|
pub static tag_unboxed_closure: uint = 0x96;
|
||||||
pub static tag_unboxed_closure_type: uint = 0x97;
|
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_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::StaticMethodInfo;
|
||||||
use metadata::csearch;
|
use metadata::csearch;
|
||||||
use metadata::cstore;
|
use metadata::cstore;
|
||||||
use metadata::tydecode::{parse_ty_data, parse_def_id};
|
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
|
||||||
use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data};
|
parse_type_param_def_data, parse_bounds_data,
|
||||||
use metadata::tydecode::{parse_trait_ref_data};
|
parse_bare_fn_ty_data, parse_trait_ref_data};
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
use middle::resolve::TraitItemKind;
|
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)
|
doc_trait_ref(tp, tcx, cdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_ty_param_defs(item: rbml::Doc,
|
fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
|
||||||
tcx: &ty::ctxt,
|
parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
|
||||||
cdata: Cmd,
|
|_, did| translate_def_id(cdata, did))
|
||||||
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 item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd)
|
fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
|
||||||
-> subst::VecPerParamSpace<ty::RegionParameterDef>
|
let d = reader::get_doc(doc, tag_trait_def_bounds);
|
||||||
{
|
doc_bounds(d, tcx, cdata)
|
||||||
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 enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
|
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
|
tcx: &ty::ctxt) -> ty::TraitDef
|
||||||
{
|
{
|
||||||
let item_doc = lookup_item(item_id, cdata.data());
|
let item_doc = lookup_item(item_id, cdata.data());
|
||||||
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
|
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
|
||||||
tag_items_data_item_ty_param_bounds);
|
let bounds = trait_def_bounds(item_doc, tcx, cdata);
|
||||||
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
|
|
||||||
});
|
|
||||||
|
|
||||||
ty::TraitDef {
|
ty::TraitDef {
|
||||||
generics: ty::Generics {types: tp_defs,
|
generics: generics,
|
||||||
regions: rp_defs},
|
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
|
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,
|
let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
|
||||||
cdata);
|
cdata);
|
||||||
|
|
||||||
let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
|
let generics = doc_generics(item, tcx, cdata, tag_item_generics);
|
||||||
let rp_defs = item_region_param_defs(item, cdata);
|
|
||||||
|
|
||||||
ty::Polytype {
|
ty::Polytype {
|
||||||
generics: ty::Generics {types: tp_defs,
|
generics: generics,
|
||||||
regions: rp_defs},
|
|
||||||
ty: t
|
ty: t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,6 +745,7 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
|
||||||
tcx: &ty::ctxt)
|
tcx: &ty::ctxt)
|
||||||
-> ty::ImplOrTraitItem {
|
-> ty::ImplOrTraitItem {
|
||||||
let method_doc = lookup_item(id, cdata.data());
|
let method_doc = lookup_item(id, cdata.data());
|
||||||
|
|
||||||
let def_id = item_def_id(method_doc, cdata);
|
let def_id = item_def_id(method_doc, cdata);
|
||||||
|
|
||||||
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
|
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) {
|
match item_sort(method_doc) {
|
||||||
'r' | 'p' => {
|
'r' | 'p' => {
|
||||||
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
|
let generics = doc_generics(method_doc, tcx, cdata,
|
||||||
tag_item_method_tps);
|
tag_method_ty_generics);
|
||||||
let rp_defs = item_region_param_defs(method_doc, cdata);
|
|
||||||
let fty = doc_method_fty(method_doc, tcx, cdata);
|
let fty = doc_method_fty(method_doc, tcx, cdata);
|
||||||
let vis = item_visibility(method_doc);
|
let vis = item_visibility(method_doc);
|
||||||
let explicit_self = get_explicit_self(method_doc);
|
let explicit_self = get_explicit_self(method_doc);
|
||||||
let provided_source = get_provided_source(method_doc, cdata);
|
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,
|
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
|
||||||
generics,
|
generics,
|
||||||
fty,
|
fty,
|
||||||
|
@ -1392,3 +1339,57 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
|
||||||
_ => false,
|
_ => 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::cstore;
|
||||||
use metadata::decoder;
|
use metadata::decoder;
|
||||||
use metadata::tyencode;
|
use metadata::tyencode;
|
||||||
use middle::subst::VecPerParamSpace;
|
use middle::ty::{lookup_item_type};
|
||||||
use middle::ty::{node_id_to_type, lookup_item_type};
|
|
||||||
use middle::astencode;
|
use middle::astencode;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
|
@ -150,45 +149,6 @@ pub fn def_to_string(did: DefId) -> String {
|
||||||
format!("{}:{}", did.krate, did.node)
|
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,
|
fn encode_item_variances(rbml_w: &mut Encoder,
|
||||||
ecx: &EncodeContext,
|
ecx: &EncodeContext,
|
||||||
id: ast::NodeId) {
|
id: ast::NodeId) {
|
||||||
|
@ -201,9 +161,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
|
||||||
fn encode_bounds_and_type(rbml_w: &mut Encoder,
|
fn encode_bounds_and_type(rbml_w: &mut Encoder,
|
||||||
ecx: &EncodeContext,
|
ecx: &EncodeContext,
|
||||||
pty: &ty::Polytype) {
|
pty: &ty::Polytype) {
|
||||||
encode_ty_type_param_defs(rbml_w, ecx, &pty.generics.types,
|
encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
|
||||||
tag_items_data_item_ty_param_bounds);
|
|
||||||
encode_region_param_defs(rbml_w, &pty.generics.regions);
|
|
||||||
encode_type(ecx, rbml_w, pty.ty);
|
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);
|
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,
|
fn encode_type(ecx: &EncodeContext,
|
||||||
rbml_w: &mut Encoder,
|
rbml_w: &mut Encoder,
|
||||||
typ: ty::t) {
|
typ: ty::t) {
|
||||||
|
@ -246,6 +231,14 @@ fn encode_type(ecx: &EncodeContext,
|
||||||
rbml_w.end_tag();
|
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,
|
fn encode_method_fty(ecx: &EncodeContext,
|
||||||
rbml_w: &mut Encoder,
|
rbml_w: &mut Encoder,
|
||||||
typ: &ty::BareFnTy) {
|
typ: &ty::BareFnTy) {
|
||||||
|
@ -728,7 +721,6 @@ fn encode_info_for_struct(ecx: &EncodeContext,
|
||||||
/* Each class has its own index, since different classes
|
/* Each class has its own index, since different classes
|
||||||
may have fields with the same name */
|
may have fields with the same name */
|
||||||
let mut index = Vec::new();
|
let mut index = Vec::new();
|
||||||
let tcx = ecx.tcx;
|
|
||||||
/* We encode both private and public fields -- need to include
|
/* We encode both private and public fields -- need to include
|
||||||
private fields to get the offsets right */
|
private fields to get the offsets right */
|
||||||
for field in fields.iter() {
|
for field in fields.iter() {
|
||||||
|
@ -745,7 +737,8 @@ fn encode_info_for_struct(ecx: &EncodeContext,
|
||||||
token::get_name(nm), id);
|
token::get_name(nm), id);
|
||||||
encode_struct_field_family(rbml_w, field.vis);
|
encode_struct_field_family(rbml_w, field.vis);
|
||||||
encode_name(rbml_w, nm);
|
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));
|
encode_def_id(rbml_w, local_def(id));
|
||||||
|
|
||||||
let stab = stability::lookup(ecx.tcx, field.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,
|
encode_bounds_and_type(rbml_w, ecx,
|
||||||
&lookup_item_type(ecx.tcx, local_def(ctor_id)));
|
&lookup_item_type(ecx.tcx, local_def(ctor_id)));
|
||||||
encode_name(rbml_w, name.name);
|
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));
|
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
|
||||||
encode_parent_item(rbml_w, local_def(struct_id));
|
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();
|
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,
|
fn encode_method_ty_fields(ecx: &EncodeContext,
|
||||||
rbml_w: &mut Encoder,
|
rbml_w: &mut Encoder,
|
||||||
method_ty: &ty::Method) {
|
method_ty: &ty::Method) {
|
||||||
encode_def_id(rbml_w, method_ty.def_id);
|
encode_def_id(rbml_w, method_ty.def_id);
|
||||||
encode_name(rbml_w, method_ty.ident.name);
|
encode_name(rbml_w, method_ty.ident.name);
|
||||||
encode_ty_type_param_defs(rbml_w, ecx, &method_ty.generics.types,
|
encode_generics(rbml_w, ecx, &method_ty.generics,
|
||||||
tag_item_method_tps);
|
tag_method_ty_generics);
|
||||||
encode_method_fty(ecx, rbml_w, &method_ty.fty);
|
encode_method_fty(ecx, rbml_w, &method_ty.fty);
|
||||||
encode_visibility(rbml_w, method_ty.vis);
|
encode_visibility(rbml_w, method_ty.vis);
|
||||||
encode_explicit_self(rbml_w, &method_ty.explicit_self);
|
encode_explicit_self(rbml_w, &method_ty.explicit_self);
|
||||||
|
@ -982,7 +1021,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||||
} else {
|
} else {
|
||||||
encode_family(rbml_w, 'c');
|
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_symbol(ecx, rbml_w, item.id);
|
||||||
encode_name(rbml_w, item.ident.name);
|
encode_name(rbml_w, item.ident.name);
|
||||||
encode_path(rbml_w, path);
|
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);
|
add_to_index(item, rbml_w, index);
|
||||||
rbml_w.start_tag(tag_items_data_item);
|
rbml_w.start_tag(tag_items_data_item);
|
||||||
encode_def_id(rbml_w, def_id);
|
encode_def_id(rbml_w, def_id);
|
||||||
encode_family(rbml_w, 'I');
|
encode_family(rbml_w, 'I');
|
||||||
encode_item_variances(rbml_w, ecx, item.id);
|
encode_item_variances(rbml_w, ecx, item.id);
|
||||||
let trait_def = ty::lookup_trait_def(tcx, def_id);
|
let trait_def = ty::lookup_trait_def(tcx, def_id);
|
||||||
encode_ty_type_param_defs(rbml_w, ecx,
|
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
|
||||||
&trait_def.generics.types,
|
|
||||||
tag_items_data_item_ty_param_bounds);
|
|
||||||
encode_region_param_defs(rbml_w, &trait_def.generics.regions);
|
|
||||||
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||||
encode_name(rbml_w, item.ident.name);
|
encode_name(rbml_w, item.ident.name);
|
||||||
encode_attributes(rbml_w, item.attrs.as_slice());
|
encode_attributes(rbml_w, item.attrs.as_slice());
|
||||||
|
@ -1253,13 +1289,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||||
rbml_w.end_tag();
|
rbml_w.end_tag();
|
||||||
}
|
}
|
||||||
encode_path(rbml_w, path.clone());
|
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
|
encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
|
||||||
// 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 the implementations of this trait.
|
// Encode the implementations of this trait.
|
||||||
encode_extension_implementations(ecx, rbml_w, def_id);
|
encode_extension_implementations(ecx, rbml_w, def_id);
|
||||||
|
@ -1390,7 +1421,8 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
|
||||||
} else {
|
} else {
|
||||||
encode_family(rbml_w, 'c');
|
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_symbol(ecx, rbml_w, nitem.id);
|
||||||
encode_name(rbml_w, nitem.ident.name);
|
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>,
|
rbml_w_for_visit_item: &'a mut Encoder<'b>,
|
||||||
ecx_ptr:*const int,
|
ecx_ptr:*const int,
|
||||||
index: &'a mut Vec<entry<i64>>,
|
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) {
|
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>,
|
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>,
|
ecx: &'a EncodeContext<'b>,
|
||||||
rbml_w: &'a mut Encoder<'c>,
|
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)
|
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,
|
pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
|
||||||
conv: conv_did) -> ty::BareFnTy {
|
conv: conv_did) -> ty::BareFnTy {
|
||||||
debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
|
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)
|
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> {
|
fn parse_size(st: &mut PState) -> Option<uint> {
|
||||||
assert_eq!(next(st), '/');
|
assert_eq!(next(st), '/');
|
||||||
|
|
||||||
|
@ -355,9 +383,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||||
assert_eq!(next(st), '[');
|
assert_eq!(next(st), '[');
|
||||||
let def = parse_def(st, NominalType, |x,y| conv(x,y));
|
let def = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||||
let substs = parse_substs(st, |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), ']');
|
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' => {
|
'p' => {
|
||||||
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
|
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 fn_style = parse_fn_style(next(st));
|
||||||
let onceness = parse_onceness(next(st));
|
let onceness = parse_onceness(next(st));
|
||||||
let store = parse_trait_store(st, |x,y| conv(x,y));
|
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 sig = parse_sig(st, |x,y| conv(x,y));
|
||||||
let abi = parse_abi_set(st);
|
let abi = parse_abi_set(st);
|
||||||
ty::ClosureTy {
|
ty::ClosureTy {
|
||||||
fn_style: fn_style,
|
fn_style: fn_style,
|
||||||
onceness: onceness,
|
onceness: onceness,
|
||||||
store: store,
|
store: store,
|
||||||
bounds: bounds.builtin_bounds,
|
bounds: bounds,
|
||||||
sig: sig,
|
sig: sig,
|
||||||
abi: abi,
|
abi: abi,
|
||||||
}
|
}
|
||||||
|
@ -601,7 +629,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
|
||||||
assert_eq!(next(st), '|');
|
assert_eq!(next(st), '|');
|
||||||
let index = parse_uint(st);
|
let index = parse_uint(st);
|
||||||
assert_eq!(next(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)));
|
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
|
||||||
|
|
||||||
ty::TypeParameterDef {
|
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 {
|
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 {
|
let mut param_bounds = ty::ParamBounds {
|
||||||
builtin_bounds: ty::empty_builtin_bounds(),
|
opt_region_bound: None,
|
||||||
|
builtin_bounds: builtin_bounds,
|
||||||
trait_bounds: Vec::new()
|
trait_bounds: Vec::new()
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
match next(st) {
|
match next(st) {
|
||||||
'S' => {
|
'R' => {
|
||||||
param_bounds.builtin_bounds.add(ty::BoundSend);
|
param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
|
||||||
}
|
|
||||||
'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);
|
|
||||||
}
|
}
|
||||||
'I' => {
|
'I' => {
|
||||||
param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));
|
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 {
|
match r {
|
||||||
ty::ReLateBound(id, br) => {
|
ty::ReLateBound(id, br) => {
|
||||||
mywrite!(w, "b[{}|", id);
|
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 {
|
ty::ty_trait(box ty::TyTrait {
|
||||||
def_id,
|
def_id,
|
||||||
ref substs,
|
ref substs,
|
||||||
bounds
|
ref bounds
|
||||||
}) => {
|
}) => {
|
||||||
mywrite!(w, "x[{}|", (cx.ds)(def_id));
|
mywrite!(w, "x[{}|", (cx.ds)(def_id));
|
||||||
enc_substs(w, cx, substs);
|
enc_substs(w, cx, substs);
|
||||||
let bounds = ty::ParamBounds {builtin_bounds: bounds,
|
enc_existential_bounds(w, cx, bounds);
|
||||||
trait_bounds: Vec::new()};
|
|
||||||
enc_bounds(w, cx, &bounds);
|
|
||||||
mywrite!(w, "]");
|
mywrite!(w, "]");
|
||||||
}
|
}
|
||||||
ty::ty_tup(ref ts) => {
|
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_fn_style(w, ft.fn_style);
|
||||||
enc_onceness(w, ft.onceness);
|
enc_onceness(w, ft.onceness);
|
||||||
enc_trait_store(w, cx, ft.store);
|
enc_trait_store(w, cx, ft.store);
|
||||||
let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
|
enc_existential_bounds(w, cx, &ft.bounds);
|
||||||
trait_bounds: Vec::new()};
|
|
||||||
enc_bounds(w, cx, &bounds);
|
|
||||||
enc_fn_sig(w, cx, &ft.sig);
|
enc_fn_sig(w, cx, &ft.sig);
|
||||||
enc_abi(w, ft.abi);
|
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);
|
enc_ty(w, cx, fsig.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
|
pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
|
||||||
for bound in bs.builtin_bounds.iter() {
|
for bound in bs.iter() {
|
||||||
match bound {
|
match bound {
|
||||||
ty::BoundSend => mywrite!(w, "S"),
|
ty::BoundSend => mywrite!(w, "S"),
|
||||||
ty::BoundStatic => mywrite!(w, "O"),
|
|
||||||
ty::BoundSized => mywrite!(w, "Z"),
|
ty::BoundSized => mywrite!(w, "Z"),
|
||||||
ty::BoundCopy => mywrite!(w, "P"),
|
ty::BoundCopy => mywrite!(w, "P"),
|
||||||
ty::BoundSync => mywrite!(w, "T"),
|
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() {
|
for tp in bs.trait_bounds.iter() {
|
||||||
mywrite!(w, "I");
|
mywrite!(w, "I");
|
||||||
enc_trait_ref(w, cx, &**tp);
|
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, "{}:{}|{}|{}|",
|
mywrite!(w, "{}:{}|{}|{}|",
|
||||||
token::get_ident(v.ident), (cx.ds)(v.def_id),
|
token::get_ident(v.ident), (cx.ds)(v.def_id),
|
||||||
v.space.to_uint(), v.index);
|
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));
|
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||||
}
|
}
|
||||||
|
|
|
@ -942,6 +942,8 @@ trait rbml_writer_helpers {
|
||||||
ecx: &e::EncodeContext,
|
ecx: &e::EncodeContext,
|
||||||
pty: ty::Polytype);
|
pty: ty::Polytype);
|
||||||
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs);
|
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_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment);
|
||||||
fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef);
|
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);
|
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) {
|
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs) {
|
||||||
self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer,
|
self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer,
|
||||||
&ecx.ty_str_ctxt(),
|
&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))
|
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("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(1, |this| def_id.encode(this));
|
||||||
this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs)))
|
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,
|
ecx_ptr: *const libc::c_void,
|
||||||
new_rbml_w: &'a mut Encoder<'b>,
|
new_rbml_w: &'a mut Encoder<'b>,
|
||||||
}
|
}
|
||||||
|
@ -1380,6 +1395,7 @@ trait rbml_decoder_decoder_helpers {
|
||||||
-> ty::TypeParameterDef;
|
-> ty::TypeParameterDef;
|
||||||
fn read_polytype(&mut self, xcx: &ExtendedDecodeContext)
|
fn read_polytype(&mut self, xcx: &ExtendedDecodeContext)
|
||||||
-> ty::Polytype;
|
-> ty::Polytype;
|
||||||
|
fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds;
|
||||||
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
|
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
|
||||||
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
|
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
|
||||||
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
||||||
|
@ -1514,6 +1530,17 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||||
}).unwrap()
|
}).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 {
|
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs {
|
||||||
self.read_opaque(|this, doc| {
|
self.read_opaque(|this, doc| {
|
||||||
Ok(tydecode::parse_substs_data(doc.data,
|
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)
|
ty::UnsizeStruct(box uk, idx)
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let b: ty::BuiltinBounds =
|
let b =
|
||||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
this.read_enum_variant_arg(
|
||||||
|
0, |this| Ok(this.read_existential_bounds(xcx))).unwrap();
|
||||||
let def_id: ast::DefId =
|
let def_id: ast::DefId =
|
||||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||||
let substs = this.read_enum_variant_arg(2,
|
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 {
|
fn stmt(&mut self, stmt: Gc<ast::Stmt>, pred: CFGIndex) -> CFGIndex {
|
||||||
match stmt.node {
|
match stmt.node {
|
||||||
ast::StmtDecl(ref decl, _) => {
|
ast::StmtDecl(ref decl, id) => {
|
||||||
self.decl(&**decl, pred)
|
let exit = self.decl(&**decl, pred);
|
||||||
|
self.add_node(id, [exit])
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => {
|
ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
|
||||||
self.expr(expr.clone(), pred)
|
let exit = self.expr(expr.clone(), pred);
|
||||||
|
self.add_node(id, [exit])
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::StmtMac(..) => {
|
ast::StmtMac(..) => {
|
||||||
|
|
|
@ -1018,7 +1018,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) {
|
||||||
visitor.visit_pat(pat, true);
|
visitor.visit_pat(pat, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AtBindingPatternVisitor<'a,'b> {
|
struct AtBindingPatternVisitor<'a,'b:'a> {
|
||||||
cx: &'a MatchCheckCtxt<'b>,
|
cx: &'a MatchCheckCtxt<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,11 +80,18 @@ pub trait DataFlowOperator : BitwiseOperator {
|
||||||
fn initial_value(&self) -> bool;
|
fn initial_value(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
struct PropagationContext<'a, 'b, O> {
|
struct PropagationContext<'a, 'b, O> {
|
||||||
dfcx: &'a mut DataFlowContext<'b, O>,
|
dfcx: &'a mut DataFlowContext<'b, O>,
|
||||||
changed: bool
|
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 {
|
fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
|
||||||
let opt_cfgindex = index.find(&id).map(|&i|i);
|
let opt_cfgindex = index.find(&id).map(|&i|i);
|
||||||
opt_cfgindex.unwrap_or_else(|| {
|
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<()> {
|
blk: &ast::Block) -> io::IoResult<()> {
|
||||||
let mut ps = pprust::rust_printer_annotated(wr, self);
|
let mut ps = pprust::rust_printer_annotated(wr, self);
|
||||||
try!(ps.cbox(pprust::indent_unit));
|
try!(ps.cbox(pprust::indent_unit));
|
||||||
|
|
|
@ -192,10 +192,18 @@ impl OverloadedCallType {
|
||||||
// supplies types from the tree. After type checking is complete, you
|
// supplies types from the tree. After type checking is complete, you
|
||||||
// can just use the tcx as the typer.
|
// can just use the tcx as the typer.
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct ExprUseVisitor<'d,'t,TYPER> {
|
pub struct ExprUseVisitor<'d,'t,TYPER> {
|
||||||
typer: &'t TYPER,
|
typer: &'t TYPER,
|
||||||
mc: mc::MemCategorizationContext<'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
|
// 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);
|
pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
|
||||||
|
|
||||||
// Use a private field here to guarantee no more instances are created:
|
// Use a private field here to guarantee no more instances are created:
|
||||||
|
#[deriving(Show)]
|
||||||
pub struct Direction { repr: uint }
|
pub struct Direction { repr: uint }
|
||||||
pub static Outgoing: Direction = Direction { repr: 0 };
|
pub static Outgoing: Direction = Direction { repr: 0 };
|
||||||
pub static Incoming: Direction = Direction { repr: 1 };
|
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.
|
// If this trait has builtin-kind supertraits, meet them.
|
||||||
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
|
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);
|
debug!("checking impl with self type {}", ty::get(self_ty).sty);
|
||||||
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
|
check_builtin_bounds(
|
||||||
span_err!(cx.tcx.sess, self_type.span, E0142,
|
cx, self_ty, trait_def.bounds.builtin_bounds,
|
||||||
"the type `{}', which does not fulfill `{}`, cannot implement this trait",
|
|missing| {
|
||||||
ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
|
span_err!(cx.tcx.sess, self_type.span, E0142,
|
||||||
span_note!(cx.tcx.sess, self_type.span,
|
"the type `{}', which does not fulfill `{}`, \
|
||||||
"types implementing this trait must fulfill `{}`",
|
cannot implement this trait",
|
||||||
trait_def.bounds.user_string(cx.tcx));
|
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 this is a destructor, check kinds.
|
||||||
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
|
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 {
|
match ty::get(fty).sty {
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
ty::ty_closure(box ty::ClosureTy {
|
||||||
store: ty::UniqTraitStore,
|
store: ty::UniqTraitStore,
|
||||||
bounds: mut bounds, ..
|
bounds: bounds,
|
||||||
|
..
|
||||||
}) => {
|
}) => {
|
||||||
// Procs can't close over non-static references!
|
b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds))
|
||||||
bounds.add(ty::BoundStatic);
|
|
||||||
|
|
||||||
b(|cx, fv| check_for_uniq(cx, fv, bounds))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
ty::ty_closure(box ty::ClosureTy {
|
||||||
store: ty::RegionTraitStore(region, _), bounds, ..
|
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(_) => {
|
ty::ty_bare_fn(_) => {
|
||||||
b(check_for_bare)
|
b(check_for_bare)
|
||||||
|
@ -377,13 +378,6 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||||
expression_type);
|
expression_type);
|
||||||
|
|
||||||
match e.node {
|
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, _) => {
|
ExprCast(ref source, _) => {
|
||||||
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
||||||
let target_ty = ty::expr_ty(cx.tcx, e);
|
let target_ty = ty::expr_ty(cx.tcx, e);
|
||||||
|
@ -562,7 +556,6 @@ fn check_trait_cast(cx: &mut Context,
|
||||||
target_ty: ty::t,
|
target_ty: ty::t,
|
||||||
span: Span,
|
span: Span,
|
||||||
method_call: MethodCall) {
|
method_call: MethodCall) {
|
||||||
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
|
||||||
match ty::get(target_ty).sty {
|
match ty::get(target_ty).sty {
|
||||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
|
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
|
||||||
match ty::get(ty).sty {
|
match ty::get(ty).sty {
|
||||||
|
@ -580,7 +573,8 @@ fn check_trait_cast(cx: &mut Context,
|
||||||
vtable_res)
|
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 kind = ty::type_contents(cx.tcx, ty);
|
||||||
let mut missing = ty::empty_builtin_bounds();
|
let mut missing = ty::empty_builtin_bounds();
|
||||||
for bound in bounds.iter() {
|
for bound in bounds.iter() {
|
||||||
if !kind.meets_bound(cx.tcx, bound) {
|
if !kind.meets_builtin_bound(cx.tcx, bound) {
|
||||||
missing.add(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).
|
// 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) {
|
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
|
||||||
if !ty::type_is_sized(tcx, ty) {
|
if !ty::type_is_sized(tcx, ty) {
|
||||||
|
|
|
@ -240,10 +240,16 @@ impl ast_node for ast::Pat {
|
||||||
fn span(&self) -> Span { self.span }
|
fn span(&self) -> Span { self.span }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct MemCategorizationContext<'t,TYPER> {
|
pub struct MemCategorizationContext<'t,TYPER> {
|
||||||
typer: &'t TYPER
|
typer: &'t TYPER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub struct MemCategorizationContext<'t,TYPER:'t> {
|
||||||
|
typer: &'t TYPER
|
||||||
|
}
|
||||||
|
|
||||||
pub type McResult<T> = Result<T, ()>;
|
pub type McResult<T> = Result<T, ()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1221,8 +1221,8 @@ struct VisiblePrivateTypesVisitor<'a> {
|
||||||
public_items: &'a PublicItems,
|
public_items: &'a PublicItems,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckTypeForPrivatenessVisitor<'a, 'b> {
|
struct CheckTypeForPrivatenessVisitor<'a, 'b:'a> {
|
||||||
inner: &'b VisiblePrivateTypesVisitor<'a>,
|
inner: &'a VisiblePrivateTypesVisitor<'b>,
|
||||||
/// whether the type refers to private types.
|
/// whether the type refers to private types.
|
||||||
contains_private: bool,
|
contains_private: bool,
|
||||||
/// whether we've recurred at all (i.e. if we're pointing at the
|
/// 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::{FreeRegion};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
|
use util::common::can_reach;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
@ -78,7 +79,7 @@ The region maps encode information about region relationships.
|
||||||
pub struct RegionMaps {
|
pub struct RegionMaps {
|
||||||
scope_map: RefCell<NodeMap<ast::NodeId>>,
|
scope_map: RefCell<NodeMap<ast::NodeId>>,
|
||||||
var_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>>,
|
rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
|
||||||
terminating_scopes: RefCell<HashSet<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).
|
* (that is, the user can give two different names to the same lifetime).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if sub == sup {
|
can_reach(&*self.free_region_map.borrow(), 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_subregion_of(&self,
|
pub fn is_subregion_of(&self,
|
||||||
|
@ -300,6 +274,7 @@ impl RegionMaps {
|
||||||
|
|
||||||
sub_region == super_region || {
|
sub_region == super_region || {
|
||||||
match (sub_region, super_region) {
|
match (sub_region, super_region) {
|
||||||
|
(ty::ReEmpty, _) |
|
||||||
(_, ty::ReStatic) => {
|
(_, ty::ReStatic) => {
|
||||||
true
|
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::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
|
||||||
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method};
|
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method};
|
||||||
use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
|
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::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
|
||||||
use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic};
|
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::{StructVariantKind, TraitRef, TraitTyParamBound};
|
||||||
use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
|
use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
|
||||||
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
|
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
|
||||||
|
@ -901,7 +901,7 @@ struct Resolver<'a> {
|
||||||
used_imports: HashSet<(NodeId, Namespace)>,
|
used_imports: HashSet<(NodeId, Namespace)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BuildReducedGraphVisitor<'a, 'b> {
|
struct BuildReducedGraphVisitor<'a, 'b:'a> {
|
||||||
resolver: &'a mut Resolver<'b>,
|
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> {
|
impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> {
|
||||||
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
|
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
|
||||||
|
@ -3946,7 +3948,7 @@ impl<'a> Resolver<'a> {
|
||||||
impl_items.as_slice());
|
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.
|
// Create a new rib for the self type.
|
||||||
let self_type_rib = Rib::new(ItemRibKind);
|
let self_type_rib = Rib::new(ItemRibKind);
|
||||||
|
|
||||||
|
@ -3965,10 +3967,9 @@ impl<'a> Resolver<'a> {
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
this.resolve_where_clause(&generics.where_clause);
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
|
|
||||||
// Resolve derived traits.
|
this.resolve_type_parameter_bounds(item.id, bounds,
|
||||||
for trt in traits.iter() {
|
TraitDerivation);
|
||||||
this.resolve_trait_reference(item.id, trt, TraitDerivation);
|
|
||||||
}
|
|
||||||
match unbound {
|
match unbound {
|
||||||
&Some(ast::TraitTyParamBound(ref tpb)) => {
|
&Some(ast::TraitTyParamBound(ref tpb)) => {
|
||||||
this.resolve_trait_reference(item.id, tpb, TraitDerivation);
|
this.resolve_trait_reference(item.id, tpb, TraitDerivation);
|
||||||
|
@ -4199,10 +4200,13 @@ impl<'a> Resolver<'a> {
|
||||||
type_parameters: &OwnedSlice<TyParam>) {
|
type_parameters: &OwnedSlice<TyParam>) {
|
||||||
for type_parameter in type_parameters.iter() {
|
for type_parameter in type_parameters.iter() {
|
||||||
for bound in type_parameter.bounds.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 {
|
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 => {}
|
&None => {}
|
||||||
}
|
}
|
||||||
match type_parameter.default {
|
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,
|
fn resolve_type_parameter_bound(&mut self,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
type_parameter_bound: &TyParamBound) {
|
type_parameter_bound: &TyParamBound,
|
||||||
|
reference_type: TraitReferenceType) {
|
||||||
match *type_parameter_bound {
|
match *type_parameter_bound {
|
||||||
TraitTyParamBound(ref tref) => {
|
TraitTyParamBound(ref tref) => {
|
||||||
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
|
self.resolve_trait_reference(id, tref, reference_type)
|
||||||
}
|
}
|
||||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
UnboxedFnTyParamBound(ref unboxed_function) => {
|
||||||
for argument in unboxed_function.decl.inputs.iter() {
|
for argument in unboxed_function.decl.inputs.iter() {
|
||||||
|
@ -4226,7 +4241,7 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
self.resolve_type(&*unboxed_function.decl.output);
|
self.resolve_type(&*unboxed_function.decl.output);
|
||||||
}
|
}
|
||||||
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
|
RegionTyParamBound(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4240,7 +4255,7 @@ impl<'a> Resolver<'a> {
|
||||||
let usage_str = match reference_type {
|
let usage_str = match reference_type {
|
||||||
TraitBoundingTypeParameter => "bound type parameter with",
|
TraitBoundingTypeParameter => "bound type parameter with",
|
||||||
TraitImplementation => "implement",
|
TraitImplementation => "implement",
|
||||||
TraitDerivation => "derive"
|
TraitDerivation => "derive",
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
|
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() {
|
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| {
|
bounds.as_ref().map(|bound_vec| {
|
||||||
for bound in bound_vec.iter() {
|
self.resolve_type_parameter_bounds(ty.id, bound_vec,
|
||||||
self.resolve_type_parameter_bound(ty.id, bound);
|
TraitBoundingTypeParameter);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TyClosure(c, _) | TyProc(c) => {
|
TyClosure(c) | TyProc(c) => {
|
||||||
c.bounds.as_ref().map(|bounds| {
|
self.resolve_type_parameter_bounds(ty.id, &c.bounds,
|
||||||
for bound in bounds.iter() {
|
TraitBoundingTypeParameter);
|
||||||
self.resolve_type_parameter_bound(ty.id, bound);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
visit::walk_ty(self, ty, ());
|
visit::walk_ty(self, ty, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ use driver::session::Session;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::owned_slice::OwnedSlice;
|
|
||||||
use syntax::parse::token::special_idents;
|
use syntax::parse::token::special_idents;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::pprust::{lifetime_to_string};
|
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::ItemStruct(_, ref generics) |
|
||||||
ast::ItemImpl(ref generics, _, _, _) |
|
ast::ItemImpl(ref generics, _, _, _) |
|
||||||
ast::ItemTrait(ref generics, _, _, _) => {
|
ast::ItemTrait(ref generics, _, _, _) => {
|
||||||
self.check_lifetime_names(&generics.lifetimes);
|
let scope: ScopeChain =
|
||||||
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root)
|
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root);
|
||||||
|
self.check_lifetime_defs(&generics.lifetimes, &scope);
|
||||||
|
scope
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("entering 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>) {
|
fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) {
|
||||||
match ty.node {
|
match ty.node {
|
||||||
ast::TyClosure(c, _) | ast::TyProc(c) => {
|
ast::TyClosure(c) | ast::TyProc(c) => {
|
||||||
push_fn_scope(self, ty, scope, &c.lifetimes);
|
push_fn_scope(self, ty, scope, &c.lifetimes);
|
||||||
}
|
}
|
||||||
ast::TyBareFn(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,
|
ty: &ast::Ty,
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
lifetimes: &Vec<ast::LifetimeDef>) {
|
lifetimes: &Vec<ast::LifetimeDef>) {
|
||||||
let scope1 = LateScope(ty.id, lifetimes, scope);
|
let scope1: ScopeChain = LateScope(ty.id, lifetimes, scope);
|
||||||
this.check_lifetime_names(lifetimes);
|
this.check_lifetime_defs(lifetimes, &scope1);
|
||||||
debug!("pushing fn scope id={} due to type", ty.id);
|
debug!("pushing fn scope id={} due to type", ty.id);
|
||||||
visit::walk_ty(this, ty, &scope1);
|
visit::walk_ty(this, ty, &scope1);
|
||||||
debug!("popping fn scope id={} due to type", ty.id);
|
debug!("popping fn scope id={} due to type", ty.id);
|
||||||
|
@ -204,24 +205,22 @@ impl<'a> LifetimeContext<'a> {
|
||||||
* the ordering is not important there.
|
* the ordering is not important there.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
self.check_lifetime_names(&generics.lifetimes);
|
let referenced_idents = early_bound_lifetime_names(generics);
|
||||||
|
|
||||||
let referenced_idents = free_lifetimes(&generics.ty_params,
|
|
||||||
&generics.where_clause);
|
|
||||||
debug!("pushing fn scope id={} due to fn item/method\
|
debug!("pushing fn scope id={} due to fn item/method\
|
||||||
referenced_idents={:?}",
|
referenced_idents={:?}",
|
||||||
n,
|
n,
|
||||||
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
|
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
|
||||||
if referenced_idents.is_empty() {
|
if referenced_idents.is_empty() {
|
||||||
let scope1 = LateScope(n, &generics.lifetimes, scope);
|
let scope1: ScopeChain = LateScope(n, &generics.lifetimes, scope);
|
||||||
walk(self, &scope1)
|
self.check_lifetime_defs(&generics.lifetimes, &scope1);
|
||||||
|
walk(self, &scope1);
|
||||||
} else {
|
} else {
|
||||||
let (early, late) = generics.lifetimes.clone().partition(
|
let (early, late) = generics.lifetimes.clone().partition(
|
||||||
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
||||||
|
|
||||||
let scope1 = EarlyScope(subst::FnSpace, &early, scope);
|
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);
|
walk(self, &scope2);
|
||||||
}
|
}
|
||||||
debug!("popping fn scope id={} due to fn item/method", n);
|
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());
|
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()) {
|
for i in range(0, lifetimes.len()) {
|
||||||
let lifetime_i = lifetimes.get(i);
|
let lifetime_i = lifetimes.get(i);
|
||||||
|
|
||||||
|
@ -364,11 +365,7 @@ impl<'a> LifetimeContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for bound in lifetime_i.bounds.iter() {
|
for bound in lifetime_i.bounds.iter() {
|
||||||
if !self.sess.features.issue_5723_bootstrap.get() {
|
self.resolve_lifetime_ref(bound, scope);
|
||||||
self.sess.span_err(
|
|
||||||
bound.span,
|
|
||||||
"region bounds require `issue_5723_bootstrap`");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,8 +401,7 @@ fn search_lifetimes(lifetimes: &Vec<ast::LifetimeDef>,
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
|
pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
|
||||||
let referenced_idents = free_lifetimes(&generics.ty_params,
|
let referenced_idents = early_bound_lifetime_names(generics);
|
||||||
&generics.where_clause);
|
|
||||||
if referenced_idents.is_empty() {
|
if referenced_idents.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
@ -416,34 +412,72 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::Lifeti
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_lifetimes(ty_params: &OwnedSlice<ast::TyParam>,
|
fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
|
||||||
where_clause: &ast::WhereClause)
|
|
||||||
-> Vec<ast::Name> {
|
|
||||||
/*!
|
/*!
|
||||||
* Gathers up and returns the names of any lifetimes that appear
|
* Given a set of generic declarations, returns a list of names
|
||||||
* free in `ty_params`. Of course, right now, all lifetimes appear
|
* containing all early bound lifetime names for those
|
||||||
* free, since we don't currently have any binders in type parameter
|
* generics. (In fact, this list may also contain other names.)
|
||||||
* declarations; just being forwards compatible with future extensions.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut collector = FreeLifetimeCollector { names: vec!() };
|
// Create two lists, dividing the lifetimes into early/late bound.
|
||||||
for ty_param in ty_params.iter() {
|
// Initially, all of them are considered late, but we will move
|
||||||
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
|
// things from late into early as we go if we find references to
|
||||||
}
|
// them.
|
||||||
for predicate in where_clause.predicates.iter() {
|
let mut early_bound = Vec::new();
|
||||||
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
|
let mut late_bound = generics.lifetimes.iter()
|
||||||
}
|
.map(|l| l.lifetime.name)
|
||||||
return collector.names;
|
.collect();
|
||||||
|
|
||||||
struct FreeLifetimeCollector {
|
// Any lifetime that appears in a type bound is early.
|
||||||
names: Vec<ast::Name>,
|
{
|
||||||
|
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,
|
fn visit_lifetime_ref(&mut self,
|
||||||
lifetime_ref: &ast::Lifetime,
|
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::codemap::*;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::parse::token::{get_ident,keywords};
|
use syntax::parse::token::{get_ident,keywords};
|
||||||
|
use syntax::owned_slice::OwnedSlice;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
use syntax::print::pprust::{path_to_string,ty_to_string};
|
use syntax::print::pprust::{path_to_string,ty_to_string};
|
||||||
|
@ -653,7 +654,7 @@ impl <'l> DxrVisitor<'l> {
|
||||||
item: &ast::Item,
|
item: &ast::Item,
|
||||||
e: DxrVisitorEnv,
|
e: DxrVisitorEnv,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
trait_refs: &Vec<ast::TraitRef>,
|
trait_refs: &OwnedSlice<ast::TyParamBound>,
|
||||||
methods: &Vec<ast::TraitItem>) {
|
methods: &Vec<ast::TraitItem>) {
|
||||||
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
|
||||||
|
|
||||||
|
@ -665,7 +666,16 @@ impl <'l> DxrVisitor<'l> {
|
||||||
e.cur_scope);
|
e.cur_scope);
|
||||||
|
|
||||||
// super-traits
|
// 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) {
|
match self.lookup_type_ref(trait_ref.ref_id) {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
|
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!(),
|
collected_paths: vec!(),
|
||||||
collecting: false,
|
collecting: false,
|
||||||
fmt: FmtStrs::new(box Recorder {
|
fmt: FmtStrs::new(box Recorder {
|
||||||
out: output_file as Box<Writer>,
|
out: output_file as Box<Writer+'static>,
|
||||||
dump_spans: false,
|
dump_spans: false,
|
||||||
},
|
},
|
||||||
SpanUtils {
|
SpanUtils {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use syntax::codemap::*;
|
||||||
|
|
||||||
pub struct Recorder {
|
pub struct Recorder {
|
||||||
// output file
|
// output file
|
||||||
pub out: Box<Writer>,
|
pub out: Box<Writer+'static>,
|
||||||
pub dump_spans: bool,
|
pub dump_spans: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||||
|
|
||||||
let t1 = match ty::get(t).sty {
|
let t1 = match ty::get(t).sty {
|
||||||
ty::ty_param(p) => {
|
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)
|
ty_fold::super_fold_ty(self, t)
|
||||||
|
@ -627,6 +627,7 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||||
return t1;
|
return t1;
|
||||||
|
|
||||||
fn check(this: &SubstFolder,
|
fn check(this: &SubstFolder,
|
||||||
|
p: ty::ParamTy,
|
||||||
source_ty: ty::t,
|
source_ty: ty::t,
|
||||||
opt_ty: Option<&ty::t>)
|
opt_ty: Option<&ty::t>)
|
||||||
-> ty::t {
|
-> ty::t {
|
||||||
|
@ -636,8 +637,9 @@ impl<'a> TypeFolder for SubstFolder<'a> {
|
||||||
let span = this.span.unwrap_or(DUMMY_SP);
|
let span = this.span.unwrap_or(DUMMY_SP);
|
||||||
this.tcx().sess.span_bug(
|
this.tcx().sess.span_bug(
|
||||||
span,
|
span,
|
||||||
format!("Type parameter {} out of range \
|
format!("Type parameter `{}` ({}) out of range \
|
||||||
when substituting (root type={})",
|
when substituting (root type={})",
|
||||||
|
p.repr(this.tcx()),
|
||||||
source_ty.repr(this.tcx()),
|
source_ty.repr(this.tcx()),
|
||||||
this.root_ty.repr(this.tcx())).as_slice());
|
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,
|
* 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.
|
* 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> {
|
struct Match<'a, 'b> {
|
||||||
pats: Vec<Gc<ast::Pat>>,
|
pats: Vec<Gc<ast::Pat>>,
|
||||||
data: &'a ArmData<'a, 'b>,
|
data: &'a ArmData<'a, 'b>,
|
||||||
|
|
|
@ -25,7 +25,6 @@ use middle::ty;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
|
||||||
pub struct CleanupScope<'a> {
|
pub struct CleanupScope<'a> {
|
||||||
// The id of this cleanup scope. If the id is None,
|
// The id of this cleanup scope. If the id is None,
|
||||||
// this is a *temporary scope* that is pushed during trans to
|
// this is a *temporary scope* that is pushed during trans to
|
||||||
|
@ -35,7 +34,7 @@ pub struct CleanupScope<'a> {
|
||||||
kind: CleanupScopeKind<'a>,
|
kind: CleanupScopeKind<'a>,
|
||||||
|
|
||||||
// Cleanups to run upon scope exit.
|
// Cleanups to run upon scope exit.
|
||||||
cleanups: Vec<Box<Cleanup>>,
|
cleanups: Vec<CleanupObj>,
|
||||||
|
|
||||||
cached_early_exits: Vec<CachedEarlyExit>,
|
cached_early_exits: Vec<CachedEarlyExit>,
|
||||||
cached_landing_pad: Option<BasicBlockRef>,
|
cached_landing_pad: Option<BasicBlockRef>,
|
||||||
|
@ -73,6 +72,8 @@ pub trait Cleanup {
|
||||||
fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>;
|
fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type CleanupObj = Box<Cleanup+'static>;
|
||||||
|
|
||||||
pub enum ScopeId {
|
pub enum ScopeId {
|
||||||
AstScope(ast::NodeId),
|
AstScope(ast::NodeId),
|
||||||
CustomScope(CustomScopeIndex)
|
CustomScope(CustomScopeIndex)
|
||||||
|
@ -238,7 +239,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||||
cleanup_scope,
|
cleanup_scope,
|
||||||
self.ccx.tn.val_to_string(val));
|
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,
|
fn schedule_drop_mem(&self,
|
||||||
|
@ -264,7 +265,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||||
self.ccx.tn.val_to_string(val),
|
self.ccx.tn.val_to_string(val),
|
||||||
ty.repr(self.ccx.tcx()));
|
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,
|
fn schedule_drop_and_zero_mem(&self,
|
||||||
|
@ -291,7 +292,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||||
ty.repr(self.ccx.tcx()),
|
ty.repr(self.ccx.tcx()),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_drop_immediate(&self,
|
fn schedule_drop_immediate(&self,
|
||||||
|
@ -316,7 +317,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||||
self.ccx.tn.val_to_string(val),
|
self.ccx.tn.val_to_string(val),
|
||||||
ty.repr(self.ccx.tcx()));
|
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,
|
fn schedule_free_value(&self,
|
||||||
|
@ -336,12 +337,12 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
|
||||||
self.ccx.tn.val_to_string(val),
|
self.ccx.tn.val_to_string(val),
|
||||||
heap);
|
heap);
|
||||||
|
|
||||||
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
|
self.schedule_clean(cleanup_scope, drop as CleanupObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_clean(&self,
|
fn schedule_clean(&self,
|
||||||
cleanup_scope: ScopeId,
|
cleanup_scope: ScopeId,
|
||||||
cleanup: Box<Cleanup>) {
|
cleanup: CleanupObj) {
|
||||||
match cleanup_scope {
|
match cleanup_scope {
|
||||||
AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
|
AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
|
||||||
CustomScope(id) => self.schedule_clean_in_custom_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,
|
fn schedule_clean_in_ast_scope(&self,
|
||||||
cleanup_scope: ast::NodeId,
|
cleanup_scope: ast::NodeId,
|
||||||
cleanup: Box<Cleanup>) {
|
cleanup: CleanupObj) {
|
||||||
/*!
|
/*!
|
||||||
* Schedules a cleanup to occur upon exit from `cleanup_scope`.
|
* Schedules a cleanup to occur upon exit from `cleanup_scope`.
|
||||||
* If `cleanup_scope` is not provided, then the cleanup is scheduled
|
* 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,
|
fn schedule_clean_in_custom_scope(&self,
|
||||||
custom_scope: CustomScopeIndex,
|
custom_scope: CustomScopeIndex,
|
||||||
cleanup: Box<Cleanup>) {
|
cleanup: CleanupObj) {
|
||||||
/*!
|
/*!
|
||||||
* Schedules a cleanup to occur in the top-most scope,
|
* Schedules a cleanup to occur in the top-most scope,
|
||||||
* which must be a temporary scope.
|
* which must be a temporary scope.
|
||||||
|
@ -1021,13 +1022,13 @@ pub trait CleanupMethods<'a> {
|
||||||
content_ty: ty::t);
|
content_ty: ty::t);
|
||||||
fn schedule_clean(&self,
|
fn schedule_clean(&self,
|
||||||
cleanup_scope: ScopeId,
|
cleanup_scope: ScopeId,
|
||||||
cleanup: Box<Cleanup>);
|
cleanup: CleanupObj);
|
||||||
fn schedule_clean_in_ast_scope(&self,
|
fn schedule_clean_in_ast_scope(&self,
|
||||||
cleanup_scope: ast::NodeId,
|
cleanup_scope: ast::NodeId,
|
||||||
cleanup: Box<Cleanup>);
|
cleanup: CleanupObj);
|
||||||
fn schedule_clean_in_custom_scope(&self,
|
fn schedule_clean_in_custom_scope(&self,
|
||||||
custom_scope: CustomScopeIndex,
|
custom_scope: CustomScopeIndex,
|
||||||
cleanup: Box<Cleanup>);
|
cleanup: CleanupObj);
|
||||||
fn needs_invoke(&self) -> bool;
|
fn needs_invoke(&self) -> bool;
|
||||||
fn get_landing_pad(&'a self) -> BasicBlockRef;
|
fn get_landing_pad(&'a self) -> BasicBlockRef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,9 +498,8 @@ impl TypeMap {
|
||||||
|
|
||||||
unique_type_id.push_char(':');
|
unique_type_id.push_char(':');
|
||||||
|
|
||||||
for bound in bounds.iter() {
|
for bound in bounds.builtin_bounds.iter() {
|
||||||
match bound {
|
match bound {
|
||||||
ty::BoundStatic => unique_type_id.push_str("'static"),
|
|
||||||
ty::BoundSend => unique_type_id.push_str("Send"),
|
ty::BoundSend => unique_type_id.push_str("Send"),
|
||||||
ty::BoundSized => unique_type_id.push_str("Sized"),
|
ty::BoundSized => unique_type_id.push_str("Sized"),
|
||||||
ty::BoundCopy => unique_type_id.push_str("Copy"),
|
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_::Type;
|
||||||
use middle::trans::type_of::{type_of, sizing_type_of, align_of};
|
use middle::trans::type_of::{type_of, sizing_type_of, align_of};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::ppaux::ty_to_short_str;
|
use util::ppaux::{ty_to_short_str, Repr};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
|
|
||||||
use arena::TypedArena;
|
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)
|
pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||||
-> &'a Block<'a> {
|
-> &'a Block<'a> {
|
||||||
// NB: v is an *alias* of type t here, not a direct value.
|
// 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");
|
let _icx = push_ctxt("drop_ty");
|
||||||
if ty::type_needs_drop(bcx.tcx(), t) {
|
if ty::type_needs_drop(bcx.tcx(), t) {
|
||||||
let ccx = bcx.ccx();
|
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 _icx = push_ctxt("make_visit_glue");
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
||||||
|
ty::ReStatic,
|
||||||
ty::ReStatic) {
|
ty::ReStatic) {
|
||||||
Ok(pair) => pair,
|
Ok(pair) => pair,
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
|
|
|
@ -273,7 +273,7 @@ pub enum UnsizeKind {
|
||||||
// An unsize coercion applied to the tail field of a struct.
|
// An unsize coercion applied to the tail field of a struct.
|
||||||
// The uint is the index of the type parameter which is unsized.
|
// The uint is the index of the type parameter which is unsized.
|
||||||
UnsizeStruct(Box<UnsizeKind>, uint),
|
UnsizeStruct(Box<UnsizeKind>, uint),
|
||||||
UnsizeVtable(ty::BuiltinBounds,
|
UnsizeVtable(ty::ExistentialBounds,
|
||||||
ast::DefId, /* Trait ID */
|
ast::DefId, /* Trait ID */
|
||||||
subst::Substs /* Trait substitutions */)
|
subst::Substs /* Trait substitutions */)
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,6 @@ pub struct ctxt {
|
||||||
pub lang_items: middle::lang_items::LanguageItems,
|
pub lang_items: middle::lang_items::LanguageItems,
|
||||||
/// A mapping of fake provided method def_ids to the default implementation
|
/// A mapping of fake provided method def_ids to the default implementation
|
||||||
pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
|
pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
|
||||||
pub supertraits: RefCell<DefIdMap<Rc<Vec<Rc<TraitRef>>>>>,
|
|
||||||
pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
|
pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
|
||||||
pub struct_fields: RefCell<DefIdMap<Rc<Vec<field_ty>>>>,
|
pub struct_fields: RefCell<DefIdMap<Rc<Vec<field_ty>>>>,
|
||||||
|
|
||||||
|
@ -620,7 +619,7 @@ pub struct ClosureTy {
|
||||||
pub fn_style: ast::FnStyle,
|
pub fn_style: ast::FnStyle,
|
||||||
pub onceness: ast::Onceness,
|
pub onceness: ast::Onceness,
|
||||||
pub store: TraitStore,
|
pub store: TraitStore,
|
||||||
pub bounds: BuiltinBounds,
|
pub bounds: ExistentialBounds,
|
||||||
pub sig: FnSig,
|
pub sig: FnSig,
|
||||||
pub abi: abi::Abi,
|
pub abi: abi::Abi,
|
||||||
}
|
}
|
||||||
|
@ -932,7 +931,7 @@ pub enum sty {
|
||||||
pub struct TyTrait {
|
pub struct TyTrait {
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
pub substs: Substs,
|
pub substs: Substs,
|
||||||
pub bounds: BuiltinBounds
|
pub bounds: ExistentialBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Hash, Show)]
|
#[deriving(PartialEq, Eq, Hash, Show)]
|
||||||
|
@ -995,18 +994,30 @@ pub enum type_err {
|
||||||
terr_variadic_mismatch(expected_found<bool>)
|
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 struct ParamBounds {
|
||||||
|
pub opt_region_bound: Option<ty::Region>,
|
||||||
pub builtin_bounds: BuiltinBounds,
|
pub builtin_bounds: BuiltinBounds,
|
||||||
pub trait_bounds: Vec<Rc<TraitRef>>
|
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>;
|
pub type BuiltinBounds = EnumSet<BuiltinBound>;
|
||||||
|
|
||||||
#[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)]
|
#[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)]
|
||||||
#[repr(uint)]
|
#[repr(uint)]
|
||||||
pub enum BuiltinBound {
|
pub enum BuiltinBound {
|
||||||
BoundStatic,
|
|
||||||
BoundSend,
|
BoundSend,
|
||||||
BoundSized,
|
BoundSized,
|
||||||
BoundCopy,
|
BoundCopy,
|
||||||
|
@ -1019,13 +1030,21 @@ pub fn empty_builtin_bounds() -> BuiltinBounds {
|
||||||
|
|
||||||
pub fn all_builtin_bounds() -> BuiltinBounds {
|
pub fn all_builtin_bounds() -> BuiltinBounds {
|
||||||
let mut set = EnumSet::empty();
|
let mut set = EnumSet::empty();
|
||||||
set.add(BoundStatic);
|
|
||||||
set.add(BoundSend);
|
set.add(BoundSend);
|
||||||
set.add(BoundSized);
|
set.add(BoundSized);
|
||||||
set.add(BoundSync);
|
set.add(BoundSync);
|
||||||
set
|
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 {
|
impl CLike for BuiltinBound {
|
||||||
fn to_uint(&self) -> uint {
|
fn to_uint(&self) -> uint {
|
||||||
*self as uint
|
*self as uint
|
||||||
|
@ -1141,8 +1160,8 @@ pub struct TypeParameterDef {
|
||||||
pub def_id: ast::DefId,
|
pub def_id: ast::DefId,
|
||||||
pub space: subst::ParamSpace,
|
pub space: subst::ParamSpace,
|
||||||
pub index: uint,
|
pub index: uint,
|
||||||
pub bounds: Rc<ParamBounds>,
|
pub bounds: ParamBounds,
|
||||||
pub default: Option<ty::t>
|
pub default: Option<ty::t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Encodable, Decodable, Clone, Show)]
|
#[deriving(Encodable, Decodable, Clone, Show)]
|
||||||
|
@ -1151,6 +1170,7 @@ pub struct RegionParameterDef {
|
||||||
pub def_id: ast::DefId,
|
pub def_id: ast::DefId,
|
||||||
pub space: subst::ParamSpace,
|
pub space: subst::ParamSpace,
|
||||||
pub index: uint,
|
pub index: uint,
|
||||||
|
pub bounds: Vec<ty::Region>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the type/lifetime parameters associated with an
|
/// Information about the type/lifetime parameters associated with an
|
||||||
|
@ -1198,6 +1218,12 @@ pub struct ParameterEnvironment {
|
||||||
|
|
||||||
/// Bounds on the various type parameters
|
/// Bounds on the various type parameters
|
||||||
pub bounds: VecPerParamSpace<ParamBounds>,
|
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 {
|
impl ParameterEnvironment {
|
||||||
|
@ -1292,7 +1318,7 @@ pub struct Polytype {
|
||||||
/// As `Polytype` but for a trait ref.
|
/// As `Polytype` but for a trait ref.
|
||||||
pub struct TraitDef {
|
pub struct TraitDef {
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
pub bounds: BuiltinBounds,
|
pub bounds: ParamBounds,
|
||||||
pub trait_ref: Rc<ty::TraitRef>,
|
pub trait_ref: Rc<ty::TraitRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,7 +1408,6 @@ pub fn mk_ctxt(s: Session,
|
||||||
normalized_cache: RefCell::new(HashMap::new()),
|
normalized_cache: RefCell::new(HashMap::new()),
|
||||||
lang_items: lang_items,
|
lang_items: lang_items,
|
||||||
provided_method_sources: RefCell::new(DefIdMap::new()),
|
provided_method_sources: RefCell::new(DefIdMap::new()),
|
||||||
supertraits: RefCell::new(DefIdMap::new()),
|
|
||||||
superstructs: RefCell::new(DefIdMap::new()),
|
superstructs: RefCell::new(DefIdMap::new()),
|
||||||
struct_fields: RefCell::new(DefIdMap::new()),
|
struct_fields: RefCell::new(DefIdMap::new()),
|
||||||
destructor_for_type: 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;
|
return f;
|
||||||
}
|
}
|
||||||
|
fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
|
||||||
|
rflags(bounds.region_bound)
|
||||||
|
}
|
||||||
match &st {
|
match &st {
|
||||||
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
|
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
|
||||||
&ty_str => {}
|
&ty_str => {}
|
||||||
|
@ -1483,8 +1511,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||||
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
|
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
|
||||||
flags |= sflags(substs);
|
flags |= sflags(substs);
|
||||||
}
|
}
|
||||||
&ty_trait(box ty::TyTrait { ref substs, .. }) => {
|
&ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => {
|
||||||
flags |= sflags(substs);
|
flags |= sflags(substs);
|
||||||
|
flags |= flags_for_bounds(bounds);
|
||||||
}
|
}
|
||||||
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
|
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
|
||||||
flags |= get(tt).flags
|
flags |= get(tt).flags
|
||||||
|
@ -1514,6 +1543,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||||
flags |= get(f.sig.output).flags;
|
flags |= get(f.sig.output).flags;
|
||||||
// T -> _|_ is *not* _|_ !
|
// T -> _|_ is *not* _|_ !
|
||||||
flags &= !(has_ty_bot as uint);
|
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,
|
pub fn mk_trait(cx: &ctxt,
|
||||||
did: ast::DefId,
|
did: ast::DefId,
|
||||||
substs: Substs,
|
substs: Substs,
|
||||||
bounds: BuiltinBounds)
|
bounds: ExistentialBounds)
|
||||||
-> t {
|
-> t {
|
||||||
// take a copy of substs so that we own the vectors inside
|
// take a copy of substs so that we own the vectors inside
|
||||||
let inner = box TyTrait {
|
let inner = box TyTrait {
|
||||||
def_id: did,
|
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)
|
|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 {
|
impl ItemSubsts {
|
||||||
pub fn empty() -> ItemSubsts {
|
pub fn empty() -> ItemSubsts {
|
||||||
ItemSubsts { substs: Substs::empty() }
|
ItemSubsts { substs: Substs::empty() }
|
||||||
|
@ -2115,9 +2166,6 @@ def_type_content_sets!(
|
||||||
// that it neither reaches nor owns a managed pointer.
|
// that it neither reaches nor owns a managed pointer.
|
||||||
Nonsendable = 0b0000_0111__0000_0100__0000,
|
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
|
// Things that prevent values from being considered sized
|
||||||
Nonsized = 0b0000_0000__0000_0000__0001,
|
Nonsized = 0b0000_0000__0000_0000__0001,
|
||||||
|
|
||||||
|
@ -2142,9 +2190,8 @@ def_type_content_sets!(
|
||||||
)
|
)
|
||||||
|
|
||||||
impl TypeContents {
|
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 {
|
match bb {
|
||||||
BoundStatic => self.is_static(cx),
|
|
||||||
BoundSend => self.is_sendable(cx),
|
BoundSend => self.is_sendable(cx),
|
||||||
BoundSized => self.is_sized(cx),
|
BoundSized => self.is_sized(cx),
|
||||||
BoundCopy => self.is_copy(cx),
|
BoundCopy => self.is_copy(cx),
|
||||||
|
@ -2160,10 +2207,6 @@ impl TypeContents {
|
||||||
(self.bits & tc.bits) != 0
|
(self.bits & tc.bits) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_static(&self, _: &ctxt) -> bool {
|
|
||||||
!self.intersects(TC::Nonstatic)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_sendable(&self, _: &ctxt) -> bool {
|
pub fn is_sendable(&self, _: &ctxt) -> bool {
|
||||||
!self.intersects(TC::Nonsendable)
|
!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 {
|
pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool {
|
||||||
type_contents(cx, t).is_sendable(cx)
|
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 ty_param_defs = cx.ty_param_defs.borrow();
|
||||||
let tp_def = ty_param_defs.get(&p.def_id.node);
|
let tp_def = ty_param_defs.get(&p.def_id.node);
|
||||||
kind_bounds_to_contents(cx,
|
kind_bounds_to_contents(
|
||||||
tp_def.bounds.builtin_bounds,
|
cx,
|
||||||
tp_def.bounds.trait_bounds.as_slice())
|
tp_def.bounds.builtin_bounds,
|
||||||
}
|
tp_def.bounds.trait_bounds.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
ty_infer(_) => {
|
ty_infer(_) => {
|
||||||
// This occurs during coherence, but shouldn't occur at other
|
// 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,
|
fn object_contents(cx: &ctxt,
|
||||||
bounds: BuiltinBounds)
|
bounds: ExistentialBounds)
|
||||||
-> TypeContents {
|
-> TypeContents {
|
||||||
// These are the type contents of the (opaque) interior
|
// 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,
|
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;
|
let mut tc = TC::All;
|
||||||
each_inherited_builtin_bound(cx, bounds, traits, |bound| {
|
each_inherited_builtin_bound(cx, bounds, traits, |bound| {
|
||||||
tc = tc - match bound {
|
tc = tc - match bound {
|
||||||
BoundStatic => TC::Nonstatic,
|
|
||||||
BoundSend => TC::Nonsendable,
|
BoundSend => TC::Nonsendable,
|
||||||
BoundSized => TC::Nonsized,
|
BoundSized => TC::Nonsized,
|
||||||
BoundCopy => TC::Noncopy,
|
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| {
|
each_bound_trait_and_supertraits(cx, traits, |trait_ref| {
|
||||||
let trait_def = lookup_trait_def(cx, trait_ref.def_id);
|
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);
|
f(bound);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -3272,16 +3311,19 @@ pub fn adjust_ty(cx: &ctxt,
|
||||||
AutoAddEnv(store) => {
|
AutoAddEnv(store) => {
|
||||||
match ty::get(unadjusted_ty).sty {
|
match ty::get(unadjusted_ty).sty {
|
||||||
ty::ty_bare_fn(ref b) => {
|
ty::ty_bare_fn(ref b) => {
|
||||||
|
let bounds = ty::ExistentialBounds {
|
||||||
|
region_bound: ReStatic,
|
||||||
|
builtin_bounds: all_builtin_bounds(),
|
||||||
|
};
|
||||||
|
|
||||||
ty::mk_closure(
|
ty::mk_closure(
|
||||||
cx,
|
cx,
|
||||||
ty::ClosureTy {
|
ty::ClosureTy {fn_style: b.fn_style,
|
||||||
fn_style: b.fn_style,
|
onceness: ast::Many,
|
||||||
onceness: ast::Many,
|
store: store,
|
||||||
store: store,
|
bounds: bounds,
|
||||||
bounds: ty::all_builtin_bounds(),
|
sig: b.sig.clone(),
|
||||||
sig: b.sig.clone(),
|
abi: b.abi})
|
||||||
abi: b.abi,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ref b => {
|
ref b => {
|
||||||
cx.sess.bug(
|
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>(
|
fn lookup_locally_or_in_crate_store<V:Clone>(
|
||||||
descr: &str,
|
descr: &str,
|
||||||
def_id: ast::DefId,
|
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()
|
def.def_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_add_builtin_trait(tcx: &ctxt,
|
pub fn try_add_builtin_trait(
|
||||||
trait_def_id: ast::DefId,
|
tcx: &ctxt,
|
||||||
builtin_bounds: &mut BuiltinBounds) -> bool {
|
trait_def_id: ast::DefId,
|
||||||
|
builtin_bounds: &mut EnumSet<BuiltinBound>)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
//! Checks whether `trait_ref` refers to one of the builtin
|
//! Checks whether `trait_ref` refers to one of the builtin
|
||||||
//! traits, like `Send`, and adds the corresponding
|
//! traits, like `Send`, and adds the corresponding
|
||||||
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
|
//! 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.
|
/// Iterate over attributes of a definition.
|
||||||
// (This should really be an iterator, but that would require csearch and
|
// (This should really be an iterator, but that would require csearch and
|
||||||
// decoder to use iterators instead of higher-order functions.)
|
// 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)
|
node_id_to_type(tcx, id.node)
|
||||||
} else {
|
} else {
|
||||||
let mut tcache = tcx.tcache.borrow_mut();
|
let mut tcache = tcx.tcache.borrow_mut();
|
||||||
match tcache.find(&id) {
|
let pty = tcache.find_or_insert_with(id, |_| {
|
||||||
Some(&Polytype {ty, ..}) => ty,
|
csearch::get_field_type(tcx, struct_id, id)
|
||||||
None => {
|
});
|
||||||
let tpt = csearch::get_field_type(tcx, struct_id, id);
|
pty.ty
|
||||||
tcache.insert(id, tpt.clone());
|
|
||||||
tpt.ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
t.subst(tcx, substs)
|
t.subst(tcx, substs)
|
||||||
}
|
}
|
||||||
|
@ -4745,9 +4774,10 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add supertraits to supertrait_set
|
// Add supertraits to supertrait_set
|
||||||
let supertrait_refs = trait_ref_supertraits(tcx,
|
let trait_ref = trait_refs.get(i).clone();
|
||||||
&**trait_refs.get(i));
|
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||||
for supertrait_ref in supertrait_refs.iter() {
|
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={})",
|
debug!("each_bound_trait_and_supertraits(supertrait_ref={})",
|
||||||
supertrait_ref.repr(tcx));
|
supertrait_ref.repr(tcx));
|
||||||
|
|
||||||
|
@ -4765,6 +4795,61 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
|
||||||
return true;
|
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> {
|
pub fn get_tydesc_ty(tcx: &ctxt) -> Result<t, String> {
|
||||||
tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| {
|
tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| {
|
||||||
tcx.intrinsic_defs.borrow().find_copy(&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,
|
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) {
|
let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
Err(s) => { return Err(s); }
|
Err(s) => { return Err(s); }
|
||||||
|
@ -4788,11 +4876,12 @@ pub fn visitor_object_ty(tcx: &ctxt,
|
||||||
let substs = Substs::empty();
|
let substs = Substs::empty();
|
||||||
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
|
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
|
||||||
Ok((trait_ref.clone(),
|
Ok((trait_ref.clone(),
|
||||||
mk_rptr(tcx, region, mt {mutbl: ast::MutMutable,
|
mk_rptr(tcx, ptr_region,
|
||||||
ty: mk_trait(tcx,
|
mt {mutbl: ast::MutMutable,
|
||||||
trait_ref.def_id,
|
ty: mk_trait(tcx,
|
||||||
trait_ref.substs.clone(),
|
trait_ref.def_id,
|
||||||
empty_builtin_bounds()) })))
|
trait_ref.substs.clone(),
|
||||||
|
ty::region_existential_bound(trait_region))})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
|
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));
|
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={} \
|
debug!("construct_parameter_environment: free_id={} \
|
||||||
free_subst={} \
|
free_subst={} \
|
||||||
bounds={}",
|
bounds={}",
|
||||||
|
@ -5193,7 +5294,8 @@ pub fn construct_parameter_environment(
|
||||||
|
|
||||||
return ty::ParameterEnvironment {
|
return ty::ParameterEnvironment {
|
||||||
free_substs: free_substs,
|
free_substs: free_substs,
|
||||||
bounds: bounds
|
bounds: bounds,
|
||||||
|
implicit_region_bound: ty::ReScope(free_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
|
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
|
||||||
|
@ -5222,10 +5324,41 @@ pub fn construct_parameter_environment(
|
||||||
free_substs: &subst::Substs,
|
free_substs: &subst::Substs,
|
||||||
defs: &[TypeParameterDef]) {
|
defs: &[TypeParameterDef]) {
|
||||||
for def in defs.iter() {
|
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);
|
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 {
|
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)
|
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 {
|
fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef {
|
||||||
super_fold_autoref(self, ar)
|
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 {
|
impl TypeFoldable for ty::ParamBounds {
|
||||||
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ParamBounds {
|
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ParamBounds {
|
||||||
ty::ParamBounds {
|
ty::ParamBounds {
|
||||||
|
opt_region_bound: self.opt_region_bound.fold_with(folder),
|
||||||
builtin_bounds: self.builtin_bounds.fold_with(folder),
|
builtin_bounds: self.builtin_bounds.fold_with(folder),
|
||||||
trait_bounds: self.trait_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 {
|
impl TypeFoldable for ty::RegionParameterDef {
|
||||||
fn fold_with<F:TypeFolder>(&self, _folder: &mut F) -> ty::RegionParameterDef {
|
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::RegionParameterDef {
|
||||||
*self
|
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),
|
sig: fty.sig.fold_with(this),
|
||||||
fn_style: fty.fn_style,
|
fn_style: fty.fn_style,
|
||||||
onceness: fty.onceness,
|
onceness: fty.onceness,
|
||||||
bounds: fty.bounds,
|
bounds: fty.bounds.fold_with(this),
|
||||||
abi: fty.abi,
|
abi: fty.abi,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,7 +407,7 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
|
||||||
ty::ty_trait(box ty::TyTrait {
|
ty::ty_trait(box ty::TyTrait {
|
||||||
def_id: def_id,
|
def_id: def_id,
|
||||||
substs: substs.fold_with(this),
|
substs: substs.fold_with(this),
|
||||||
bounds: bounds
|
bounds: this.fold_existential_bounds(bounds),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::ty_tup(ref ts) => {
|
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,
|
pub fn super_fold_autoref<T:TypeFolder>(this: &mut T,
|
||||||
autoref: &ty::AutoRef)
|
autoref: &ty::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::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||||
use middle::subst::{VecPerParamSpace};
|
use middle::subst::{VecPerParamSpace};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::typeck::lookup_def_tcx;
|
||||||
use middle::typeck::rscope::RegionScope;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
|
use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope};
|
||||||
use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
|
use middle::typeck::rscope;
|
||||||
|
use middle::typeck::TypeAndSubsts;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::{Repr, UserString};
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::{ast, ast_util};
|
use syntax::{ast, ast_util};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::owned_slice::OwnedSlice;
|
|
||||||
use syntax::print::pprust::{lifetime_to_string, path_to_string};
|
|
||||||
|
|
||||||
pub trait AstConv {
|
pub trait AstConv {
|
||||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt;
|
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 {}",
|
debug!("ast_region_to_region(lifetime={} id={}) yields {}",
|
||||||
lifetime_to_string(lifetime),
|
lifetime.repr(tcx),
|
||||||
lifetime.id, r.repr(tcx));
|
lifetime.id,
|
||||||
|
r.repr(tcx));
|
||||||
|
|
||||||
r
|
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 {}",
|
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.repr(this.tcx()));
|
||||||
|
|
||||||
r
|
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>(
|
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
|
||||||
this: &AC,
|
this: &AC,
|
||||||
rscope: &RS,
|
rscope: &RS,
|
||||||
did: ast::DefId,
|
did: ast::DefId,
|
||||||
path: &ast::Path)
|
path: &ast::Path)
|
||||||
-> TypeAndSubsts
|
-> TypeAndSubsts
|
||||||
{
|
{
|
||||||
let tcx = this.tcx();
|
let tcx = this.tcx();
|
||||||
let ty::Polytype {
|
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 => {
|
None => {
|
||||||
tcx.sess.span_bug(ast_ty.span,
|
tcx.sess.span_bug(ast_ty.span,
|
||||||
format!("unbound path {}",
|
format!("unbound path {}",
|
||||||
path_to_string(path)).as_slice())
|
path.repr(tcx)).as_slice())
|
||||||
}
|
}
|
||||||
Some(&d) => d
|
Some(&d) => d
|
||||||
};
|
};
|
||||||
|
@ -430,7 +431,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
|
||||||
.sess
|
.sess
|
||||||
.span_bug(ast_ty.span,
|
.span_bug(ast_ty.span,
|
||||||
format!("unbound path {}",
|
format!("unbound path {}",
|
||||||
path_to_string(path)).as_slice())
|
path.repr(this.tcx())).as_slice())
|
||||||
}
|
}
|
||||||
Some(&d) => d
|
Some(&d) => d
|
||||||
};
|
};
|
||||||
|
@ -520,6 +521,16 @@ enum PointerTy {
|
||||||
Uniq
|
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,
|
pub fn trait_ref_for_unboxed_function<AC:AstConv,
|
||||||
RS:RegionScope>(
|
RS:RegionScope>(
|
||||||
this: &AC,
|
this: &AC,
|
||||||
|
@ -589,10 +600,11 @@ fn mk_pointer<AC:AstConv,
|
||||||
rscope,
|
rscope,
|
||||||
&**unboxed_function,
|
&**unboxed_function,
|
||||||
None);
|
None);
|
||||||
|
let r = ptr_ty.default_region();
|
||||||
let tr = ty::mk_trait(this.tcx(),
|
let tr = ty::mk_trait(this.tcx(),
|
||||||
def_id,
|
def_id,
|
||||||
substs,
|
substs,
|
||||||
ty::empty_builtin_bounds());
|
ty::region_existential_bound(r));
|
||||||
match ptr_ty {
|
match ptr_ty {
|
||||||
Uniq => {
|
Uniq => {
|
||||||
return ty::mk_uniq(this.tcx(), tr);
|
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"
|
// Note that the "bounds must be empty if path is not a trait"
|
||||||
// restriction is enforced in the below case for ty_path, which
|
// restriction is enforced in the below case for ty_path, which
|
||||||
// will run after this as long as the path isn't a trait.
|
// 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)) => {
|
Some(&def::DefTrait(trait_def_id)) => {
|
||||||
let result = ast_path_to_trait_ref(
|
let result = ast_path_to_trait_ref(
|
||||||
this, rscope, trait_def_id, None, path);
|
this, rscope, trait_def_id, None, path);
|
||||||
let static_region = match ptr_ty {
|
let bounds = match *opt_bounds {
|
||||||
RPtr(r) if r == ty::ReStatic => true,
|
None => {
|
||||||
_ => false
|
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,
|
let tr = ty::mk_trait(tcx,
|
||||||
result.def_id,
|
result.def_id,
|
||||||
result.substs.clone(),
|
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,
|
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
|
||||||
bf.abi, &*bf.decl))
|
bf.abi, &*bf.decl))
|
||||||
}
|
}
|
||||||
ast::TyClosure(ref f, ref region) => {
|
ast::TyClosure(ref f) => {
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Use corresponding trait store to figure out default bounds
|
// Use corresponding trait store to figure out default bounds
|
||||||
// if none were specified.
|
// if none were specified.
|
||||||
let bounds = conv_builtin_bounds(this.tcx(),
|
let bounds = conv_existential_bounds(this,
|
||||||
ast_ty.span,
|
rscope,
|
||||||
&f.bounds,
|
ast_ty.span,
|
||||||
bound_region == ty::ReStatic);
|
[].as_slice(),
|
||||||
|
f.bounds.as_slice());
|
||||||
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
|
|
||||||
let fn_decl = ty_of_closure(this,
|
let fn_decl = ty_of_closure(this,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
f.fn_style,
|
f.fn_style,
|
||||||
f.onceness,
|
f.onceness,
|
||||||
bounds,
|
bounds,
|
||||||
store,
|
ty::RegionTraitStore(
|
||||||
|
bounds.region_bound,
|
||||||
|
ast::MutMutable),
|
||||||
&*f.decl,
|
&*f.decl,
|
||||||
abi::Rust,
|
abi::Rust,
|
||||||
None);
|
None);
|
||||||
|
@ -766,10 +781,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
ast::TyProc(ref f) => {
|
ast::TyProc(ref f) => {
|
||||||
// Use corresponding trait store to figure out default bounds
|
// Use corresponding trait store to figure out default bounds
|
||||||
// if none were specified.
|
// if none were specified.
|
||||||
let bounds = conv_builtin_bounds(this.tcx(),
|
let bounds = conv_existential_bounds(this, rscope,
|
||||||
ast_ty.span,
|
ast_ty.span,
|
||||||
&f.bounds,
|
[].as_slice(),
|
||||||
false);
|
f.bounds.as_slice());
|
||||||
|
|
||||||
let fn_decl = ty_of_closure(this,
|
let fn_decl = ty_of_closure(this,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
|
@ -780,6 +795,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
&*f.decl,
|
&*f.decl,
|
||||||
abi::Rust,
|
abi::Rust,
|
||||||
None);
|
None);
|
||||||
|
|
||||||
ty::mk_closure(tcx, fn_decl)
|
ty::mk_closure(tcx, fn_decl)
|
||||||
}
|
}
|
||||||
ast::TyUnboxedFn(..) => {
|
ast::TyUnboxedFn(..) => {
|
||||||
|
@ -793,7 +809,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
tcx.sess
|
tcx.sess
|
||||||
.span_bug(ast_ty.span,
|
.span_bug(ast_ty.span,
|
||||||
format!("unbound path {}",
|
format!("unbound path {}",
|
||||||
path_to_string(path)).as_slice())
|
path.repr(tcx)).as_slice())
|
||||||
}
|
}
|
||||||
Some(&d) => d
|
Some(&d) => d
|
||||||
};
|
};
|
||||||
|
@ -808,16 +824,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
}
|
}
|
||||||
match a_def {
|
match a_def {
|
||||||
def::DefTrait(trait_def_id) => {
|
def::DefTrait(trait_def_id) => {
|
||||||
let result = ast_path_to_trait_ref(
|
let result = ast_path_to_trait_ref(
|
||||||
this, rscope, trait_def_id, None, path);
|
this, rscope, trait_def_id, None, path);
|
||||||
let bounds = conv_builtin_bounds(this.tcx(),
|
let empty_bounds: &[ast::TyParamBound] = &[];
|
||||||
path.span,
|
let ast_bounds = match *bounds {
|
||||||
bounds,
|
Some(ref b) => b.as_slice(),
|
||||||
false);
|
None => empty_bounds
|
||||||
ty::mk_trait(tcx,
|
};
|
||||||
result.def_id,
|
let bounds = conv_existential_bounds(this,
|
||||||
result.substs.clone(),
|
rscope,
|
||||||
bounds)
|
ast_ty.span,
|
||||||
|
&[result.clone()],
|
||||||
|
ast_bounds);
|
||||||
|
ty::mk_trait(tcx,
|
||||||
|
result.def_id,
|
||||||
|
result.substs.clone(),
|
||||||
|
bounds)
|
||||||
}
|
}
|
||||||
def::DefTy(did) | def::DefStruct(did) => {
|
def::DefTy(did) | def::DefStruct(did) => {
|
||||||
ast_path_to_ty(this, rscope, did, path).ty
|
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 {
|
match implied_output_region {
|
||||||
Some(implied_output_region) => {
|
Some(implied_output_region) => {
|
||||||
let rb = ImpliedSingleRscope {
|
let rb = SpecificRscope::new(implied_output_region);
|
||||||
region: implied_output_region,
|
|
||||||
};
|
|
||||||
ast_ty_to_ty(this, &rb, &*decl.output)
|
ast_ty_to_ty(this, &rb, &*decl.output)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -1130,7 +1150,7 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
fn_style: ast::FnStyle,
|
fn_style: ast::FnStyle,
|
||||||
onceness: ast::Onceness,
|
onceness: ast::Onceness,
|
||||||
bounds: ty::BuiltinBounds,
|
bounds: ty::ExistentialBounds,
|
||||||
store: ty::TraitStore,
|
store: ty::TraitStore,
|
||||||
decl: &ast::FnDecl,
|
decl: &ast::FnDecl,
|
||||||
abi: abi::Abi,
|
abi: abi::Abi,
|
||||||
|
@ -1176,67 +1196,250 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv_builtin_bounds(tcx: &ty::ctxt,
|
pub fn conv_existential_bounds<AC:AstConv, RS:RegionScope>(
|
||||||
span: Span,
|
this: &AC,
|
||||||
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
rscope: &RS,
|
||||||
static_region: bool)
|
span: Span,
|
||||||
-> ty::BuiltinBounds {
|
main_trait_refs: &[Rc<ty::TraitRef>],
|
||||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
ast_bounds: &[ast::TyParamBound])
|
||||||
//! struct. Reports an error if any of the bounds that appear
|
-> ty::ExistentialBounds
|
||||||
//! 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
|
* Given an existential type like `Foo+'a+Bar`, this routine
|
||||||
//! legal.
|
* converts the `'a` and `Bar` intos an `ExistentialBounds`
|
||||||
//! If no bounds were specified, we choose a "default" bound based on
|
* struct. The `main_trait_refs` argument specifies the `Foo` --
|
||||||
//! the allocation type of the fn/trait, as per issue #7264. The user can
|
* it is absent for closures. Eventually this should all be
|
||||||
//! override this with an empty bounds list, e.g. "Box<fn:()>" or
|
* normalized, I think, so that there is no "main trait ref" and
|
||||||
//! "Box<Trait:>".
|
* instead we just have a flat list of bounds as the existential
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
|
||||||
match ast_bounds {
|
let ast_bound_refs: Vec<&ast::TyParamBound> =
|
||||||
&Some(ref bound_vec) => {
|
ast_bounds.iter().collect();
|
||||||
let mut builtin_bounds = ty::empty_builtin_bounds();
|
|
||||||
for ast_bound in bound_vec.iter() {
|
let PartitionedBounds { builtin_bounds,
|
||||||
match *ast_bound {
|
trait_bounds,
|
||||||
ast::TraitTyParamBound(ref b) => {
|
region_bounds,
|
||||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
unboxed_fn_ty_bounds } =
|
||||||
def::DefTrait(trait_did) => {
|
partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
|
||||||
if ty::try_add_builtin_trait(tcx, trait_did,
|
|
||||||
&mut builtin_bounds) {
|
if !trait_bounds.is_empty() {
|
||||||
continue; // success
|
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());
|
||||||
tcx.sess.span_fatal(
|
}
|
||||||
b.path.span,
|
|
||||||
"only the builtin traits can be used as closure \
|
if !unboxed_fn_ty_bounds.is_empty() {
|
||||||
or object bounds");
|
this.tcx().sess.span_err(
|
||||||
}
|
span,
|
||||||
ast::StaticRegionTyParamBound => {
|
format!("only the builtin traits can be used \
|
||||||
builtin_bounds.add(ty::BoundStatic);
|
as closure or object bounds").as_slice());
|
||||||
}
|
}
|
||||||
ast::UnboxedFnTyParamBound(_) => {
|
|
||||||
tcx.sess.span_err(span,
|
// The "main trait refs", rather annoyingly, have no type
|
||||||
"unboxed functions are not allowed \
|
// specified for the `Self` parameter of the trait. The reason for
|
||||||
here");
|
// this is that they are, after all, *existential* types, and
|
||||||
}
|
// hence that type is unknown. However, leaving this type missing
|
||||||
ast::OtherRegionTyParamBound(span) => {
|
// causes the substitution code to go all awry when walking the
|
||||||
if !tcx.sess.features.issue_5723_bootstrap.get() {
|
// bounds, so here we clone those trait refs and insert ty::err as
|
||||||
tcx.sess.span_err(
|
// the self type. Perhaps we should do this more generally, it'd
|
||||||
span,
|
// be convenient (or perhaps something else, i.e., ty::erased).
|
||||||
"only the 'static lifetime is accepted \
|
let main_trait_refs: Vec<Rc<ty::TraitRef>> =
|
||||||
here.");
|
main_trait_refs.iter()
|
||||||
}
|
.map(|t|
|
||||||
}
|
Rc::new(ty::TraitRef {
|
||||||
}
|
def_id: t.def_id,
|
||||||
}
|
substs: t.substs.with_self_ty(ty::mk_err()) }))
|
||||||
builtin_bounds
|
.collect();
|
||||||
},
|
|
||||||
// &'static Trait is sugar for &'static Trait:'static.
|
let region_bound = compute_region_bound(this,
|
||||||
&None if static_region => {
|
rscope,
|
||||||
let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set
|
span,
|
||||||
}
|
builtin_bounds,
|
||||||
&None => ty::empty_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::astconv::AstConv;
|
||||||
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
|
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
|
||||||
use middle::typeck::check;
|
use middle::typeck::check;
|
||||||
use middle::typeck::infer::MiscVariable;
|
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::MethodCallee;
|
use middle::typeck::MethodCallee;
|
||||||
use middle::typeck::{MethodOrigin, MethodParam};
|
use middle::typeck::{MethodOrigin, MethodParam};
|
||||||
|
@ -240,6 +239,7 @@ fn construct_transformed_self_ty_for_object(
|
||||||
span: Span,
|
span: Span,
|
||||||
trait_def_id: ast::DefId,
|
trait_def_id: ast::DefId,
|
||||||
rcvr_substs: &subst::Substs,
|
rcvr_substs: &subst::Substs,
|
||||||
|
rcvr_bounds: ty::ExistentialBounds,
|
||||||
method_ty: &ty::Method)
|
method_ty: &ty::Method)
|
||||||
-> ty::t
|
-> ty::t
|
||||||
{
|
{
|
||||||
|
@ -276,8 +276,7 @@ fn construct_transformed_self_ty_for_object(
|
||||||
tcx.sess.span_bug(span, "static method for object type receiver");
|
tcx.sess.span_bug(span, "static method for object type receiver");
|
||||||
}
|
}
|
||||||
ByValueExplicitSelfCategory => {
|
ByValueExplicitSelfCategory => {
|
||||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds);
|
||||||
ty::empty_builtin_bounds());
|
|
||||||
ty::mk_uniq(tcx, tr)
|
ty::mk_uniq(tcx, tr)
|
||||||
}
|
}
|
||||||
ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
|
ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
|
||||||
|
@ -286,12 +285,12 @@ fn construct_transformed_self_ty_for_object(
|
||||||
ty::ty_rptr(r, mt) => { // must be SelfRegion
|
ty::ty_rptr(r, mt) => { // must be SelfRegion
|
||||||
let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
|
let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
|
||||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
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::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
|
||||||
}
|
}
|
||||||
ty::ty_uniq(_) => { // must be SelfUniq
|
ty::ty_uniq(_) => { // must be SelfUniq
|
||||||
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
|
||||||
ty::empty_builtin_bounds());
|
rcvr_bounds);
|
||||||
ty::mk_uniq(tcx, tr)
|
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);
|
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||||
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
||||||
match get(self_ty).sty {
|
match get(self_ty).sty {
|
||||||
ty_trait(box TyTrait { def_id, ref substs, .. }) => {
|
ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
|
||||||
self.push_inherent_candidates_from_object(def_id, substs);
|
self.push_inherent_candidates_from_object(
|
||||||
|
def_id, substs, bounds);
|
||||||
self.push_inherent_impl_candidates_for_type(def_id);
|
self.push_inherent_impl_candidates_for_type(def_id);
|
||||||
}
|
}
|
||||||
ty_enum(did, _) |
|
ty_enum(did, _) |
|
||||||
|
@ -538,15 +538,13 @@ impl<'a> LookupContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let vcx = self.fcx.vtable_context();
|
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.
|
// Get the tupled type of the arguments.
|
||||||
let arguments_type = *closure_function_type.sig.inputs.get(0);
|
let arguments_type = *closure_function_type.sig.inputs.get(0);
|
||||||
let return_type = closure_function_type.sig.output;
|
let return_type = closure_function_type.sig.output;
|
||||||
|
|
||||||
let closure_region =
|
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(),
|
let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
|
||||||
closure_did,
|
closure_did,
|
||||||
closure_region);
|
closure_region);
|
||||||
|
@ -555,7 +553,7 @@ impl<'a> LookupContext<'a> {
|
||||||
RcvrMatchesIfSubtype(unboxed_closure_type),
|
RcvrMatchesIfSubtype(unboxed_closure_type),
|
||||||
rcvr_substs: subst::Substs::new_trait(
|
rcvr_substs: subst::Substs::new_trait(
|
||||||
vec![arguments_type, return_type],
|
vec![arguments_type, return_type],
|
||||||
region_params,
|
vec![],
|
||||||
*vcx.infcx.next_ty_vars(1).get(0)),
|
*vcx.infcx.next_ty_vars(1).get(0)),
|
||||||
method_ty: method,
|
method_ty: method,
|
||||||
origin: MethodStaticUnboxedClosure(closure_did),
|
origin: MethodStaticUnboxedClosure(closure_did),
|
||||||
|
@ -595,11 +593,11 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
fn push_inherent_candidates_from_object(&mut self,
|
fn push_inherent_candidates_from_object(&mut self,
|
||||||
did: DefId,
|
did: DefId,
|
||||||
substs: &subst::Substs) {
|
substs: &subst::Substs,
|
||||||
|
bounds: ty::ExistentialBounds) {
|
||||||
debug!("push_inherent_candidates_from_object(did={}, substs={})",
|
debug!("push_inherent_candidates_from_object(did={}, substs={})",
|
||||||
self.did_to_string(did),
|
self.did_to_string(did),
|
||||||
substs.repr(self.tcx()));
|
substs.repr(self.tcx()));
|
||||||
let _indenter = indenter();
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let span = self.span;
|
let span = self.span;
|
||||||
|
|
||||||
|
@ -617,28 +615,30 @@ impl<'a> LookupContext<'a> {
|
||||||
substs: rcvr_substs.clone()
|
substs: rcvr_substs.clone()
|
||||||
});
|
});
|
||||||
|
|
||||||
self.push_inherent_candidates_from_bounds_inner(&[trait_ref.clone()],
|
self.push_inherent_candidates_from_bounds_inner(
|
||||||
|new_trait_ref, m, method_num, _bound_num| {
|
&[trait_ref.clone()],
|
||||||
let vtable_index = get_method_index(tcx, &*new_trait_ref,
|
|_this, new_trait_ref, m, method_num, _bound_num| {
|
||||||
trait_ref.clone(), method_num);
|
let vtable_index =
|
||||||
let mut m = (*m).clone();
|
get_method_index(tcx, &*new_trait_ref,
|
||||||
// We need to fix up the transformed self type.
|
trait_ref.clone(), method_num);
|
||||||
*m.fty.sig.inputs.get_mut(0) =
|
let mut m = (*m).clone();
|
||||||
construct_transformed_self_ty_for_object(
|
// We need to fix up the transformed self type.
|
||||||
tcx, span, did, &rcvr_substs, &m);
|
*m.fty.sig.inputs.get_mut(0) =
|
||||||
|
construct_transformed_self_ty_for_object(
|
||||||
|
tcx, span, did, &rcvr_substs, bounds, &m);
|
||||||
|
|
||||||
Some(Candidate {
|
Some(Candidate {
|
||||||
rcvr_match_condition: RcvrMatchesIfObject(did),
|
rcvr_match_condition: RcvrMatchesIfObject(did),
|
||||||
rcvr_substs: new_trait_ref.substs.clone(),
|
rcvr_substs: new_trait_ref.substs.clone(),
|
||||||
method_ty: Rc::new(m),
|
method_ty: Rc::new(m),
|
||||||
origin: MethodObject(MethodObject {
|
origin: MethodObject(MethodObject {
|
||||||
trait_id: new_trait_ref.def_id,
|
trait_id: new_trait_ref.def_id,
|
||||||
object_trait_id: did,
|
object_trait_id: did,
|
||||||
method_num: method_num,
|
method_num: method_num,
|
||||||
real_index: vtable_index
|
real_index: vtable_index
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_inherent_candidates_from_param(&mut self,
|
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
|
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
|
||||||
.as_slice();
|
.as_slice();
|
||||||
self.push_inherent_candidates_from_bounds_inner(bounds,
|
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 {
|
match restrict_to {
|
||||||
Some(trait_did) => {
|
Some(trait_did) => {
|
||||||
if trait_did != trait_ref.def_id {
|
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 {
|
Some(Candidate {
|
||||||
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
||||||
rcvr_substs: trait_ref.substs.clone(),
|
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
|
// Do a search through a list of bounds, using a callback to actually
|
||||||
// create the candidates.
|
// create the candidates.
|
||||||
fn push_inherent_candidates_from_bounds_inner(&mut self,
|
fn push_inherent_candidates_from_bounds_inner(
|
||||||
bounds: &[Rc<TraitRef>],
|
&mut self,
|
||||||
mk_cand: |tr: Rc<TraitRef>,
|
bounds: &[Rc<TraitRef>],
|
||||||
m: Rc<ty::Method>,
|
mk_cand: |this: &mut LookupContext,
|
||||||
method_num: uint,
|
tr: Rc<TraitRef>,
|
||||||
bound_num: uint|
|
m: Rc<ty::Method>,
|
||||||
-> Option<Candidate>) {
|
method_num: uint,
|
||||||
|
bound_num: uint|
|
||||||
|
-> Option<Candidate>) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let mut next_bound_idx = 0; // count only trait bounds
|
let mut next_bound_idx = 0; // count only trait bounds
|
||||||
|
|
||||||
|
@ -719,7 +733,8 @@ impl<'a> LookupContext<'a> {
|
||||||
ty::MethodTraitItem(ref method) => (*method).clone(),
|
ty::MethodTraitItem(ref method) => (*method).clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match mk_cand(bound_trait_ref,
|
match mk_cand(self,
|
||||||
|
bound_trait_ref,
|
||||||
method,
|
method,
|
||||||
pos,
|
pos,
|
||||||
this_bound_idx) {
|
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 {
|
MethodCallee {
|
||||||
origin: candidate.origin,
|
origin: candidate.origin,
|
||||||
ty: fty,
|
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::ty;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::check::FnCtxt;
|
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_and_force_all_but_regions;
|
||||||
use middle::typeck::infer::resolve_type;
|
use middle::typeck::infer::resolve_type;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::MethodCall;
|
use middle::typeck::MethodCall;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use util::nodemap::{DefIdMap, NodeMap};
|
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::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
@ -143,6 +143,46 @@ use syntax::visit::Visitor;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::gc::Gc;
|
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
|
// If mem categorization results in an error, it's because the type
|
||||||
// check failed (or will fail, when the error is uncovered and
|
// check failed (or will fail, when the error is uncovered and
|
||||||
// reported during writeback). In this case, we just ignore this part
|
// reported during writeback). In this case, we just ignore this part
|
||||||
|
@ -159,10 +199,32 @@ macro_rules! ignore_err(
|
||||||
pub struct Rcx<'a> {
|
pub struct Rcx<'a> {
|
||||||
fcx: &'a FnCtxt<'a>,
|
fcx: &'a FnCtxt<'a>,
|
||||||
|
|
||||||
|
region_param_pairs: Vec<(ty::Region, ty::ParamTy)>,
|
||||||
|
|
||||||
// id of innermost fn or loop
|
// id of innermost fn or loop
|
||||||
repeating_scope: ast::NodeId,
|
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 {
|
fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
|
||||||
/*!
|
/*!
|
||||||
* Returns the validity region of `def` -- that is, how long
|
* 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> {
|
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 {
|
pub fn tcx(&self) -> &'a ty::ctxt {
|
||||||
self.fcx.ccx.tcx
|
self.fcx.ccx.tcx
|
||||||
}
|
}
|
||||||
|
@ -259,6 +328,114 @@ impl<'a> Rcx<'a> {
|
||||||
|method_call| self.resolve_method_type(method_call))
|
|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> {
|
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> {
|
impl<'a> Visitor<()> for Rcx<'a> {
|
||||||
// (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
|
// (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
|
||||||
// However, right now we run into an issue whereby some free
|
// 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
|
// hierarchy, and in particular the relationships between free
|
||||||
// regions, until regionck, as described in #3238.
|
// 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_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
|
||||||
|
|
||||||
fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
|
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.
|
// variable's type enclose at least the variable's scope.
|
||||||
|
|
||||||
let var_region = tcx.region_maps.var_region(id);
|
let var_region = tcx.region_maps.var_region(id);
|
||||||
constrain_regions_in_type_of_node(
|
type_of_node_must_outlive(
|
||||||
rcx, id, var_region,
|
rcx, infer::BindingTypeIsNotValidAtDecl(span),
|
||||||
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={:?})",
|
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
|
||||||
expr.repr(rcx.fcx.tcx()), rcx.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 method_call = MethodCall::expr(expr.id);
|
||||||
let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
|
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}) => {
|
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
|
||||||
let expr_ty = rcx.resolve_node_type(expr.id);
|
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||||
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
|
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
|
||||||
match ty::adjusted_object_region(adjustment) {
|
for autoref in opt_autoref.iter() {
|
||||||
Some(trait_region) => {
|
link_autoref(rcx, expr, autoderefs, autoref);
|
||||||
// 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.
|
|
||||||
|
|
||||||
constrain_regions_in_type(rcx, trait_region,
|
// Require that the resulting region encompasses
|
||||||
infer::RelateObjectBound(expr.span), expr_ty);
|
// the current node.
|
||||||
}
|
//
|
||||||
None => {
|
// FIXME(#6268) remove to support nested method calls
|
||||||
for autoref in opt_autoref.iter() {
|
type_of_node_must_outlive(
|
||||||
link_autoref(rcx, expr, autoderefs, autoref);
|
rcx, infer::AutoBorrow(expr.span),
|
||||||
|
expr.id, ty::ReScope(expr.id));
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
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 {
|
match expr.node {
|
||||||
ast::ExprCall(ref callee, ref args) => {
|
ast::ExprCall(ref callee, ref args) => {
|
||||||
if has_method_map {
|
if has_method_map {
|
||||||
constrain_call(rcx, None, expr, Some(*callee),
|
constrain_call(rcx, expr, Some(*callee),
|
||||||
args.as_slice(), false);
|
args.as_slice(), false);
|
||||||
} else {
|
} else {
|
||||||
constrain_callee(rcx, callee.id, expr, &**callee);
|
constrain_callee(rcx, callee.id, expr, &**callee);
|
||||||
constrain_call(rcx,
|
constrain_call(rcx,
|
||||||
Some(callee.id),
|
|
||||||
expr,
|
expr,
|
||||||
None,
|
None,
|
||||||
args.as_slice(),
|
args.as_slice(),
|
||||||
|
@ -473,7 +629,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprMethodCall(_, _, ref args) => {
|
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);
|
args.slice_from(1), false);
|
||||||
|
|
||||||
visit::walk_expr(rcx, expr, ());
|
visit::walk_expr(rcx, expr, ());
|
||||||
|
@ -486,7 +642,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||||
|
|
||||||
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
|
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||||
if has_method_map {
|
if has_method_map {
|
||||||
constrain_call(rcx, None, expr, Some(lhs.clone()),
|
constrain_call(rcx, expr, Some(lhs.clone()),
|
||||||
[rhs.clone()], true);
|
[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
|
// overloaded op. Note that we (sadly) currently use an
|
||||||
// implicit "by ref" sort of passing style here. This
|
// implicit "by ref" sort of passing style here. This
|
||||||
// should be converted to an adjustment!
|
// should be converted to an adjustment!
|
||||||
constrain_call(rcx, None, expr, Some(lhs.clone()),
|
constrain_call(rcx, expr, Some(lhs.clone()),
|
||||||
[rhs.clone()], true);
|
[rhs.clone()], true);
|
||||||
|
|
||||||
visit::walk_expr(rcx, expr, ());
|
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 => {
|
ast::ExprUnary(_, ref lhs) if has_method_map => {
|
||||||
// As above.
|
// As above.
|
||||||
constrain_call(rcx, None, expr, Some(lhs.clone()), [], true);
|
constrain_call(rcx, expr, Some(lhs.clone()), [], true);
|
||||||
|
|
||||||
visit::walk_expr(rcx, expr, ());
|
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) => {
|
ast::ExprUnary(ast::UnDeref, ref base) => {
|
||||||
// For *a, the lifetime of a must enclose the deref
|
// For *a, the lifetime of a must enclose the deref
|
||||||
let method_call = MethodCall::expr(expr.id);
|
let method_call = MethodCall::expr(expr.id);
|
||||||
let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
|
let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
|
||||||
Some(method) => {
|
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)
|
ty::ty_fn_ret(method.ty)
|
||||||
}
|
}
|
||||||
None => rcx.resolve_node_type(base.id)
|
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
|
// Determine if we are casting `source` to a trait
|
||||||
// instance. If so, we have to be sure that the type of
|
// instance. If so, we have to be sure that the type of
|
||||||
// the source obeys the trait's region bound.
|
// the source obeys the trait's region bound.
|
||||||
//
|
constrain_cast(rcx, expr, &**source);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
visit::walk_expr(rcx, expr, ());
|
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
|
// FIXME(#6268) nested method calls requires that this rule change
|
||||||
let ty0 = rcx.resolve_node_type(expr.id);
|
let ty0 = rcx.resolve_node_type(expr.id);
|
||||||
constrain_regions_in_type(rcx, ty::ReScope(expr.id),
|
type_must_outlive(rcx, infer::AddrOf(expr.span),
|
||||||
infer::AddrOf(expr.span), ty0);
|
ty0, ty::ReScope(expr.id));
|
||||||
visit::walk_expr(rcx, expr, ());
|
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,
|
fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
body: &ast::Block) {
|
body: &ast::Block) {
|
||||||
let tcx = rcx.fcx.tcx();
|
let tcx = rcx.fcx.tcx();
|
||||||
let function_type = rcx.resolve_node_type(expr.id);
|
let function_type = rcx.resolve_node_type(expr.id);
|
||||||
|
|
||||||
match ty::get(function_type).sty {
|
match ty::get(function_type).sty {
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..),
|
||||||
store: ty::RegionTraitStore(region, _), ..}) => {
|
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| {
|
freevars::with_freevars(tcx, expr.id, |freevars| {
|
||||||
if freevars.is_empty() {
|
if freevars.is_empty() {
|
||||||
// No free variables means that the environment
|
// No free variables means that the environment
|
||||||
// will be NULL at runtime and hence the closure
|
// will be NULL at runtime and hence the closure
|
||||||
// has static lifetime.
|
// has static lifetime.
|
||||||
} else {
|
} else {
|
||||||
// Closure must not outlive the variables it closes over.
|
// Variables being referenced must outlive closure.
|
||||||
constrain_free_variables(rcx, region, expr, freevars);
|
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;
|
let s = rcx.repeating_scope;
|
||||||
rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
|
rcx.fcx.mk_subr(infer::InfStackClosure(expr.span),
|
||||||
region, ty::ReScope(s));
|
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) => {
|
ty::ty_unboxed_closure(_, region) => {
|
||||||
freevars::with_freevars(tcx, expr.id, |freevars| {
|
freevars::with_freevars(tcx, expr.id, |freevars| {
|
||||||
// No free variables means that there is no environment and
|
// No free variables means that there is no environment and
|
||||||
// hence the closure has static lifetime. Otherwise, the
|
// hence the closure has static lifetime. Otherwise, the
|
||||||
// closure must not outlive the variables it closes over
|
// closure must not outlive the variables it closes over
|
||||||
// by-reference.
|
// by-reference.
|
||||||
|
//
|
||||||
|
// NDM -- this seems wrong, discuss with pcwalton, should
|
||||||
|
// be straightforward enough.
|
||||||
if !freevars.is_empty() {
|
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);
|
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,
|
fn ensure_free_variable_types_outlive_closure_bound(
|
||||||
region: ty::Region,
|
rcx: &mut Rcx,
|
||||||
expr: &ast::Expr,
|
region_bound: ty::Region,
|
||||||
freevars: &[freevars::freevar_entry]) {
|
expr: &ast::Expr,
|
||||||
|
freevars: &[freevars::freevar_entry])
|
||||||
|
{
|
||||||
/*!
|
/*!
|
||||||
* Make sure that all free variables referenced inside the closure
|
* Make sure that the type of all free variables referenced
|
||||||
* outlive the closure itself. Also, create an entry in the
|
* inside a closure/proc outlive the closure/proc's lifetime
|
||||||
* upvar_borrows map with a region.
|
* 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 tcx = rcx.fcx.ccx.tcx;
|
||||||
let infcx = rcx.fcx.infcx();
|
let infcx = rcx.fcx.infcx();
|
||||||
debug!("constrain_free_variables({}, {})",
|
debug!("constrain_free_variables({}, {})",
|
||||||
region.repr(tcx), expr.repr(tcx));
|
region_bound.repr(tcx), expr.repr(tcx));
|
||||||
for freevar in freevars.iter() {
|
for freevar in freevars.iter() {
|
||||||
debug!("freevar def is {:?}", freevar.def);
|
debug!("freevar def is {:?}", freevar.def);
|
||||||
|
|
||||||
// Identify the variable being closed over and its node-id.
|
// Identify the variable being closed over and its node-id.
|
||||||
let def = freevar.def;
|
let def = freevar.def;
|
||||||
let def_id = def.def_id();
|
let var_node_id = {
|
||||||
assert!(def_id.krate == ast::LOCAL_CRATE);
|
let def_id = def.def_id();
|
||||||
let upvar_id = ty::UpvarId { var_id: def_id.node,
|
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 };
|
closure_expr_id: expr.id };
|
||||||
|
|
||||||
// Create a region variable to represent this borrow. This borrow
|
// Create a region variable to represent this borrow. This borrow
|
||||||
// must outlive the region on the closure.
|
// must outlive the region on the closure.
|
||||||
let origin = infer::UpvarRegion(upvar_id, expr.span);
|
let origin = infer::UpvarRegion(upvar_id, expr.span);
|
||||||
let freevar_region = infcx.next_region_var(origin);
|
let freevar_region = infcx.next_region_var(origin);
|
||||||
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
|
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||||
region, freevar_region);
|
region_bound, freevar_region);
|
||||||
|
|
||||||
// Create a UpvarBorrow entry. Note that we begin with a
|
// Create a UpvarBorrow entry. Note that we begin with a
|
||||||
// const borrow_kind, but change it to either mut or
|
// const borrow_kind, but change it to either mut or
|
||||||
|
@ -738,10 +979,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
upvar_borrow);
|
upvar_borrow);
|
||||||
|
|
||||||
// Guarantee that the closure does not outlive the variable itself.
|
// Guarantee that the closure does not outlive the variable itself.
|
||||||
let en_region = region_of_def(rcx.fcx, def);
|
let enclosing_region = region_of_def(rcx.fcx, def);
|
||||||
debug!("en_region = {}", en_region.repr(tcx));
|
debug!("enclosing_region = {}", enclosing_region.repr(tcx));
|
||||||
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
|
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||||
region, en_region);
|
region_bound, enclosing_region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,7 +1058,7 @@ fn constrain_callee(rcx: &mut Rcx,
|
||||||
}
|
}
|
||||||
ty::UniqTraitStore => ty::ReStatic
|
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);
|
call_region, region);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -832,9 +1073,6 @@ fn constrain_callee(rcx: &mut Rcx,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constrain_call(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,
|
call_expr: &ast::Expr,
|
||||||
receiver: Option<Gc<ast::Expr>>,
|
receiver: Option<Gc<ast::Expr>>,
|
||||||
arg_exprs: &[Gc<ast::Expr>],
|
arg_exprs: &[Gc<ast::Expr>],
|
||||||
|
@ -853,16 +1091,6 @@ fn constrain_call(rcx: &mut Rcx,
|
||||||
receiver.repr(tcx),
|
receiver.repr(tcx),
|
||||||
arg_exprs.repr(tcx),
|
arg_exprs.repr(tcx),
|
||||||
implicitly_ref_args);
|
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
|
// `callee_region` is the scope representing the time in which the
|
||||||
// call occurs.
|
// call occurs.
|
||||||
|
@ -871,14 +1099,16 @@ fn constrain_call(rcx: &mut Rcx,
|
||||||
let callee_scope = call_expr.id;
|
let callee_scope = call_expr.id;
|
||||||
let callee_region = ty::ReScope(callee_scope);
|
let callee_region = ty::ReScope(callee_scope);
|
||||||
|
|
||||||
|
debug!("callee_region={}", callee_region.repr(tcx));
|
||||||
|
|
||||||
for arg_expr in arg_exprs.iter() {
|
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
|
// ensure that any regions appearing in the argument type are
|
||||||
// valid for at least the lifetime of the function:
|
// valid for at least the lifetime of the function:
|
||||||
constrain_regions_in_type_of_node(
|
type_of_node_must_outlive(
|
||||||
rcx, arg_expr.id, callee_region,
|
rcx, infer::CallArg(arg_expr.span),
|
||||||
infer::CallArg(arg_expr.span));
|
arg_expr.id, callee_region);
|
||||||
|
|
||||||
// unfortunately, there are two means of taking implicit
|
// unfortunately, there are two means of taking implicit
|
||||||
// references, and we need to propagate constraints as a
|
// 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
|
// as loop above, but for receiver
|
||||||
for r in receiver.iter() {
|
for r in receiver.iter() {
|
||||||
debug!("Receiver");
|
debug!("receiver: {}", r.repr(tcx));
|
||||||
constrain_regions_in_type_of_node(
|
type_of_node_must_outlive(
|
||||||
rcx, r.id, callee_region, infer::CallRcvr(r.span));
|
rcx, infer::CallRcvr(r.span),
|
||||||
|
r.id, callee_region);
|
||||||
if implicitly_ref_args {
|
if implicitly_ref_args {
|
||||||
link_by_ref(rcx, &**r, callee_scope);
|
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,
|
fn constrain_autoderefs(rcx: &mut Rcx,
|
||||||
|
@ -942,12 +1167,10 @@ fn constrain_autoderefs(rcx: &mut Rcx,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialized version of constrain_call.
|
// Specialized version of constrain_call.
|
||||||
constrain_regions_in_type(rcx, r_deref_expr,
|
type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
|
||||||
infer::CallRcvr(deref_expr.span),
|
self_ty, r_deref_expr);
|
||||||
self_ty);
|
type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
|
||||||
constrain_regions_in_type(rcx, r_deref_expr,
|
fn_sig.output, r_deref_expr);
|
||||||
infer::CallReturn(deref_expr.span),
|
|
||||||
fn_sig.output);
|
|
||||||
fn_sig.output
|
fn_sig.output
|
||||||
}
|
}
|
||||||
None => derefd_ty
|
None => derefd_ty
|
||||||
|
@ -974,7 +1197,7 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
|
||||||
deref_span: Span,
|
deref_span: Span,
|
||||||
minimum_lifetime: ty::Region,
|
minimum_lifetime: ty::Region,
|
||||||
maximum_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)
|
minimum_lifetime, maximum_lifetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,7 +1219,7 @@ fn constrain_index(rcx: &mut Rcx,
|
||||||
match ty::get(indexed_ty).sty {
|
match ty::get(indexed_ty).sty {
|
||||||
ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
|
ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
|
||||||
ty::ty_vec(_, None) | ty::ty_str => {
|
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);
|
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,
|
rcx: &mut Rcx,
|
||||||
|
origin: infer::SubregionOrigin,
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
minimum_lifetime: ty::Region,
|
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
|
* Guarantees that any lifetimes which appear in the type of
|
||||||
//! least `minimum_lifetime`
|
* the node `id` (after applying adjustments) are valid for at
|
||||||
|
* least `minimum_lifetime`
|
||||||
|
*/
|
||||||
|
|
||||||
let tcx = rcx.fcx.tcx();
|
let tcx = rcx.fcx.tcx();
|
||||||
|
|
||||||
|
@ -1028,54 +1254,7 @@ fn constrain_regions_in_type_of_node(
|
||||||
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
|
||||||
ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
|
ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
|
||||||
id, minimum_lifetime);
|
id, minimum_lifetime);
|
||||||
constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
|
type_must_outlive(rcx, origin, ty, minimum_lifetime);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
||||||
|
@ -1290,7 +1469,7 @@ fn link_region(rcx: &Rcx,
|
||||||
debug!("link_region: {} <= {}",
|
debug!("link_region: {} <= {}",
|
||||||
region_min.repr(rcx.tcx()),
|
region_min.repr(rcx.tcx()),
|
||||||
r_borrowed.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 kind != ty::ImmBorrow {
|
||||||
// If this is a mutable borrow, then the thing
|
// 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)]
|
// #![warn(deprecated_mode)]
|
||||||
|
|
||||||
|
use middle::subst::{ParamSpace, Subst, Substs};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
use util::ppaux;
|
|
||||||
|
|
||||||
// Helper functions related to manipulating region types.
|
// Helper functions related to manipulating region types.
|
||||||
|
|
||||||
|
@ -44,125 +46,363 @@ pub fn replace_late_bound_regions_in_fn_sig(
|
||||||
(map, fn_sig)
|
(map, fn_sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relate_nested_regions(tcx: &ty::ctxt,
|
pub enum WfConstraint {
|
||||||
opt_region: Option<ty::Region>,
|
RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
|
||||||
ty: ty::t,
|
RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
|
||||||
relate_op: |ty::Region, ty::Region|) {
|
}
|
||||||
|
|
||||||
|
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
|
* This routine computes the well-formedness constraints that must
|
||||||
* in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
|
* hold for the type `ty` to appear in a context with lifetime
|
||||||
* here is the region of any enclosing `&'r T` pointer. If there is
|
* `outer_region`
|
||||||
* 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`.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut rr = RegionRelator { tcx: tcx,
|
let mut stack = Vec::new();
|
||||||
stack: Vec::new(),
|
stack.push((outer_region, None));
|
||||||
relate_op: relate_op };
|
let mut wf = Wf { tcx: tcx,
|
||||||
match opt_region {
|
stack: stack,
|
||||||
Some(o_r) => { rr.stack.push(o_r); }
|
out: Vec::new() };
|
||||||
None => {}
|
wf.accumulate_from_ty(ty);
|
||||||
}
|
wf.out
|
||||||
rr.fold_ty(ty);
|
}
|
||||||
|
|
||||||
struct RegionRelator<'a> {
|
impl<'a> Wf<'a> {
|
||||||
tcx: &'a ty::ctxt,
|
fn accumulate_from_ty(&mut self, ty: ty::t) {
|
||||||
stack: Vec<ty::Region>,
|
debug!("Wf::accumulate_from_ty(ty={})",
|
||||||
relate_op: |ty::Region, ty::Region|: 'a,
|
ty.repr(self.tcx));
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(#10151) -- Define more precisely when a region is
|
match ty::get(ty).sty {
|
||||||
// considered "nested". Consider taking variance into account as
|
ty::ty_nil |
|
||||||
// well.
|
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> {
|
ty::ty_closure(box ref c) => {
|
||||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
|
self.accumulate_from_closure_ty(ty, c);
|
||||||
self.tcx
|
}
|
||||||
|
|
||||||
|
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 {
|
fn accumulate_from_rptr(&mut self,
|
||||||
match ty::get(ty).sty {
|
ty: ty::t,
|
||||||
ty::ty_rptr(r, ty::mt {ty, ..}) => {
|
r_b: ty::Region,
|
||||||
self.relate(r);
|
ty_b: ty::t) {
|
||||||
self.stack.push(r);
|
// We are walking down a type like this, and current
|
||||||
ty_fold::super_fold_ty(self, ty);
|
// 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();
|
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 accumulate_from_closure_ty(&mut self,
|
||||||
fn relate(&mut self, r_sub: ty::Region) {
|
ty: ty::t,
|
||||||
for &r in self.stack.iter() {
|
c: &ty::ClosureTy)
|
||||||
if !r.is_bound() && !r_sub.is_bound() {
|
{
|
||||||
(self.relate_op)(r, r_sub);
|
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 result = type_param_defs.map_rev(|def| {
|
||||||
let ty = *substs.types.get(def.space, def.index);
|
let ty = *substs.types.get(def.space, def.index);
|
||||||
lookup_vtables_for_param(vcx, span, Some(substs),
|
lookup_vtables_for_param(vcx, span, Some(substs),
|
||||||
&*def.bounds, ty, is_early)
|
&def.bounds, ty, is_early)
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("lookup_vtables result(\
|
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
|
// use a dummy type just to package up the substs that need fixing up
|
||||||
let t = ty::mk_trait(tcx,
|
let t = ty::mk_trait(tcx,
|
||||||
id, substs,
|
id, substs,
|
||||||
ty::empty_builtin_bounds());
|
ty::region_existential_bound(ty::ReStatic));
|
||||||
fixup_ty(vcx, span, t, is_early).map(|t_f| {
|
fixup_ty(vcx, span, t, is_early).map(|t_f| {
|
||||||
match ty::get(t_f).sty {
|
match ty::get(t_f).sty {
|
||||||
ty::ty_trait(ref inner) => inner.substs.clone(),
|
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_uniq(..), &ty::ty_uniq(..) ) => {}
|
||||||
(&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
|
(&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
|
||||||
infer::mk_subr(fcx.infcx(),
|
infer::mk_subr(fcx.infcx(),
|
||||||
false,
|
|
||||||
infer::RelateObjectBound(ex.span),
|
infer::RelateObjectBound(ex.span),
|
||||||
r_t,
|
r_t,
|
||||||
r_s);
|
r_s);
|
||||||
|
@ -702,9 +701,11 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||||
});
|
});
|
||||||
|
|
||||||
let param_bounds = ty::ParamBounds {
|
let param_bounds = ty::ParamBounds {
|
||||||
|
opt_region_bound: None,
|
||||||
builtin_bounds: ty::empty_builtin_bounds(),
|
builtin_bounds: ty::empty_builtin_bounds(),
|
||||||
trait_bounds: vec!(target_trait_ref)
|
trait_bounds: vec!(target_trait_ref)
|
||||||
};
|
};
|
||||||
|
|
||||||
let vtables =
|
let vtables =
|
||||||
lookup_vtables_for_param(&vcx,
|
lookup_vtables_for_param(&vcx,
|
||||||
ex.span,
|
ex.span,
|
||||||
|
|
|
@ -42,47 +42,31 @@ use middle::ty::{Polytype};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
use middle::typeck::astconv::{AstConv, ty_of_arg};
|
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::astconv;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::rscope::*;
|
use middle::typeck::rscope::*;
|
||||||
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::{Repr,UserString};
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::gc::Gc;
|
use std::gc::Gc;
|
||||||
|
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
|
|
||||||
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_map;
|
use syntax::ast_map;
|
||||||
use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod};
|
use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::codemap;
|
use syntax::parse::token::{special_idents};
|
||||||
use syntax::owned_slice::OwnedSlice;
|
|
||||||
use syntax::parse::token::special_idents;
|
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::pprust::{path_to_string};
|
use syntax::print::pprust::{path_to_string};
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
|
|
||||||
struct CollectItemTypesVisitor<'a> {
|
///////////////////////////////////////////////////////////////////////////
|
||||||
ccx: &'a CrateCtxt<'a>
|
// Main entry point
|
||||||
}
|
|
||||||
|
|
||||||
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, ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
|
pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
|
||||||
fn collect_intrinsic_type(ccx: &CrateCtxt,
|
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 => {}
|
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 };
|
let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
|
||||||
visit::walk_crate(&mut visitor, krate, ());
|
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 {
|
pub trait ToTy {
|
||||||
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
|
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,
|
fn collect_trait_methods(ccx: &CrateCtxt,
|
||||||
trait_id: ast::NodeId,
|
trait_id: ast::NodeId,
|
||||||
trait_def: &ty::TraitDef) {
|
trait_def: &ty::TraitDef) {
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
match tcx.map.get(trait_id) {
|
match tcx.map.get(trait_id) {
|
||||||
ast_map::NodeItem(item) => {
|
ast_map::NodeItem(item) => {
|
||||||
|
@ -360,7 +391,13 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||||
ms: &[Gc<ast::Method>],
|
ms: &[Gc<ast::Method>],
|
||||||
untransformed_rcvr_ty: ty::t,
|
untransformed_rcvr_ty: ty::t,
|
||||||
rcvr_ty_generics: &ty::Generics,
|
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 tcx = ccx.tcx;
|
||||||
let mut seen_methods = HashSet::new();
|
let mut seen_methods = HashSet::new();
|
||||||
for m in ms.iter() {
|
for m in ms.iter() {
|
||||||
|
@ -388,6 +425,9 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||||
|
|
||||||
write_ty_to_tcx(tcx, m.id, fty);
|
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
|
tcx.impl_or_trait_items
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(mty.def_id, ty::MethodTraitItem(mty));
|
.insert(mty.def_id, ty::MethodTraitItem(mty));
|
||||||
|
@ -448,9 +488,20 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
thing: &'static str) {
|
thing: &'static str) {
|
||||||
for ty_param in generics.ty_params.iter() {
|
for ty_param in generics.ty_params.iter() {
|
||||||
if ty_param.bounds.len() > 0 {
|
for bound in ty_param.bounds.iter() {
|
||||||
span_err!(ccx.tcx.sess, span, E0122,
|
match *bound {
|
||||||
"trait bounds are not allowed in {} definitions", thing);
|
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) => {
|
ast::ItemTrait(_, _, _, ref trait_methods) => {
|
||||||
let trait_def = trait_def_of_item(ccx, it);
|
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() {
|
for trait_method in trait_methods.iter() {
|
||||||
let self_type = ty::mk_param(ccx.tcx,
|
let self_type = ty::mk_param(ccx.tcx,
|
||||||
subst::SelfSpace,
|
subst::SelfSpace,
|
||||||
|
@ -556,7 +611,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
// We need to do this *after* converting methods, since
|
// We need to do this *after* converting methods, since
|
||||||
// convert_methods produces a tcache entry that is wrong for
|
// convert_methods produces a tcache entry that is wrong for
|
||||||
// static trait methods. This is somewhat unfortunate.
|
// 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, _) => {
|
ast::ItemStruct(struct_def, _) => {
|
||||||
// Write the class type.
|
// 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> {
|
fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
|
||||||
if trait_id.krate != ast::LOCAL_CRATE {
|
if trait_id.krate != ast::LOCAL_CRATE {
|
||||||
return ty::lookup_trait_def(ccx.tcx, trait_id)
|
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 {
|
let (generics, unbound, bounds) = match it.node {
|
||||||
ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => {
|
ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => {
|
||||||
(generics, unbound, supertraits)
|
(generics, unbound, bounds)
|
||||||
}
|
}
|
||||||
ref s => {
|
ref s => {
|
||||||
tcx.sess.span_bug(
|
tcx.sess.span_bug(
|
||||||
|
@ -779,13 +847,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
|
||||||
&substs,
|
&substs,
|
||||||
generics);
|
generics);
|
||||||
|
|
||||||
let builtin_bounds =
|
let self_param_ty = ty::ParamTy::for_self(def_id);
|
||||||
ensure_supertraits(ccx, it.id, it.span, supertraits, unbound);
|
|
||||||
|
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 substs = mk_item_substs(ccx, &ty_generics);
|
||||||
let trait_def = Rc::new(ty::TraitDef {
|
let trait_def = Rc::new(ty::TraitDef {
|
||||||
generics: ty_generics,
|
generics: ty_generics,
|
||||||
bounds: builtin_bounds,
|
bounds: bounds,
|
||||||
trait_ref: Rc::new(ty::TraitRef {
|
trait_ref: Rc::new(ty::TraitRef {
|
||||||
def_id: def_id,
|
def_id: def_id,
|
||||||
substs: substs
|
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)
|
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)
|
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,
|
fn ty_generics_for_type(ccx: &CrateCtxt,
|
||||||
generics: &ast::Generics)
|
generics: &ast::Generics)
|
||||||
-> ty::Generics {
|
-> ty::Generics
|
||||||
|
{
|
||||||
ty_generics(ccx,
|
ty_generics(ccx,
|
||||||
subst::TypeSpace,
|
subst::TypeSpace,
|
||||||
&generics.lifetimes,
|
generics.lifetimes.as_slice(),
|
||||||
&generics.ty_params,
|
generics.ty_params.as_slice(),
|
||||||
ty::Generics::empty(),
|
ty::Generics::empty(),
|
||||||
&generics.where_clause)
|
&generics.where_clause)
|
||||||
}
|
}
|
||||||
|
@ -1000,8 +1023,8 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
|
||||||
-> ty::Generics {
|
-> ty::Generics {
|
||||||
let mut generics = ty_generics(ccx,
|
let mut generics = ty_generics(ccx,
|
||||||
subst::TypeSpace,
|
subst::TypeSpace,
|
||||||
&generics.lifetimes,
|
generics.lifetimes.as_slice(),
|
||||||
&generics.ty_params,
|
generics.ty_params.as_slice(),
|
||||||
ty::Generics::empty(),
|
ty::Generics::empty(),
|
||||||
&generics.where_clause);
|
&generics.where_clause);
|
||||||
|
|
||||||
|
@ -1018,10 +1041,11 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
|
||||||
index: 0,
|
index: 0,
|
||||||
ident: special_idents::type_self,
|
ident: special_idents::type_self,
|
||||||
def_id: local_def(param_id),
|
def_id: local_def(param_id),
|
||||||
bounds: Rc::new(ty::ParamBounds {
|
bounds: ty::ParamBounds {
|
||||||
|
opt_region_bound: None,
|
||||||
builtin_bounds: ty::empty_builtin_bounds(),
|
builtin_bounds: ty::empty_builtin_bounds(),
|
||||||
trait_bounds: vec!(self_trait_ref),
|
trait_bounds: vec!(self_trait_ref),
|
||||||
}),
|
},
|
||||||
default: None
|
default: None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1039,8 +1063,8 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
|
||||||
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
||||||
ty_generics(ccx,
|
ty_generics(ccx,
|
||||||
subst::FnSpace,
|
subst::FnSpace,
|
||||||
&early_lifetimes,
|
early_lifetimes.as_slice(),
|
||||||
&generics.ty_params,
|
generics.ty_params.as_slice(),
|
||||||
base_generics,
|
base_generics,
|
||||||
&generics.where_clause)
|
&generics.where_clause)
|
||||||
}
|
}
|
||||||
|
@ -1053,7 +1077,7 @@ fn add_unsized_bound(ccx: &CrateCtxt,
|
||||||
span: Span) {
|
span: Span) {
|
||||||
let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
|
let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
|
||||||
match unbound {
|
match unbound {
|
||||||
&Some(TraitTyParamBound(ref tpb)) => {
|
&Some(ast::TraitTyParamBound(ref tpb)) => {
|
||||||
// #FIXME(8559) currently requires the unbound to be built-in.
|
// #FIXME(8559) currently requires the unbound to be built-in.
|
||||||
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
|
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
|
||||||
match kind_id {
|
match kind_id {
|
||||||
|
@ -1084,18 +1108,23 @@ fn add_unsized_bound(ccx: &CrateCtxt,
|
||||||
|
|
||||||
fn ty_generics(ccx: &CrateCtxt,
|
fn ty_generics(ccx: &CrateCtxt,
|
||||||
space: subst::ParamSpace,
|
space: subst::ParamSpace,
|
||||||
lifetimes: &Vec<ast::LifetimeDef>,
|
lifetime_defs: &[ast::LifetimeDef],
|
||||||
types: &OwnedSlice<ast::TyParam>,
|
types: &[ast::TyParam],
|
||||||
base_generics: ty::Generics,
|
base_generics: ty::Generics,
|
||||||
where_clause: &ast::WhereClause)
|
where_clause: &ast::WhereClause)
|
||||||
-> ty::Generics {
|
-> ty::Generics
|
||||||
|
{
|
||||||
let mut result = base_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,
|
let def = ty::RegionParameterDef { name: l.lifetime.name,
|
||||||
space: space,
|
space: space,
|
||||||
index: i,
|
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);
|
debug!("ty_generics: def for region param: {}", def);
|
||||||
result.regions.push(space, def);
|
result.regions.push(space, def);
|
||||||
}
|
}
|
||||||
|
@ -1123,19 +1152,17 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_ty = ty::ParamTy {space: space,
|
let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
|
||||||
idx: index,
|
let bounds = compute_bounds(ccx,
|
||||||
def_id: local_def(param.id)};
|
param.ident.name,
|
||||||
let bounds = Rc::new(compute_bounds(ccx,
|
param_ty,
|
||||||
param_ty,
|
param.bounds.as_slice(),
|
||||||
¶m.bounds,
|
¶m.unbound,
|
||||||
¶m.unbound,
|
param.span,
|
||||||
param.ident,
|
where_clause);
|
||||||
param.span,
|
|
||||||
where_clause));
|
|
||||||
let default = param.default.map(|path| {
|
let default = param.default.map(|path| {
|
||||||
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*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| {
|
ty::walk_ty(ty, |t| {
|
||||||
match ty::get(t).sty {
|
match ty::get(t).sty {
|
||||||
|
@ -1164,130 +1191,139 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
|
|
||||||
def
|
def
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_bounds(ccx: &CrateCtxt,
|
fn compute_bounds(
|
||||||
param_ty: ty::ParamTy,
|
ccx: &CrateCtxt,
|
||||||
ast_bounds: &OwnedSlice<ast::TyParamBound>,
|
name_of_bounded_thing: ast::Name,
|
||||||
unbound: &Option<ast::TyParamBound>,
|
param_ty: ty::ParamTy,
|
||||||
ident: ast::Ident,
|
ast_bounds: &[ast::TyParamBound],
|
||||||
span: Span,
|
unbound: &Option<ast::TyParamBound>,
|
||||||
where_clause: &ast::WhereClause)
|
span: Span,
|
||||||
-> ty::ParamBounds {
|
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
|
* Translate the AST's notion of ty param bounds (which are an
|
||||||
* traits, or the built-in trait (formerly known as kind): Send.
|
* 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 {
|
let mut param_bounds = conv_param_bounds(ccx,
|
||||||
builtin_bounds: ty::empty_builtin_bounds(),
|
span,
|
||||||
trait_bounds: Vec::new()
|
param_ty,
|
||||||
};
|
ast_bounds,
|
||||||
for ast_bound in ast_bounds.iter() {
|
where_clause);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
param_bounds
|
||||||
/// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticRegionTyParamBound => {
|
fn check_bounds_compatible(tcx: &ty::ctxt,
|
||||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
name_of_bounded_thing: ast::Name,
|
||||||
}
|
param_bounds: &ty::ParamBounds,
|
||||||
|
span: Span) {
|
||||||
UnboxedFnTyParamBound(ref unboxed_function) => {
|
// Currently the only bound which is incompatible with other bounds is
|
||||||
let rscope = ExplicitRscope;
|
// Sized/Unsized.
|
||||||
let self_ty = ty::mk_param(ccx.tcx,
|
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
|
||||||
param_ty.space,
|
ty::each_bound_trait_and_supertraits(
|
||||||
param_ty.idx,
|
tcx,
|
||||||
param_ty.def_id);
|
param_bounds.trait_bounds.as_slice(),
|
||||||
let trait_ref =
|
|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| {
|
|
||||||
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
|
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,
|
span_err!(tcx.sess, span, E0129,
|
||||||
"incompatible bounds on type parameter {}, \
|
"incompatible bounds on type parameter `{}`, \
|
||||||
bound {} does not allow unsized type",
|
bound `{}` does not allow unsized type",
|
||||||
token::get_ident(ident),
|
name_of_bounded_thing.user_string(tcx),
|
||||||
ppaux::trait_ref_to_string(tcx, &*trait_ref));
|
ppaux::trait_ref_to_string(tcx, &*trait_ref));
|
||||||
}
|
}
|
||||||
true
|
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,
|
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 fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
|
||||||
let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
|
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 sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
|
||||||
let abi = if_ok!(self.abi(a.abi, b.abi));
|
let abi = if_ok!(self.abi(a.abi, b.abi));
|
||||||
Ok(ty::ClosureTy {
|
Ok(ty::ClosureTy {
|
||||||
|
@ -251,9 +251,26 @@ pub trait Combine {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
|
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)
|
fn contraregions(&self, a: ty::Region, b: ty::Region)
|
||||||
-> cres<ty::Region>;
|
-> cres<ty::Region>;
|
||||||
|
|
||||||
fn regions(&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,
|
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 => {
|
if a_.def_id == b_.def_id => {
|
||||||
debug!("Trying to match traits {:?} and {:?}", a, b);
|
debug!("Trying to match traits {:?} and {:?}", a, b);
|
||||||
let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
|
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,
|
Ok(ty::mk_trait(tcx,
|
||||||
a_.def_id,
|
a_.def_id,
|
||||||
substs.clone(),
|
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::ConcreteFailure;
|
||||||
use middle::typeck::infer::region_inference::SubSupConflict;
|
use middle::typeck::infer::region_inference::SubSupConflict;
|
||||||
use middle::typeck::infer::region_inference::SupSupConflict;
|
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::ProcessedErrors;
|
||||||
use middle::typeck::infer::region_inference::SameRegions;
|
use middle::typeck::infer::region_inference::SameRegions;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
@ -89,10 +90,13 @@ use syntax::owned_slice::OwnedSlice;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::pprust;
|
use syntax::print::pprust;
|
||||||
use util::ppaux::UserString;
|
|
||||||
use util::ppaux::bound_region_to_string;
|
use util::ppaux::bound_region_to_string;
|
||||||
use util::ppaux::note_and_explain_region;
|
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 {
|
pub trait ErrorReporting {
|
||||||
fn report_region_errors(&self,
|
fn report_region_errors(&self,
|
||||||
errors: &Vec<RegionResolutionError>);
|
errors: &Vec<RegionResolutionError>);
|
||||||
|
@ -118,6 +122,12 @@ pub trait ErrorReporting {
|
||||||
sub: Region,
|
sub: Region,
|
||||||
sup: 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,
|
fn report_sub_sup_conflict(&self,
|
||||||
var_origin: RegionVariableOrigin,
|
var_origin: RegionVariableOrigin,
|
||||||
sub_origin: SubregionOrigin,
|
sub_origin: SubregionOrigin,
|
||||||
|
@ -145,7 +155,7 @@ trait ErrorReportingHelpers {
|
||||||
var_origin: RegionVariableOrigin);
|
var_origin: RegionVariableOrigin);
|
||||||
|
|
||||||
fn note_region_origin(&self,
|
fn note_region_origin(&self,
|
||||||
origin: SubregionOrigin);
|
origin: &SubregionOrigin);
|
||||||
|
|
||||||
fn give_expl_lifetime_param(&self,
|
fn give_expl_lifetime_param(&self,
|
||||||
decl: &ast::FnDecl,
|
decl: &ast::FnDecl,
|
||||||
|
@ -167,6 +177,10 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
self.report_concrete_failure(origin, sub, sup);
|
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,
|
SubSupConflict(var_origin,
|
||||||
sub_origin, sub_r,
|
sub_origin, sub_r,
|
||||||
sup_origin, sup_r) => {
|
sup_origin, sup_r) => {
|
||||||
|
@ -410,6 +424,62 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
found.user_string(self.tcx)))
|
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,
|
fn report_concrete_failure(&self,
|
||||||
origin: SubregionOrigin,
|
origin: SubregionOrigin,
|
||||||
sub: Region,
|
sub: Region,
|
||||||
|
@ -538,6 +608,67 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
sup,
|
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) => {
|
infer::CallRcvr(span) => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
|
@ -593,6 +724,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
sup,
|
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) => {
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
|
@ -606,9 +749,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
format!("in type `{}`, pointer has a longer lifetime than \
|
format!("in type `{}`, reference has a longer lifetime \
|
||||||
the data it references",
|
than the data it references",
|
||||||
ty.user_string(self.tcx)).as_slice());
|
self.ty_to_string(ty)).as_slice());
|
||||||
note_and_explain_region(
|
note_and_explain_region(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
"the pointer is valid for ",
|
"the pointer is valid for ",
|
||||||
|
@ -620,6 +763,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
sup,
|
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,
|
sup_region,
|
||||||
"...");
|
"...");
|
||||||
|
|
||||||
self.note_region_origin(sup_origin);
|
self.note_region_origin(&sup_origin);
|
||||||
|
|
||||||
note_and_explain_region(
|
note_and_explain_region(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
|
@ -645,7 +793,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
sub_region,
|
sub_region,
|
||||||
"...");
|
"...");
|
||||||
|
|
||||||
self.note_region_origin(sub_origin);
|
self.note_region_origin(&sub_origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_sup_sup_conflict(&self,
|
fn report_sup_sup_conflict(&self,
|
||||||
|
@ -662,7 +810,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
region1,
|
region1,
|
||||||
"...");
|
"...");
|
||||||
|
|
||||||
self.note_region_origin(origin1);
|
self.note_region_origin(&origin1);
|
||||||
|
|
||||||
note_and_explain_region(
|
note_and_explain_region(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
|
@ -670,7 +818,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
region2,
|
region2,
|
||||||
"...");
|
"...");
|
||||||
|
|
||||||
self.note_region_origin(origin2);
|
self.note_region_origin(&origin2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_processed_errors(&self,
|
fn report_processed_errors(&self,
|
||||||
|
@ -920,8 +1068,12 @@ impl<'a> Rebuilder<'a> {
|
||||||
-> OwnedSlice<ast::TyParamBound> {
|
-> OwnedSlice<ast::TyParamBound> {
|
||||||
ty_param_bounds.map(|tpb| {
|
ty_param_bounds.map(|tpb| {
|
||||||
match tpb {
|
match tpb {
|
||||||
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
|
&ast::RegionTyParamBound(lt) => {
|
||||||
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
|
// 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) => {
|
||||||
ast::UnboxedFnTyParamBound(unboxed_function_type)
|
ast::UnboxedFnTyParamBound(unboxed_function_type)
|
||||||
}
|
}
|
||||||
|
@ -1291,8 +1443,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
var_description).as_slice());
|
var_description).as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note_region_origin(&self, origin: SubregionOrigin) {
|
fn note_region_origin(&self, origin: &SubregionOrigin) {
|
||||||
match origin {
|
match *origin {
|
||||||
infer::Subtype(ref trace) => {
|
infer::Subtype(ref trace) => {
|
||||||
let desc = match trace.origin {
|
let desc = match trace.origin {
|
||||||
infer::Misc(_) => {
|
infer::Misc(_) => {
|
||||||
|
@ -1384,8 +1536,16 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
infer::RelateObjectBound(span) => {
|
infer::RelateObjectBound(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
"...so that source pointer does not outlive \
|
"...so that it can be closed over into an object");
|
||||||
lifetime bound of the object type");
|
}
|
||||||
|
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) => {
|
infer::CallRcvr(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
|
@ -1414,16 +1574,52 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
"...so that reference is valid \
|
"...so that reference is valid \
|
||||||
at the time of implicit borrow");
|
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) => {
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
"...so that variable is valid at time of its declaration");
|
"...so that variable is valid at time of its declaration");
|
||||||
}
|
}
|
||||||
infer::ReferenceOutlivesReferent(_, span) => {
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
"...so that the pointer does not outlive the \
|
format!("...so that the reference type `{}` \
|
||||||
data it points at");
|
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
|
// More bounds is a subtype of fewer bounds, so
|
||||||
// the GLB (mutual subtype) is the union.
|
// the GLB (mutual subtype) is the union.
|
||||||
Ok(a.union(b))
|
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
|
// More bounds is a subtype of fewer bounds, so
|
||||||
// the LUB (mutual supertype) is the intersection.
|
// the LUB (mutual supertype) is the intersection.
|
||||||
Ok(a.intersection(b))
|
Ok(a.intersection(b))
|
||||||
|
|
|
@ -168,6 +168,22 @@ pub enum SubregionOrigin {
|
||||||
// relating `'a` to `'b`
|
// relating `'a` to `'b`
|
||||||
RelateObjectBound(Span),
|
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
|
// Creating a pointer `b` to contents of another reference
|
||||||
Reborrow(Span),
|
Reborrow(Span),
|
||||||
|
|
||||||
|
@ -177,6 +193,9 @@ pub enum SubregionOrigin {
|
||||||
// (&'a &'b T) where a >= b
|
// (&'a &'b T) where a >= b
|
||||||
ReferenceOutlivesReferent(ty::t, Span),
|
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
|
// A `ref b` whose region does not enclose the decl site
|
||||||
BindingTypeIsNotValidAtDecl(Span),
|
BindingTypeIsNotValidAtDecl(Span),
|
||||||
|
|
||||||
|
@ -194,6 +213,9 @@ pub enum SubregionOrigin {
|
||||||
|
|
||||||
// An auto-borrow that does not enclose the expr where it occurs
|
// An auto-borrow that does not enclose the expr where it occurs
|
||||||
AutoBorrow(Span),
|
AutoBorrow(Span),
|
||||||
|
|
||||||
|
// Managed data cannot contain borrowed pointers.
|
||||||
|
Managed(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reasons to create a region inference variable
|
/// 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,
|
pub fn mk_subr(cx: &InferCtxt,
|
||||||
_a_is_expected: bool,
|
|
||||||
origin: SubregionOrigin,
|
origin: SubregionOrigin,
|
||||||
a: ty::Region,
|
a: ty::Region,
|
||||||
b: ty::Region) {
|
b: ty::Region) {
|
||||||
|
@ -346,6 +367,18 @@ pub fn mk_subr(cx: &InferCtxt,
|
||||||
cx.region_vars.commit(snapshot);
|
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,
|
pub fn mk_eqty(cx: &InferCtxt,
|
||||||
a_is_expected: bool,
|
a_is_expected: bool,
|
||||||
origin: TypeOrigin,
|
origin: TypeOrigin,
|
||||||
|
@ -589,6 +622,13 @@ impl<'a> InferCtxt<'a> {
|
||||||
self.rollback_to(snapshot);
|
self.rollback_to(snapshot);
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_given(&self,
|
||||||
|
sub: ty::FreeRegion,
|
||||||
|
sup: ty::RegionVid)
|
||||||
|
{
|
||||||
|
self.region_vars.add_given(sub, sup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InferCtxt<'a> {
|
impl<'a> InferCtxt<'a> {
|
||||||
|
@ -687,14 +727,13 @@ impl<'a> InferCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
|
pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
|
||||||
trait_ref:
|
trait_ref: &ty::TraitRef)
|
||||||
&ty::TraitRef)
|
|
||||||
-> ty::TraitRef {
|
-> ty::TraitRef {
|
||||||
// make up a dummy type just to reuse/abuse the resolve machinery
|
// make up a dummy type just to reuse/abuse the resolve machinery
|
||||||
let dummy0 = ty::mk_trait(self.tcx,
|
let dummy0 = ty::mk_trait(self.tcx,
|
||||||
trait_ref.def_id,
|
trait_ref.def_id,
|
||||||
trait_ref.substs.clone(),
|
trait_ref.substs.clone(),
|
||||||
ty::empty_builtin_bounds());
|
ty::region_existential_bound(ty::ReStatic));
|
||||||
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
|
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
|
||||||
match ty::get(dummy1).sty {
|
match ty::get(dummy1).sty {
|
||||||
ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
|
ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
|
||||||
|
@ -896,15 +935,21 @@ impl SubregionOrigin {
|
||||||
FreeVariable(a, _) => a,
|
FreeVariable(a, _) => a,
|
||||||
IndexSlice(a) => a,
|
IndexSlice(a) => a,
|
||||||
RelateObjectBound(a) => a,
|
RelateObjectBound(a) => a,
|
||||||
|
RelateProcBound(a, _, _) => a,
|
||||||
|
RelateParamBound(a, _, _) => a,
|
||||||
|
RelateRegionParamBound(a) => a,
|
||||||
|
RelateDefaultParamBound(a, _) => a,
|
||||||
Reborrow(a) => a,
|
Reborrow(a) => a,
|
||||||
ReborrowUpvar(a, _) => a,
|
ReborrowUpvar(a, _) => a,
|
||||||
ReferenceOutlivesReferent(_, a) => a,
|
ReferenceOutlivesReferent(_, a) => a,
|
||||||
|
ExprTypeIsNotInScope(_, a) => a,
|
||||||
BindingTypeIsNotValidAtDecl(a) => a,
|
BindingTypeIsNotValidAtDecl(a) => a,
|
||||||
CallRcvr(a) => a,
|
CallRcvr(a) => a,
|
||||||
CallArg(a) => a,
|
CallArg(a) => a,
|
||||||
CallReturn(a) => a,
|
CallReturn(a) => a,
|
||||||
AddrOf(a) => a,
|
AddrOf(a) => a,
|
||||||
AutoBorrow(a) => a,
|
AutoBorrow(a) => a,
|
||||||
|
Managed(a) => a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -933,6 +978,27 @@ impl Repr for SubregionOrigin {
|
||||||
RelateObjectBound(a) => {
|
RelateObjectBound(a) => {
|
||||||
format!("RelateObjectBound({})", a.repr(tcx))
|
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)),
|
Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
|
||||||
ReborrowUpvar(a, b) => {
|
ReborrowUpvar(a, b) => {
|
||||||
format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
|
format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
|
||||||
|
@ -940,6 +1006,11 @@ impl Repr for SubregionOrigin {
|
||||||
ReferenceOutlivesReferent(_, a) => {
|
ReferenceOutlivesReferent(_, a) => {
|
||||||
format!("ReferenceOutlivesReferent({})", a.repr(tcx))
|
format!("ReferenceOutlivesReferent({})", a.repr(tcx))
|
||||||
}
|
}
|
||||||
|
ExprTypeIsNotInScope(a, b) => {
|
||||||
|
format!("ExprTypeIsNotInScope({}, {})",
|
||||||
|
a.repr(tcx),
|
||||||
|
b.repr(tcx))
|
||||||
|
}
|
||||||
BindingTypeIsNotValidAtDecl(a) => {
|
BindingTypeIsNotValidAtDecl(a) => {
|
||||||
format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
|
format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
|
||||||
}
|
}
|
||||||
|
@ -948,6 +1019,7 @@ impl Repr for SubregionOrigin {
|
||||||
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
||||||
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
||||||
AutoBorrow(a) => format!("AutoBorrow({})", 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;
|
mod doc;
|
||||||
|
|
||||||
|
// A constraint that influences the inference process.
|
||||||
#[deriving(PartialEq, Eq, Hash)]
|
#[deriving(PartialEq, Eq, Hash)]
|
||||||
pub enum Constraint {
|
pub enum Constraint {
|
||||||
|
// One region variable is subregion of another
|
||||||
ConstrainVarSubVar(RegionVid, RegionVid),
|
ConstrainVarSubVar(RegionVid, RegionVid),
|
||||||
|
|
||||||
|
// Concrete region is subregion of region variable
|
||||||
ConstrainRegSubVar(Region, RegionVid),
|
ConstrainRegSubVar(Region, RegionVid),
|
||||||
|
|
||||||
|
// Region variable is subregion of concrete region
|
||||||
ConstrainVarSubReg(RegionVid, 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)]
|
#[deriving(PartialEq, Eq, Hash)]
|
||||||
|
@ -51,6 +71,8 @@ pub enum UndoLogEntry {
|
||||||
Mark,
|
Mark,
|
||||||
AddVar(RegionVid),
|
AddVar(RegionVid),
|
||||||
AddConstraint(Constraint),
|
AddConstraint(Constraint),
|
||||||
|
AddVerify(uint),
|
||||||
|
AddGiven(ty::FreeRegion, ty::RegionVid),
|
||||||
AddCombination(CombineMapType, TwoRegions)
|
AddCombination(CombineMapType, TwoRegions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +88,13 @@ pub enum RegionResolutionError {
|
||||||
/// `o` requires that `a <= b`, but this does not hold
|
/// `o` requires that `a <= b`, but this does not hold
|
||||||
ConcreteFailure(SubregionOrigin, Region, Region),
|
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)`:
|
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
|
||||||
///
|
///
|
||||||
/// Could not infer a value for `v` because `sub_r <= v` (due to
|
/// 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> {
|
pub struct RegionVarBindings<'a> {
|
||||||
tcx: &'a ty::ctxt,
|
tcx: &'a ty::ctxt,
|
||||||
var_origins: RefCell<Vec<RegionVariableOrigin>>,
|
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>>,
|
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>,
|
lubs: RefCell<CombineMap>,
|
||||||
glbs: RefCell<CombineMap>,
|
glbs: RefCell<CombineMap>,
|
||||||
skolemization_count: Cell<uint>,
|
skolemization_count: Cell<uint>,
|
||||||
|
@ -164,6 +224,8 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
var_origins: RefCell::new(Vec::new()),
|
var_origins: RefCell::new(Vec::new()),
|
||||||
values: RefCell::new(None),
|
values: RefCell::new(None),
|
||||||
constraints: RefCell::new(HashMap::new()),
|
constraints: RefCell::new(HashMap::new()),
|
||||||
|
verifys: RefCell::new(Vec::new()),
|
||||||
|
givens: RefCell::new(HashSet::new()),
|
||||||
lubs: RefCell::new(HashMap::new()),
|
lubs: RefCell::new(HashMap::new()),
|
||||||
glbs: RefCell::new(HashMap::new()),
|
glbs: RefCell::new(HashMap::new()),
|
||||||
skolemization_count: Cell::new(0),
|
skolemization_count: Cell::new(0),
|
||||||
|
@ -216,12 +278,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
Mark | CommitedSnapshot => { }
|
Mark | CommitedSnapshot => { }
|
||||||
AddVar(vid) => {
|
AddVar(vid) => {
|
||||||
let mut var_origins = self.var_origins.borrow_mut();
|
let mut var_origins = self.var_origins.borrow_mut();
|
||||||
assert_eq!(var_origins.len(), vid.index + 1);
|
|
||||||
var_origins.pop().unwrap();
|
var_origins.pop().unwrap();
|
||||||
|
assert_eq!(var_origins.len(), vid.index);
|
||||||
}
|
}
|
||||||
AddConstraint(ref constraint) => {
|
AddConstraint(ref constraint) => {
|
||||||
self.constraints.borrow_mut().remove(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) => {
|
AddCombination(Glb, ref regions) => {
|
||||||
self.glbs.borrow_mut().remove(regions);
|
self.glbs.borrow_mut().remove(regions);
|
||||||
}
|
}
|
||||||
|
@ -289,13 +358,14 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
self.values.borrow().is_none()
|
self.values.borrow().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_constraint(&self,
|
fn add_constraint(&self,
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
origin: SubregionOrigin) {
|
origin: SubregionOrigin) {
|
||||||
// cannot add constraints once regions are resolved
|
// cannot add constraints once regions are resolved
|
||||||
assert!(self.values_are_none());
|
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.constraints.borrow_mut().insert(constraint, origin) {
|
||||||
if self.in_snapshot() {
|
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,
|
pub fn make_subregion(&self,
|
||||||
origin: SubregionOrigin,
|
origin: SubregionOrigin,
|
||||||
sub: Region,
|
sub: Region,
|
||||||
|
@ -320,7 +422,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
(ReEarlyBound(..), ReEarlyBound(..)) => {
|
(ReEarlyBound(..), ReEarlyBound(..)) => {
|
||||||
// This case is used only to make sure that explicitly-specified
|
// This case is used only to make sure that explicitly-specified
|
||||||
// `Self` types match the real self type in implementations.
|
// `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(..), _) |
|
(ReEarlyBound(..), _) |
|
||||||
(ReLateBound(..), _) |
|
(ReLateBound(..), _) |
|
||||||
|
@ -345,11 +449,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
|
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,
|
pub fn lub_regions(&self,
|
||||||
origin: SubregionOrigin,
|
origin: SubregionOrigin,
|
||||||
a: Region,
|
a: Region,
|
||||||
|
@ -358,7 +470,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
// cannot add constraints once regions are resolved
|
// cannot add constraints once regions are resolved
|
||||||
assert!(self.values_are_none());
|
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) {
|
match (a, b) {
|
||||||
(ReStatic, _) | (_, ReStatic) => {
|
(ReStatic, _) | (_, ReStatic) => {
|
||||||
ReStatic // nothing lives longer than static
|
ReStatic // nothing lives longer than static
|
||||||
|
@ -381,7 +495,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
// cannot add constraints once regions are resolved
|
// cannot add constraints once regions are resolved
|
||||||
assert!(self.values_are_none());
|
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) {
|
match (a, b) {
|
||||||
(ReStatic, r) | (r, ReStatic) => {
|
(ReStatic, r) | (r, ReStatic) => {
|
||||||
// static lives longer than everything else
|
// 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 {
|
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
|
||||||
let v = match *self.values.borrow() {
|
match *self.values.borrow() {
|
||||||
None => {
|
None => {
|
||||||
self.tcx.sess.span_bug(
|
self.tcx.sess.span_bug(
|
||||||
self.var_origins.borrow().get(rid.index).span(),
|
self.var_origins.borrow().get(rid.index).span(),
|
||||||
"attempt to resolve region variable before values have \
|
"attempt to resolve region variable before values have \
|
||||||
been computed!")
|
been computed!")
|
||||||
}
|
}
|
||||||
Some(ref values) => *values.get(rid.index)
|
Some(ref values) => {
|
||||||
};
|
let r = lookup(values, rid);
|
||||||
|
debug!("resolve_var({}) = {}", rid, r.repr(self.tcx));
|
||||||
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
|
r
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +571,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
}
|
}
|
||||||
relate(self, a, ReInfer(ReVar(c)));
|
relate(self, a, ReInfer(ReVar(c)));
|
||||||
relate(self, b, ReInfer(ReVar(c)));
|
relate(self, b, ReInfer(ReVar(c)));
|
||||||
debug!("combine_vars() c={:?}", c);
|
debug!("combine_vars() c={}", c);
|
||||||
ReInfer(ReVar(c))
|
ReInfer(ReVar(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,40 +608,53 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
while result_index < result_set.len() {
|
while result_index < result_set.len() {
|
||||||
// nb: can't use uint::range() here because result_set grows
|
// nb: can't use uint::range() here because result_set grows
|
||||||
let r = *result_set.get(result_index);
|
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
|
for undo_entry in
|
||||||
self.undo_log.borrow().slice_from(mark.length).iter()
|
self.undo_log.borrow().slice_from(mark.length).iter()
|
||||||
{
|
{
|
||||||
let regs = match undo_entry {
|
match undo_entry {
|
||||||
&AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
|
&AddConstraint(ConstrainVarSubVar(a, b)) => {
|
||||||
Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
|
consider_adding_bidirectional_edges(
|
||||||
|
&mut result_set, r,
|
||||||
|
ReInfer(ReVar(a)), ReInfer(ReVar(b)));
|
||||||
}
|
}
|
||||||
&AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
|
&AddConstraint(ConstrainRegSubVar(a, b)) => {
|
||||||
Some((*a, ReInfer(ReVar(*b))))
|
consider_adding_bidirectional_edges(
|
||||||
|
&mut result_set, r,
|
||||||
|
a, ReInfer(ReVar(b)));
|
||||||
}
|
}
|
||||||
&AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
|
&AddConstraint(ConstrainVarSubReg(a, b)) => {
|
||||||
Some((ReInfer(ReVar(*a)), *b))
|
consider_adding_bidirectional_edges(
|
||||||
|
&mut result_set, r,
|
||||||
|
ReInfer(ReVar(a)), b);
|
||||||
}
|
}
|
||||||
&AddConstraint(ConstrainRegSubReg(a, b)) => {
|
&AddGiven(a, b) => {
|
||||||
Some((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(..) |
|
&AddCombination(..) |
|
||||||
&Mark |
|
&Mark |
|
||||||
&AddVar(..) |
|
&AddVar(..) |
|
||||||
&OpenSnapshot |
|
&OpenSnapshot |
|
||||||
&CommitedSnapshot => {
|
&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;
|
return result_set;
|
||||||
|
|
||||||
fn consider_adding_edge(result_set: Vec<Region> ,
|
fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
|
||||||
r: Region,
|
r: Region,
|
||||||
r1: Region,
|
r1: Region,
|
||||||
r2: Region) -> Vec<Region> {
|
r2: Region) {
|
||||||
let mut result_set = result_set;
|
consider_adding_directed_edge(result_set, r, r1, r2);
|
||||||
if r == r1 { // Clearly, this is potentially inefficient.
|
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) {
|
if !result_set.iter().any(|x| *x == r2) {
|
||||||
result_set.push(r2);
|
result_set.push(r2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result_set;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,7 +730,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
self.tcx.sess.span_bug(
|
self.tcx.sess.span_bug(
|
||||||
self.var_origins.borrow().get(v_id.index).span(),
|
self.var_origins.borrow().get(v_id.index).span(),
|
||||||
format!("lub_concrete_regions invoked with \
|
format!("lub_concrete_regions invoked with \
|
||||||
non-concrete regions: {:?}, {:?}",
|
non-concrete regions: {}, {}",
|
||||||
a,
|
a,
|
||||||
b).as_slice());
|
b).as_slice());
|
||||||
}
|
}
|
||||||
|
@ -675,7 +810,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
a: Region,
|
a: Region,
|
||||||
b: Region)
|
b: Region)
|
||||||
-> cres<Region> {
|
-> cres<Region> {
|
||||||
debug!("glb_concrete_regions({:?}, {:?})", a, b);
|
debug!("glb_concrete_regions({}, {})", a, b);
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(ReLateBound(..), _) |
|
(ReLateBound(..), _) |
|
||||||
(_, ReLateBound(..)) |
|
(_, ReLateBound(..)) |
|
||||||
|
@ -702,7 +837,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
self.tcx.sess.span_bug(
|
self.tcx.sess.span_bug(
|
||||||
self.var_origins.borrow().get(v_id.index).span(),
|
self.var_origins.borrow().get(v_id.index).span(),
|
||||||
format!("glb_concrete_regions invoked with \
|
format!("glb_concrete_regions invoked with \
|
||||||
non-concrete regions: {:?}, {:?}",
|
non-concrete regions: {}, {}",
|
||||||
a,
|
a,
|
||||||
b).as_slice());
|
b).as_slice());
|
||||||
}
|
}
|
||||||
|
@ -783,7 +918,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
// scopes or two free regions. So, if one of
|
// scopes or two free regions. So, if one of
|
||||||
// these scopes is a subscope of the other, return
|
// these scopes is a subscope of the other, return
|
||||||
// it. Otherwise fail.
|
// 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);
|
scope_a, scope_b, region_a, region_b);
|
||||||
match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_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)),
|
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> {
|
impl<'a> RegionVarBindings<'a> {
|
||||||
fn infer_variable_values(&self,
|
fn infer_variable_values(&self,
|
||||||
errors: &mut Vec<RegionResolutionError>)
|
errors: &mut Vec<RegionResolutionError>)
|
||||||
-> Vec<VarValue> {
|
-> Vec<VarValue>
|
||||||
|
{
|
||||||
let mut var_data = self.construct_var_data();
|
let mut var_data = self.construct_var_data();
|
||||||
self.expansion(var_data.as_mut_slice());
|
self.expansion(var_data.as_mut_slice());
|
||||||
self.contraction(var_data.as_mut_slice());
|
self.contraction(var_data.as_mut_slice());
|
||||||
self.collect_concrete_region_errors(&mut *errors);
|
let values =
|
||||||
self.extract_values_and_collect_conflicts(var_data.as_slice(), errors)
|
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> {
|
fn construct_var_data(&self) -> Vec<VarData> {
|
||||||
|
@ -838,6 +977,12 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
|
|
||||||
fn expansion(&self, var_data: &mut [VarData]) {
|
fn expansion(&self, var_data: &mut [VarData]) {
|
||||||
self.iterate_until_fixed_point("Expansion", |constraint| {
|
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 {
|
match *constraint {
|
||||||
ConstrainRegSubVar(a_region, b_vid) => {
|
ConstrainRegSubVar(a_region, b_vid) => {
|
||||||
let b_data = &mut var_data[b_vid.index];
|
let b_data = &mut var_data[b_vid.index];
|
||||||
|
@ -856,10 +1001,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
// This is a contraction constraint. Ignore it.
|
// This is a contraction constraint. Ignore it.
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
ConstrainRegSubReg(..) => {
|
|
||||||
// No region variables involved. Ignore.
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -868,14 +1009,29 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
a_region: Region,
|
a_region: Region,
|
||||||
b_vid: RegionVid,
|
b_vid: RegionVid,
|
||||||
b_data: &mut VarData)
|
b_data: &mut VarData)
|
||||||
-> bool {
|
-> bool
|
||||||
debug!("expand_node({:?}, {:?} == {:?})",
|
{
|
||||||
a_region, b_vid, b_data.value);
|
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;
|
b_data.classification = Expanding;
|
||||||
match b_data.value {
|
match b_data.value {
|
||||||
NoValue => {
|
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);
|
b_data.value = Value(a_region);
|
||||||
return true;
|
return true;
|
||||||
|
@ -887,8 +1043,10 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Expanding value of {:?} from {:?} to {:?}",
|
debug!("Expanding value of {} from {} to {}",
|
||||||
b_vid, cur_region, lub);
|
b_vid,
|
||||||
|
cur_region.repr(self.tcx),
|
||||||
|
lub.repr(self.tcx));
|
||||||
|
|
||||||
b_data.value = Value(lub);
|
b_data.value = Value(lub);
|
||||||
return true;
|
return true;
|
||||||
|
@ -903,6 +1061,12 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
fn contraction(&self,
|
fn contraction(&self,
|
||||||
var_data: &mut [VarData]) {
|
var_data: &mut [VarData]) {
|
||||||
self.iterate_until_fixed_point("Contraction", |constraint| {
|
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 {
|
match *constraint {
|
||||||
ConstrainRegSubVar(..) => {
|
ConstrainRegSubVar(..) => {
|
||||||
// This is an expansion constraint. Ignore.
|
// This is an expansion constraint. Ignore.
|
||||||
|
@ -921,10 +1085,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
let a_data = &mut var_data[a_vid.index];
|
let a_data = &mut var_data[a_vid.index];
|
||||||
self.contract_node(a_vid, a_data, b_region)
|
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,
|
a_data: &mut VarData,
|
||||||
b_region: Region)
|
b_region: Region)
|
||||||
-> bool {
|
-> bool {
|
||||||
debug!("contract_node({:?} == {:?}/{:?}, {:?})",
|
debug!("contract_node({} == {}/{}, {})",
|
||||||
a_vid, a_data.value, a_data.classification, b_region);
|
a_vid, a_data.value.repr(self.tcx),
|
||||||
|
a_data.classification, b_region.repr(self.tcx));
|
||||||
|
|
||||||
return match a_data.value {
|
return match a_data.value {
|
||||||
NoValue => {
|
NoValue => {
|
||||||
|
@ -967,8 +1128,10 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
b_region: Region)
|
b_region: Region)
|
||||||
-> bool {
|
-> bool {
|
||||||
if !this.is_subregion_of(a_region, b_region) {
|
if !this.is_subregion_of(a_region, b_region) {
|
||||||
debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
|
debug!("Setting {} to ErrorValue: {} not subregion of {}",
|
||||||
a_vid, a_region, b_region);
|
a_vid,
|
||||||
|
a_region.repr(this.tcx),
|
||||||
|
b_region.repr(this.tcx));
|
||||||
a_data.value = ErrorValue;
|
a_data.value = ErrorValue;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -985,15 +1148,19 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
if glb == a_region {
|
if glb == a_region {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
debug!("Contracting value of {:?} from {:?} to {:?}",
|
debug!("Contracting value of {} from {} to {}",
|
||||||
a_vid, a_region, glb);
|
a_vid,
|
||||||
|
a_region.repr(this.tcx),
|
||||||
|
glb.repr(this.tcx));
|
||||||
a_data.value = Value(glb);
|
a_data.value = Value(glb);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
|
debug!("Setting {} to ErrorValue: no glb of {}, {}",
|
||||||
a_vid, a_region, b_region);
|
a_vid,
|
||||||
|
a_region.repr(this.tcx),
|
||||||
|
b_region.repr(this.tcx));
|
||||||
a_data.value = ErrorValue;
|
a_data.value = ErrorValue;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1001,30 +1168,44 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_concrete_region_errors(
|
fn collect_concrete_region_errors(&self,
|
||||||
&self,
|
values: &Vec<VarValue>,
|
||||||
errors: &mut Vec<RegionResolutionError>)
|
errors: &mut Vec<RegionResolutionError>)
|
||||||
{
|
{
|
||||||
for (constraint, _) in self.constraints.borrow().iter() {
|
let mut reg_reg_dups = HashSet::new();
|
||||||
let (sub, sup) = match *constraint {
|
for verify in self.verifys.borrow().iter() {
|
||||||
ConstrainVarSubVar(..) |
|
match *verify {
|
||||||
ConstrainRegSubVar(..) |
|
VerifyRegSubReg(ref origin, sub, sup) => {
|
||||||
ConstrainVarSubReg(..) => {
|
if self.is_subregion_of(sub, sup) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ConstrainRegSubReg(sub, sup) => {
|
|
||||||
(sub, sup)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.is_subregion_of(sub, sup) {
|
if !reg_reg_dups.insert((sub, sup)) {
|
||||||
continue;
|
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,
|
&self,
|
||||||
var_data: &[VarData],
|
var_data: &[VarData],
|
||||||
errors: &mut Vec<RegionResolutionError>)
|
errors: &mut Vec<RegionResolutionError>)
|
||||||
-> Vec<VarValue> {
|
-> Vec<VarValue>
|
||||||
|
{
|
||||||
debug!("extract_values_and_collect_conflicts()");
|
debug!("extract_values_and_collect_conflicts()");
|
||||||
|
|
||||||
// This is the best way that I have found to suppress
|
// This is the best way that I have found to suppress
|
||||||
|
@ -1141,10 +1323,6 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
dummy_idx,
|
dummy_idx,
|
||||||
*constraint);
|
*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.tcx.sess.span_bug(
|
||||||
self.var_origins.borrow().get(node_idx.index).span(),
|
self.var_origins.borrow().get(node_idx.index).span(),
|
||||||
format!("collect_error_for_expanding_node() could not find error \
|
format!("collect_error_for_expanding_node() could not find error \
|
||||||
for var {:?}, lower_bounds={}, upper_bounds={}",
|
for var {}, lower_bounds={}, upper_bounds={}",
|
||||||
node_idx,
|
node_idx,
|
||||||
lower_bounds.iter()
|
lower_bounds.repr(self.tcx),
|
||||||
.map(|x| x.region)
|
upper_bounds.repr(self.tcx)).as_slice());
|
||||||
.collect::<Vec<ty::Region>>()
|
|
||||||
.repr(self.tcx),
|
|
||||||
upper_bounds.iter()
|
|
||||||
.map(|x| x.region)
|
|
||||||
.collect::<Vec<ty::Region>>()
|
|
||||||
.repr(self.tcx)).as_slice());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_error_for_contracting_node(
|
fn collect_error_for_contracting_node(
|
||||||
|
@ -1257,12 +1429,9 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
self.tcx.sess.span_bug(
|
self.tcx.sess.span_bug(
|
||||||
self.var_origins.borrow().get(node_idx.index).span(),
|
self.var_origins.borrow().get(node_idx.index).span(),
|
||||||
format!("collect_error_for_contracting_node() could not find error \
|
format!("collect_error_for_contracting_node() could not find error \
|
||||||
for var {:?}, upper_bounds={}",
|
for var {}, upper_bounds={}",
|
||||||
node_idx,
|
node_idx,
|
||||||
upper_bounds.iter()
|
upper_bounds.repr(self.tcx)).as_slice());
|
||||||
.map(|x| x.region)
|
|
||||||
.collect::<Vec<ty::Region>>()
|
|
||||||
.repr(self.tcx)).as_slice());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_concrete_regions(&self,
|
fn collect_concrete_regions(&self,
|
||||||
|
@ -1301,8 +1470,8 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
state.dup_found = true;
|
state.dup_found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
|
debug!("collect_concrete_regions(orig_node_idx={}, node_idx={}, \
|
||||||
classification={:?})",
|
classification={})",
|
||||||
orig_node_idx, node_idx, classification);
|
orig_node_idx, node_idx, classification);
|
||||||
|
|
||||||
// figure out the direction from which this node takes its
|
// figure out the direction from which this node takes its
|
||||||
|
@ -1323,7 +1492,7 @@ impl<'a> RegionVarBindings<'a> {
|
||||||
graph: &RegionGraph,
|
graph: &RegionGraph,
|
||||||
source_vid: RegionVid,
|
source_vid: RegionVid,
|
||||||
dir: Direction) {
|
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);
|
let source_node_index = NodeIndex(source_vid.index);
|
||||||
graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
|
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)
|
origin: this.constraints.borrow().get_copy(&edge.data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstrainRegSubReg(..) => {}
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
@ -1386,9 +1553,53 @@ impl Repr for Constraint {
|
||||||
ConstrainVarSubReg(a, b) => {
|
ConstrainVarSubReg(a, b) => {
|
||||||
format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
|
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.
|
// More bounds is a subtype of fewer bounds.
|
||||||
//
|
//
|
||||||
// e.g., fn:Copy() <: fn(), because the former is a function
|
// 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);
|
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,
|
span: Span,
|
||||||
count: uint)
|
count: uint)
|
||||||
-> Result<Vec<ty::Region> , ()>;
|
-> 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;
|
pub struct ExplicitRscope;
|
||||||
|
|
||||||
impl RegionScope for ExplicitRscope {
|
impl RegionScope for ExplicitRscope {
|
||||||
|
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn anon_regions(&self,
|
fn anon_regions(&self,
|
||||||
_span: Span,
|
_span: Span,
|
||||||
_count: uint)
|
_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
|
/// A scope in which we generate anonymous, late-bound regions for
|
||||||
/// omitted regions. This occurs in function signatures.
|
/// omitted regions. This occurs in function signatures.
|
||||||
pub struct BindingRscope {
|
pub struct BindingRscope {
|
||||||
|
@ -58,30 +92,26 @@ impl BindingRscope {
|
||||||
anon_bindings: Cell::new(0),
|
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 {
|
impl RegionScope for BindingRscope {
|
||||||
|
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
|
||||||
|
{
|
||||||
|
Some(self.next_region())
|
||||||
|
}
|
||||||
|
|
||||||
fn anon_regions(&self,
|
fn anon_regions(&self,
|
||||||
_: Span,
|
_: Span,
|
||||||
count: uint)
|
count: uint)
|
||||||
-> Result<Vec<ty::Region>, ()> {
|
-> Result<Vec<ty::Region> , ()>
|
||||||
let idx = self.anon_bindings.get();
|
{
|
||||||
self.anon_bindings.set(idx + count);
|
Ok(Vec::from_fn(count, |_| self.next_region()))
|
||||||
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()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::collections::HashMap;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use syntax::visit::Visitor;
|
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, ());
|
visit::walk_block(&mut v, &*b, ());
|
||||||
return v.flag;
|
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_unboxed_closure};
|
||||||
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
|
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
|
||||||
use middle::ty;
|
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;
|
||||||
|
use middle::typeck::check::regionmanip;
|
||||||
|
use middle::typeck::infer;
|
||||||
|
|
||||||
use std::gc::Gc;
|
use std::gc::Gc;
|
||||||
use std::rc::Rc;
|
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)
|
pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||||
-> (String, Option<Span>) {
|
-> (String, Option<Span>) {
|
||||||
return match region {
|
return match region {
|
||||||
|
@ -87,9 +101,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
|
||||||
Some(ast_map::NodeStmt(stmt)) => {
|
Some(ast_map::NodeStmt(stmt)) => {
|
||||||
explain_span(cx, "statement", stmt.span)
|
explain_span(cx, "statement", stmt.span)
|
||||||
}
|
}
|
||||||
Some(ast_map::NodeItem(it)) if (match it.node {
|
Some(ast_map::NodeItem(it)) => {
|
||||||
ast::ItemFn(..) => true, _ => false}) => {
|
let tag = item_scope_tag(&*it);
|
||||||
explain_span(cx, "function body", it.span)
|
explain_span(cx, tag, it.span)
|
||||||
}
|
}
|
||||||
Some(_) | None => {
|
Some(_) | None => {
|
||||||
// this really should not happen
|
// 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) {
|
match cx.map.find(fr.scope_id) {
|
||||||
Some(ast_map::NodeBlock(ref blk)) => {
|
Some(ast_map::NodeBlock(ref blk)) => {
|
||||||
let (msg, opt_span) = explain_span(cx, "block", blk.span);
|
let (msg, opt_span) = explain_span(cx, "block", blk.span);
|
||||||
(format!("{} {}", prefix, msg), opt_span)
|
(format!("{} {}", prefix, msg), opt_span)
|
||||||
}
|
}
|
||||||
Some(ast_map::NodeItem(it)) if match it.node {
|
Some(ast_map::NodeItem(it)) => {
|
||||||
ast::ItemImpl(..) => true, _ => false} => {
|
let tag = item_scope_tag(&*it);
|
||||||
let (msg, opt_span) = explain_span(cx, "impl", it.span);
|
let (msg, opt_span) = explain_span(cx, tag, it.span);
|
||||||
(format!("{} {}", prefix, msg), opt_span)
|
(format!("{} {}", prefix, msg), opt_span)
|
||||||
}
|
}
|
||||||
Some(_) | None => {
|
Some(_) | None => {
|
||||||
// this really should not happen
|
// this really should not happen
|
||||||
(format!("{} node {}", prefix, fr.scope_id), None)
|
(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)
|
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);
|
let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
|
||||||
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()),
|
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()),
|
||||||
Some(span))
|
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
|
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 {
|
match cty.store {
|
||||||
ty::UniqTraitStore => {
|
ty::UniqTraitStore => {
|
||||||
assert_eq!(cty.onceness, ast::Once);
|
assert_eq!(cty.onceness, ast::Once);
|
||||||
s.push_str("proc");
|
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(..) => {
|
ty::RegionTraitStore(..) => {
|
||||||
match cty.onceness {
|
match cty.onceness {
|
||||||
ast::Many => {}
|
ast::Many => {}
|
||||||
ast::Once => s.push_str("once ")
|
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.into_owned()
|
||||||
s.push_str(":");
|
|
||||||
s.push_str(cty.bounds.repr(cx).as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_sig_to_string(cx: &ctxt,
|
fn push_sig_to_string(cx: &ctxt,
|
||||||
s: &mut String,
|
s: &mut String,
|
||||||
bra: char,
|
bra: char,
|
||||||
ket: char,
|
ket: char,
|
||||||
sig: &ty::FnSig) {
|
sig: &ty::FnSig,
|
||||||
|
bounds: &str) {
|
||||||
s.push_char(bra);
|
s.push_char(bra);
|
||||||
let strs: Vec<String> = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect();
|
let strs: Vec<String> = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect();
|
||||||
s.push_str(strs.connect(", ").as_slice());
|
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);
|
s.push_char(ket);
|
||||||
|
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
s.push_str(":");
|
||||||
|
s.push_str(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
if ty::get(sig.output).sty != ty_nil {
|
if ty::get(sig.output).sty != ty_nil {
|
||||||
s.push_str(" -> ");
|
s.push_str(" -> ");
|
||||||
if ty::type_is_bot(sig.output) {
|
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_infer(infer_ty) => infer_ty.to_string(),
|
||||||
ty_err => "[type error]".to_string(),
|
ty_err => "[type error]".to_string(),
|
||||||
ty_param(ParamTy {idx: id, def_id: did, ..}) => {
|
ty_param(ref param_ty) => {
|
||||||
let ident = match cx.ty_param_defs.borrow().find(&did.node) {
|
param_ty.repr(cx)
|
||||||
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_enum(did, ref substs) | ty_struct(did, ref substs) => {
|
ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
|
||||||
let base = ty::item_path_str(cx, did);
|
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 trait_def = ty::lookup_trait_def(cx, did);
|
||||||
let ty = parameterized(cx, base.as_slice(),
|
let ty = parameterized(cx, base.as_slice(),
|
||||||
substs, &trait_def.generics);
|
substs, &trait_def.generics);
|
||||||
let bound_sep = if bounds.is_empty() { "" } else { "+" };
|
let bound_str = bounds.user_string(cx);
|
||||||
let bound_str = bounds.repr(cx);
|
let bound_sep = if bound_str.is_empty() { "" } else { "+" };
|
||||||
format!("{}{}{}",
|
format!("{}{}{}",
|
||||||
ty,
|
ty,
|
||||||
bound_sep,
|
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 {
|
impl Repr for def::Def {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, _tcx: &ctxt) -> String {
|
||||||
format!("{:?}", *self)
|
format!("{:?}", *self)
|
||||||
|
@ -581,16 +598,18 @@ impl Repr for def::Def {
|
||||||
|
|
||||||
impl Repr for ty::TypeParameterDef {
|
impl Repr for ty::TypeParameterDef {
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
format!("TypeParameterDef({:?}, {})", self.def_id,
|
format!("TypeParameterDef({}, {})",
|
||||||
|
self.def_id.repr(tcx),
|
||||||
self.bounds.repr(tcx))
|
self.bounds.repr(tcx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repr for ty::RegionParameterDef {
|
impl Repr for ty::RegionParameterDef {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
format!("RegionParameterDef({}, {:?})",
|
format!("RegionParameterDef(name={}, def_id={}, bounds={})",
|
||||||
token::get_name(self.name),
|
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 {
|
impl Repr for ty::ParamBounds {
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for b in self.builtin_bounds.iter() {
|
res.push(self.builtin_bounds.repr(tcx));
|
||||||
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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for t in self.trait_bounds.iter() {
|
for t in self.trait_bounds.iter() {
|
||||||
res.push(t.repr(tcx));
|
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 {
|
impl Repr for ast::Expr {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, _tcx: &ctxt) -> String {
|
||||||
format!("expr({}: {})", self.id, pprust::expr_to_string(self))
|
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 {
|
impl Repr for ast::Item {
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
format!("item({})", tcx.map.node_to_string(self.id))
|
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 {
|
impl Repr for ast::Stmt {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, _tcx: &ctxt) -> String {
|
||||||
format!("stmt({}: {})",
|
format!("stmt({}: {})",
|
||||||
|
@ -724,11 +777,7 @@ impl Repr for ty::Region {
|
||||||
bound_region.repr(tcx))
|
bound_region.repr(tcx))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ReFree(ref fr) => {
|
ty::ReFree(ref fr) => fr.repr(tcx),
|
||||||
format!("ReFree({}, {})",
|
|
||||||
fr.scope_id,
|
|
||||||
fr.bound_region.repr(tcx))
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ReScope(id) => {
|
ty::ReScope(id) => {
|
||||||
format!("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 {
|
impl Repr for ast::DefId {
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
// Unfortunately, there seems to be no way to attempt to print
|
// 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 {
|
impl Repr for ast::Ident {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, _tcx: &ctxt) -> String {
|
||||||
token::get_ident(*self).get().to_string()
|
token::get_ident(*self).get().to_string()
|
||||||
|
@ -928,21 +997,14 @@ impl Repr for ty::BuiltinBound {
|
||||||
impl UserString for ty::BuiltinBound {
|
impl UserString for ty::BuiltinBound {
|
||||||
fn user_string(&self, _tcx: &ctxt) -> String {
|
fn user_string(&self, _tcx: &ctxt) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
ty::BoundStatic => "'static".to_string(),
|
ty::BoundSend => "Send".to_owned(),
|
||||||
ty::BoundSend => "Send".to_string(),
|
ty::BoundSized => "Sized".to_owned(),
|
||||||
ty::BoundSized => "Sized".to_string(),
|
ty::BoundCopy => "Copy".to_owned(),
|
||||||
ty::BoundCopy => "Copy".to_string(),
|
ty::BoundSync => "Sync".to_owned(),
|
||||||
ty::BoundSync => "Sync".to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repr for ty::BuiltinBounds {
|
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
|
||||||
self.user_string(tcx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Repr for Span {
|
impl Repr for Span {
|
||||||
fn repr(&self, tcx: &ctxt) -> String {
|
fn repr(&self, tcx: &ctxt) -> String {
|
||||||
tcx.sess.codemap().span_to_string(*self).to_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 {
|
impl UserString for ty::BuiltinBounds {
|
||||||
fn user_string(&self, tcx: &ctxt) -> String {
|
fn user_string(&self, tcx: &ctxt) -> String {
|
||||||
self.iter()
|
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 {
|
impl Repr for ty::ExplicitSelfCategory {
|
||||||
fn repr(&self, _: &ctxt) -> String {
|
fn repr(&self, _: &ctxt) -> String {
|
||||||
explicit_self_category_to_str(self).to_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 {
|
pub struct AttrBuilder {
|
||||||
attrs: Vec<(uint, Box<AttrHelper>)>
|
attrs: Vec<(uint, Box<AttrHelper+'static>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttrBuilder {
|
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 {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,18 +159,12 @@ pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
|
||||||
clean::RequiredMethod(trait_item)
|
clean::RequiredMethod(trait_item)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let supertraits = ty::trait_supertraits(tcx, did);
|
let trait_def = ty::lookup_trait_def(tcx, did);
|
||||||
let mut parents = supertraits.iter().map(|i| {
|
let bounds = trait_def.bounds.clean();
|
||||||
match i.clean() {
|
|
||||||
clean::TraitBound(ty) => ty,
|
|
||||||
clean::RegionBound => unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
clean::Trait {
|
clean::Trait {
|
||||||
generics: (&def.generics, subst::TypeSpace).clean(),
|
generics: (&def.generics, subst::TypeSpace).clean(),
|
||||||
items: items.collect(),
|
items: items.collect(),
|
||||||
parents: parents.collect()
|
bounds: bounds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -481,15 +481,14 @@ impl Clean<TyParam> for ty::TypeParameterDef {
|
||||||
|
|
||||||
#[deriving(Clone, Encodable, Decodable, PartialEq)]
|
#[deriving(Clone, Encodable, Decodable, PartialEq)]
|
||||||
pub enum TyParamBound {
|
pub enum TyParamBound {
|
||||||
RegionBound,
|
RegionBound, // FIXME(#16518) -- need to include name of actual region
|
||||||
TraitBound(Type)
|
TraitBound(Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clean<TyParamBound> for ast::TyParamBound {
|
impl Clean<TyParamBound> for ast::TyParamBound {
|
||||||
fn clean(&self) -> TyParamBound {
|
fn clean(&self) -> TyParamBound {
|
||||||
match *self {
|
match *self {
|
||||||
ast::StaticRegionTyParamBound => RegionBound,
|
ast::RegionTyParamBound(_) => RegionBound,
|
||||||
ast::OtherRegionTyParamBound(_) => RegionBound,
|
|
||||||
ast::UnboxedFnTyParamBound(_) => {
|
ast::UnboxedFnTyParamBound(_) => {
|
||||||
// FIXME(pcwalton): Wrong.
|
// FIXME(pcwalton): Wrong.
|
||||||
RegionBound
|
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 {
|
fn external_path(name: &str, substs: &subst::Substs) -> Path {
|
||||||
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
|
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -525,7 +534,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
|
||||||
};
|
};
|
||||||
let empty = subst::Substs::empty();
|
let empty = subst::Substs::empty();
|
||||||
let (did, path) = match *self {
|
let (did, path) = match *self {
|
||||||
ty::BoundStatic => return RegionBound,
|
|
||||||
ty::BoundSend =>
|
ty::BoundSend =>
|
||||||
(tcx.lang_items.send_trait().unwrap(),
|
(tcx.lang_items.send_trait().unwrap(),
|
||||||
external_path("Send", &empty)),
|
external_path("Send", &empty)),
|
||||||
|
@ -810,10 +818,7 @@ impl Clean<ClosureDecl> for ast::ClosureTy {
|
||||||
decl: self.decl.clean(),
|
decl: self.decl.clean(),
|
||||||
onceness: self.onceness,
|
onceness: self.onceness,
|
||||||
fn_style: self.fn_style,
|
fn_style: self.fn_style,
|
||||||
bounds: match self.bounds {
|
bounds: self.bounds.clean()
|
||||||
Some(ref x) => x.clean(),
|
|
||||||
None => Vec::new()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -909,7 +914,7 @@ impl Clean<RetStyle> for ast::RetStyle {
|
||||||
pub struct Trait {
|
pub struct Trait {
|
||||||
pub items: Vec<TraitItem>,
|
pub items: Vec<TraitItem>,
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
pub parents: Vec<Type>,
|
pub bounds: Vec<TyParamBound>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clean<Item> for doctree::Trait {
|
impl Clean<Item> for doctree::Trait {
|
||||||
|
@ -924,7 +929,7 @@ impl Clean<Item> for doctree::Trait {
|
||||||
inner: TraitItem(Trait {
|
inner: TraitItem(Trait {
|
||||||
items: self.items.clean(),
|
items: self.items.clean(),
|
||||||
generics: self.generics.clean(),
|
generics: self.generics.clean(),
|
||||||
parents: self.parents.clean(),
|
bounds: self.bounds.clean(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1060,7 +1065,7 @@ pub enum Type {
|
||||||
Self(ast::DefId),
|
Self(ast::DefId),
|
||||||
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
|
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
|
||||||
Primitive(Primitive),
|
Primitive(Primitive),
|
||||||
Closure(Box<ClosureDecl>, Option<Lifetime>),
|
Closure(Box<ClosureDecl>),
|
||||||
Proc(Box<ClosureDecl>),
|
Proc(Box<ClosureDecl>),
|
||||||
/// extern "ABI" fn
|
/// extern "ABI" fn
|
||||||
BareFunction(Box<BareFunctionDecl>),
|
BareFunction(Box<BareFunctionDecl>),
|
||||||
|
@ -1208,7 +1213,7 @@ impl Clean<Type> for ast::Ty {
|
||||||
tpbs.clean().map(|x| x),
|
tpbs.clean().map(|x| x),
|
||||||
id)
|
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()),
|
TyProc(ref c) => Proc(box c.clean()),
|
||||||
TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
|
TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
|
||||||
TyParen(ref ty) => ty.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(),
|
decl: (ast_util::local_def(0), &fty.sig).clean(),
|
||||||
onceness: fty.onceness,
|
onceness: fty.onceness,
|
||||||
fn_style: fty.fn_style,
|
fn_style: fty.fn_style,
|
||||||
bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
|
bounds: fty.bounds.clean(),
|
||||||
};
|
};
|
||||||
match fty.store {
|
match fty.store {
|
||||||
ty::UniqTraitStore => Proc(decl),
|
ty::UniqTraitStore => Proc(decl),
|
||||||
ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
|
ty::RegionTraitStore(..) => Closure(decl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ty_struct(did, ref substs) |
|
ty::ty_struct(did, ref substs) |
|
||||||
|
|
|
@ -156,7 +156,7 @@ pub struct Trait {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub items: Vec<ast::TraitItem>, //should be TraitItem
|
pub items: Vec<ast::TraitItem>, //should be TraitItem
|
||||||
pub generics: ast::Generics,
|
pub generics: ast::Generics,
|
||||||
pub parents: Vec<ast::TraitRef>,
|
pub bounds: Vec<ast::TyParamBound>,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub whence: Span,
|
pub whence: Span,
|
||||||
|
|
|
@ -355,7 +355,7 @@ impl fmt::Show for clean::Type {
|
||||||
}
|
}
|
||||||
clean::Self(..) => f.write("Self".as_bytes()),
|
clean::Self(..) => f.write("Self".as_bytes()),
|
||||||
clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
|
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}",
|
write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
|
||||||
style = FnStyleSpace(decl.fn_style),
|
style = FnStyleSpace(decl.fn_style),
|
||||||
lifetimes = if decl.lifetimes.len() == 0 {
|
lifetimes = if decl.lifetimes.len() == 0 {
|
||||||
|
@ -370,13 +370,6 @@ impl fmt::Show for clean::Type {
|
||||||
},
|
},
|
||||||
bounds = {
|
bounds = {
|
||||||
let mut ret = String::new();
|
let mut ret = String::new();
|
||||||
match *region {
|
|
||||||
Some(ref lt) => {
|
|
||||||
ret.push_str(format!(": {}",
|
|
||||||
*lt).as_slice());
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
for bound in decl.bounds.iter() {
|
for bound in decl.bounds.iter() {
|
||||||
match *bound {
|
match *bound {
|
||||||
clean::RegionBound => {}
|
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,
|
fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||||
t: &clean::Trait) -> fmt::Result {
|
t: &clean::Trait) -> fmt::Result {
|
||||||
let mut parents = String::new();
|
let mut bounds = String::new();
|
||||||
if t.parents.len() > 0 {
|
if t.bounds.len() > 0 {
|
||||||
parents.push_str(": ");
|
bounds.push_str(": ");
|
||||||
for (i, p) in t.parents.iter().enumerate() {
|
for (i, p) in t.bounds.iter().enumerate() {
|
||||||
if i > 0 { parents.push_str(" + "); }
|
if i > 0 { bounds.push_str(" + "); }
|
||||||
parents.push_str(format!("{}", *p).as_slice());
|
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),
|
VisSpace(it.visibility),
|
||||||
it.name.get_ref().as_slice(),
|
it.name.get_ref().as_slice(),
|
||||||
t.generics,
|
t.generics,
|
||||||
parents));
|
bounds));
|
||||||
let required = t.items.iter()
|
let required = t.items.iter()
|
||||||
.filter(|m| {
|
.filter(|m| {
|
||||||
match **m {
|
match **m {
|
||||||
|
|
|
@ -317,12 +317,12 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
};
|
};
|
||||||
om.statics.push(s);
|
om.statics.push(s);
|
||||||
},
|
},
|
||||||
ast::ItemTrait(ref gen, _, ref tr, ref items) => {
|
ast::ItemTrait(ref gen, _, ref b, ref items) => {
|
||||||
let t = Trait {
|
let t = Trait {
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
items: items.iter().map(|x| (*x).clone()).collect(),
|
items: items.iter().map(|x| (*x).clone()).collect(),
|
||||||
generics: gen.clone(),
|
generics: gen.clone(),
|
||||||
parents: tr.iter().map(|x| (*x).clone()).collect(),
|
bounds: b.iter().map(|x| (*x).clone()).collect(),
|
||||||
id: item.id,
|
id: item.id,
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
whence: item.span,
|
whence: item.span,
|
||||||
|
|
|
@ -26,7 +26,8 @@ pub struct Exclusive<T> {
|
||||||
data: UnsafeCell<T>,
|
data: UnsafeCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An RAII guard returned via `lock`
|
/// stage0 only
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct ExclusiveGuard<'a, T> {
|
pub struct ExclusiveGuard<'a, T> {
|
||||||
// FIXME #12808: strange name to try to avoid interfering with
|
// FIXME #12808: strange name to try to avoid interfering with
|
||||||
// field accesses of the contained type via Deref
|
// field accesses of the contained type via Deref
|
||||||
|
@ -34,6 +35,15 @@ pub struct ExclusiveGuard<'a, T> {
|
||||||
_guard: mutex::LockGuard<'a>,
|
_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> {
|
impl<T: Send> Exclusive<T> {
|
||||||
/// Creates a new `Exclusive` which will protect the data provided.
|
/// Creates a new `Exclusive` which will protect the data provided.
|
||||||
pub fn new(user_data: T) -> Exclusive<T> {
|
pub fn new(user_data: T) -> Exclusive<T> {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
|
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
|
||||||
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
|
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
|
||||||
#![feature(import_shadowing)]
|
#![feature(import_shadowing)]
|
||||||
|
#![feature(issue_5723_bootstrap)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![experimental]
|
#![experimental]
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ pub trait Runtime {
|
||||||
fn can_block(&self) -> bool;
|
fn can_block(&self) -> bool;
|
||||||
|
|
||||||
// FIXME: This is a serious code smell and this should not exist at all.
|
// 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
|
/// 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
|
/// The task-local data can be accessed through this value, and when this
|
||||||
/// structure is dropped it will return the borrow on the data.
|
/// 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> {
|
pub struct Ref<T> {
|
||||||
// FIXME #12808: strange names to try to avoid interfering with
|
// FIXME #12808: strange names to try to avoid interfering with
|
||||||
// field accesses of the contained type via Deref
|
// field accesses of the contained type via Deref
|
||||||
|
|
|
@ -120,7 +120,7 @@ pub struct ProcessConfig<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LocalIo<'a> {
|
pub struct LocalIo<'a> {
|
||||||
factory: &'a mut IoFactory,
|
factory: &'a mut IoFactory+'a,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[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 }
|
LocalIo { factory: io }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub struct Task {
|
||||||
pub name: Option<SendStr>,
|
pub name: Option<SendStr>,
|
||||||
|
|
||||||
state: TaskState,
|
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`,
|
// 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
|
/// Inserts a runtime object into this task, transferring ownership to the
|
||||||
/// task. It is illegal to replace a previous runtime object in this task
|
/// task. It is illegal to replace a previous runtime object in this task
|
||||||
/// with this argument.
|
/// 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());
|
assert!(self.imp.is_none());
|
||||||
self.imp = Some(ops);
|
self.imp = Some(ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the runtime from this task, transferring ownership to the
|
/// Removes the runtime from this task, transferring ownership to the
|
||||||
/// caller.
|
/// 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());
|
assert!(self.imp.is_some());
|
||||||
self.imp.take().unwrap()
|
self.imp.take().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ impl Task {
|
||||||
Ok(t) => Some(t),
|
Ok(t) => Some(t),
|
||||||
Err(t) => {
|
Err(t) => {
|
||||||
let data = mem::transmute::<_, raw::TraitObject>(t).data;
|
let data = mem::transmute::<_, raw::TraitObject>(t).data;
|
||||||
let obj: Box<Runtime + Send> =
|
let obj: Box<Runtime + Send + 'static> =
|
||||||
mem::transmute(raw::TraitObject {
|
mem::transmute(raw::TraitObject {
|
||||||
vtable: vtable,
|
vtable: vtable,
|
||||||
data: data,
|
data: data,
|
||||||
|
|
|
@ -26,11 +26,18 @@ pub struct Access<T> {
|
||||||
inner: Arc<UnsafeCell<Inner<T>>>,
|
inner: Arc<UnsafeCell<Inner<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Guard<'a, T> {
|
pub struct Guard<'a, T> {
|
||||||
access: &'a mut Access<T>,
|
access: &'a mut Access<T>,
|
||||||
missile: Option<HomingMissile>,
|
missile: Option<HomingMissile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub struct Guard<'a, T:'static> {
|
||||||
|
access: &'a mut Access<T>,
|
||||||
|
missile: Option<HomingMissile>,
|
||||||
|
}
|
||||||
|
|
||||||
struct Inner<T> {
|
struct Inner<T> {
|
||||||
queue: Vec<(BlockedTask, uint)>,
|
queue: Vec<(BlockedTask, uint)>,
|
||||||
held: bool,
|
held: bool,
|
||||||
|
|
|
@ -28,12 +28,20 @@ pub struct AccessTimeout<T> {
|
||||||
pub access: access::Access<T>,
|
pub access: access::Access<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Guard<'a, T> {
|
pub struct Guard<'a, T> {
|
||||||
state: &'a mut TimeoutState,
|
state: &'a mut TimeoutState,
|
||||||
pub access: access::Guard<'a, T>,
|
pub access: access::Guard<'a, T>,
|
||||||
pub can_timeout: bool,
|
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)]
|
#[deriving(PartialEq)]
|
||||||
enum TimeoutState {
|
enum TimeoutState {
|
||||||
NoTimeout,
|
NoTimeout,
|
||||||
|
|
|
@ -382,7 +382,7 @@ fn fmt_number_or_null(v: f64) -> String {
|
||||||
|
|
||||||
/// A structure for implementing serialization to JSON.
|
/// A structure for implementing serialization to JSON.
|
||||||
pub struct Encoder<'a> {
|
pub struct Encoder<'a> {
|
||||||
writer: &'a mut io::Writer,
|
writer: &'a mut io::Writer+'a,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Encoder<'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
|
/// Another encoder for JSON, but prints out human-readable JSON instead of
|
||||||
/// compact data
|
/// compact data
|
||||||
pub struct PrettyEncoder<'a> {
|
pub struct PrettyEncoder<'a> {
|
||||||
writer: &'a mut io::Writer,
|
writer: &'a mut io::Writer+'a,
|
||||||
curr_indent: uint,
|
curr_indent: uint,
|
||||||
indent: uint,
|
indent: uint,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ Core encoding and decoding interfaces.
|
||||||
html_root_url = "http://doc.rust-lang.org/master/",
|
html_root_url = "http://doc.rust-lang.org/master/",
|
||||||
html_playground_url = "http://play.rust-lang.org/")]
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
|
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
|
||||||
|
#![feature(issue_5723_bootstrap)]
|
||||||
|
|
||||||
// test harness access
|
// test harness access
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -409,20 +409,38 @@ mod table {
|
||||||
assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
|
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> {
|
pub struct Entries<'a, K, V> {
|
||||||
table: &'a RawTable<K, V>,
|
table: &'a RawTable<K, V>,
|
||||||
idx: uint,
|
idx: uint,
|
||||||
elems_seen: 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> {
|
pub struct MutEntries<'a, K, V> {
|
||||||
table: &'a mut RawTable<K, V>,
|
table: &'a mut RawTable<K, V>,
|
||||||
idx: uint,
|
idx: uint,
|
||||||
elems_seen: 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.
|
/// Iterator over the entries in a table, consuming the table.
|
||||||
pub struct MoveEntries<K, V> {
|
pub struct MoveEntries<K, V> {
|
||||||
table: RawTable<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
|
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||||
/// is returned by the iterator and should be handled by the caller.
|
/// is returned by the iterator and should be handled by the caller.
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Bytes<'r, T> {
|
pub struct Bytes<'r, T> {
|
||||||
reader: &'r mut 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> {
|
impl<'r, R: Reader> Bytes<'r, R> {
|
||||||
/// Constructs a new byte iterator from the given Reader instance.
|
/// Constructs a new byte iterator from the given Reader instance.
|
||||||
pub fn new(r: &'r mut R) -> Bytes<'r, R> {
|
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) }
|
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) }
|
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
|
/// A `RefReader` is a struct implementing `Reader` which contains a reference
|
||||||
/// to another reader. This is often useful when composing streams.
|
/// 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
|
/// The underlying reader which this is referencing
|
||||||
inner: &'a mut R
|
inner: &'a mut R
|
||||||
}
|
}
|
||||||
|
@ -1058,12 +1066,21 @@ pub trait Writer {
|
||||||
///
|
///
|
||||||
/// This function will return any I/O error reported while formatting.
|
/// This function will return any I/O error reported while formatting.
|
||||||
fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
|
fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
|
||||||
// Create a shim which translates a Writer to a FormatWriter and saves
|
// Note: stage0-specific version that lacks bound.
|
||||||
// off I/O errors. instead of discarding them
|
#[cfg(stage0)]
|
||||||
struct Adaptor<'a, T> {
|
struct Adaptor<'a, T> {
|
||||||
inner: &'a mut T,
|
inner: &'a mut T,
|
||||||
error: IoResult<()>,
|
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> {
|
impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
|
||||||
fn write(&mut self, bytes: &[u8]) -> fmt::Result {
|
fn write(&mut self, bytes: &[u8]) -> fmt::Result {
|
||||||
match self.inner.write(bytes) {
|
match self.inner.write(bytes) {
|
||||||
|
@ -1278,7 +1295,7 @@ pub trait Writer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writer for Box<Writer> {
|
impl Writer for Box<Writer+'static> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
|
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() }
|
fn flush(&mut self) -> IoResult<()> { self.flush() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Writer for &'a mut Writer {
|
impl<'a> Writer for &'a mut Writer+'a {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
|
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());
|
/// println!("input processed: {}", output.unwrap());
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct RefWriter<'a, W> {
|
pub struct RefWriter<'a, W> {
|
||||||
/// The underlying writer which this is referencing
|
/// The underlying writer which this is referencing
|
||||||
inner: &'a mut W
|
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> {
|
impl<'a, W: Writer> Writer for RefWriter<'a, W> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
|
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
|
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||||
/// is returned by the iterator and should be handled by the caller.
|
/// is returned by the iterator and should be handled by the caller.
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Lines<'r, T> {
|
pub struct Lines<'r, T> {
|
||||||
buffer: &'r mut 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> {
|
impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
|
||||||
fn next(&mut self) -> Option<IoResult<String>> {
|
fn next(&mut self) -> Option<IoResult<String>> {
|
||||||
match self.buffer.read_line() {
|
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
|
/// Any error other than `EndOfFile` that is produced by the underlying Reader
|
||||||
/// is returned by the iterator and should be handled by the caller.
|
/// is returned by the iterator and should be handled by the caller.
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct Chars<'r, T> {
|
pub struct Chars<'r, T> {
|
||||||
buffer: &'r mut 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> {
|
impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
|
||||||
fn next(&mut self) -> Option<IoResult<char>> {
|
fn next(&mut self) -> Option<IoResult<char>> {
|
||||||
match self.buffer.read_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.
|
/// An infinite iterator over incoming connection attempts.
|
||||||
/// Calling `next` will block the task until a connection is attempted.
|
/// 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
|
/// `Some`. The `Some` contains the `IoResult` representing whether the
|
||||||
/// connection attempt was successful. A successful connection will be wrapped
|
/// connection attempt was successful. A successful connection will be wrapped
|
||||||
/// in `Ok`. A failed connection is represented as an `Err`.
|
/// 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,
|
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,
|
/// 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.
|
/// that error is returned immediately and remaining `Writer`s are not called.
|
||||||
pub struct MultiWriter {
|
pub struct MultiWriter {
|
||||||
writers: Vec<Box<Writer>>
|
writers: Vec<Box<Writer+'static>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiWriter {
|
impl MultiWriter {
|
||||||
/// Creates a new `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 }
|
MultiWriter { writers: writers }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
#![feature(macro_rules, globs, managed_boxes, linkage)]
|
#![feature(macro_rules, globs, managed_boxes, linkage)]
|
||||||
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
||||||
#![feature(import_shadowing)]
|
#![feature(import_shadowing)]
|
||||||
|
#![feature(issue_5723_bootstrap)]
|
||||||
|
|
||||||
// Don't link to std. We are std.
|
// Don't link to std. We are std.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
|
@ -825,12 +825,20 @@ pub trait GenericPathUnsafe {
|
||||||
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
|
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> {
|
pub struct Display<'a, P> {
|
||||||
path: &'a P,
|
path: &'a P,
|
||||||
filename: bool
|
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> {
|
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.as_maybe_owned().as_slice().fmt(f)
|
self.as_maybe_owned().as_slice().fmt(f)
|
||||||
|
|
|
@ -291,7 +291,7 @@ mod imp {
|
||||||
|
|
||||||
struct Context<'a> {
|
struct Context<'a> {
|
||||||
idx: int,
|
idx: int,
|
||||||
writer: &'a mut Writer,
|
writer: &'a mut Writer+'a,
|
||||||
last_error: Option<IoError>,
|
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
|
/// whenever `next` is called, waiting for a new message, and `None` will be
|
||||||
/// returned when the corresponding channel has hung up.
|
/// returned when the corresponding channel has hung up.
|
||||||
#[unstable]
|
#[unstable]
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub struct Messages<'a, T:'a> {
|
||||||
|
rx: &'a Receiver<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stage0 only
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[unstable]
|
||||||
pub struct Messages<'a, T> {
|
pub struct Messages<'a, T> {
|
||||||
rx: &'a Receiver<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