Implement generalized object and type parameter bounds (Fixes #16462)

This commit is contained in:
Niko Matsakis 2014-08-27 21:46:52 -04:00
parent 3ee047ae1f
commit 1b487a8906
272 changed files with 6783 additions and 3154 deletions

View File

@ -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>")
} }

View File

@ -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>

View File

@ -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() }

View File

@ -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

View File

@ -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>>

View File

@ -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) {

View File

@ -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,

View File

@ -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))
} }
} }
} }

View File

@ -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> {

View File

@ -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

View File

@ -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

View File

@ -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") }
} }

View File

@ -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() }
} }

View File

@ -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;

View File

@ -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)
} }

View File

@ -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

View File

@ -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;

View File

@ -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>,
} }

View File

@ -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 {

View File

@ -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<()>
{ {

View File

@ -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) }
} }

View File

@ -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> {

View File

@ -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)]

View File

@ -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 {

View File

@ -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 }

View File

@ -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>
} }

View File

@ -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,
} }

View File

@ -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)]),

View File

@ -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

View File

@ -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),
} }

View File

@ -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"));

View File

@ -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)]

View File

@ -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;

View File

@ -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 }
}

View File

@ -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>,
} }

View File

@ -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))));

View File

@ -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));
} }

View File

@ -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,

View File

@ -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(..) => {

View File

@ -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>,
} }

View File

@ -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));

View File

@ -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

View File

@ -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 };

View File

@ -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) {

View File

@ -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, ()>;
/** /**

View File

@ -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

View File

@ -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
} }

View File

@ -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, ());
} }

View File

@ -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 => { }
} }
} }
} }

View File

@ -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 {

View File

@ -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,
} }

View File

@ -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());
} }

View File

@ -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>,

View File

@ -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;
} }

View File

@ -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"),

View File

@ -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) => {

View File

@ -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>,
} }
}) })
} }

View File

@ -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

View File

@ -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
} }
} }

View File

@ -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

View File

@ -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);
}

View File

@ -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 (&region_param, (&region_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 &region_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");
}

View File

@ -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,

View File

@ -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(),
&param.bounds, &param.unbound,
&param.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, &param_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,
&param_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,

View File

@ -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(),

View File

@ -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());
} }
} }
} }

View File

@ -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))

View File

@ -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))

View File

@ -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)),
} }
} }
} }

View File

@ -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))
}
}

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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()))
} }
} }

View File

@ -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;
}

View File

@ -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))
}
}

View File

@ -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
} }

View File

@ -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,
} }
} }

View File

@ -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) |

View File

@ -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,

View File

@ -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 => {}

View File

@ -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 {

View File

@ -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,

View File

@ -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> {

View File

@ -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

View File

@ -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

View File

@ -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 }
} }

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,
} }

View File

@ -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)]

View File

@ -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>,

View File

@ -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> {

View File

@ -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,
} }

View File

@ -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 }
} }
} }

View File

@ -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]

View File

@ -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)

View File

@ -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>,
} }

View File

@ -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