diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6a3e1fa2862..13d4a0a1f0a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -105,9 +105,9 @@ pub trait BoxAny { } #[stable] -impl BoxAny for Box { +impl BoxAny for Box { #[inline] - fn downcast(self) -> Result, Box> { + fn downcast(self) -> Result, Box> { if self.is::() { unsafe { // Get the raw representation of the trait object @@ -132,7 +132,7 @@ impl fmt::Show for Box { } } -impl fmt::Show for Box { +impl fmt::Show for Box { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Box") } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 418bb147d20..47c56375ada 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -49,19 +49,29 @@ struct Node { value: T, } -/// An iterator over references to the items of a `DList`. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Items<'a, T> { head: &'a Link, tail: Rawlink>, nelem: uint, } +/// An iterator over references to the items of a `DList`. +#[cfg(not(stage0))] +pub struct Items<'a, T:'a> { + head: &'a Link, + tail: Rawlink>, + nelem: uint, +} + // FIXME #11820: the &'a Option<> of the Link stops clone working. impl<'a, T> Clone for Items<'a, T> { fn clone(&self) -> Items<'a, T> { *self } } -/// An iterator over mutable references to the items of a `DList`. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct MutItems<'a, T> { list: &'a mut DList, head: Rawlink>, @@ -69,7 +79,16 @@ pub struct MutItems<'a, T> { nelem: uint, } -/// A consuming iterator over the items of a `DList`. +/// An iterator over mutable references to the items of a `DList`. +#[cfg(not(stage0))] +pub struct MutItems<'a, T:'a> { + list: &'a mut DList, + head: Rawlink>, + tail: Rawlink>, + nelem: uint, +} + +/// An iterator over mutable references to the items of a `DList`. #[deriving(Clone)] pub struct MoveItems { list: DList diff --git a/src/libcollections/priority_queue.rs b/src/libcollections/priority_queue.rs index 674fa129943..905078ccc3c 100644 --- a/src/libcollections/priority_queue.rs +++ b/src/libcollections/priority_queue.rs @@ -515,11 +515,18 @@ impl PriorityQueue { } } -/// `PriorityQueue` iterator. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Items <'a, T> { iter: slice::Items<'a, T>, } +/// `PriorityQueue` iterator. +#[cfg(not(stage0))] +pub struct Items <'a, T:'a> { + iter: slice::Items<'a, T>, +} + impl<'a, T> Iterator<&'a T> for Items<'a, T> { #[inline] fn next(&mut self) -> Option<(&'a T)> { self.iter.next() } diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index 2f0fbfadb17..6b293c9f4d8 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -293,7 +293,8 @@ impl RingBuf { } } -/// `RingBuf` iterator. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Items<'a, T> { lo: uint, index: uint, @@ -301,6 +302,15 @@ pub struct Items<'a, T> { elts: &'a [Option], } +/// `RingBuf` iterator. +#[cfg(not(stage0))] +pub struct Items<'a, T:'a> { + lo: uint, + index: uint, + rindex: uint, + elts: &'a [Option], +} + impl<'a, T> Iterator<&'a T> for Items<'a, T> { #[inline] fn next(&mut self) -> Option<&'a T> { @@ -348,13 +358,22 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { } } -/// `RingBuf` mutable iterator. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct MutItems<'a, T> { remaining1: &'a mut [Option], remaining2: &'a mut [Option], nelts: uint, } +/// `RingBuf` mutable iterator. +#[cfg(not(stage0))] +pub struct MutItems<'a, T:'a> { + remaining1: &'a mut [Option], + remaining2: &'a mut [Option], + nelts: uint, +} + impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { #[inline] #[allow(deprecated)] // mut_shift_ref diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs index 534262d79c9..5ef1dd2ab22 100644 --- a/src/libcollections/smallintmap.rs +++ b/src/libcollections/smallintmap.rs @@ -489,19 +489,37 @@ macro_rules! double_ended_iterator { } } -/// Forward iterator over a map. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Entries<'a, T> { front: uint, back: uint, iter: slice::Items<'a, Option> } +/// Forward iterator over a map. +#[cfg(not(stage0))] +pub struct Entries<'a, T:'a> { + front: uint, + back: uint, + iter: slice::Items<'a, Option> +} + 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> +} + /// Forward iterator over the key-value pairs of a map, with the /// values being mutable. -pub struct MutEntries<'a, T> { +#[cfg(not(stage0))] +pub struct MutEntries<'a, T:'a> { front: uint, back: uint, iter: slice::MutItems<'a, Option> diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 8e5ffbd1686..6bb1e4a5ad0 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -668,7 +668,8 @@ impl TreeMap { } } -/// A lazy forward iterator over a map. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Entries<'a, K, V> { stack: Vec<&'a TreeNode>, // See the comment on MutEntries; this is just to allow @@ -679,13 +680,32 @@ pub struct Entries<'a, K, V> { remaining_max: uint } -/// Lazy backward iterator over a map. +/// Lazy forward iterator over a map +#[cfg(not(stage0))] +pub struct Entries<'a, K:'a, V:'a> { + stack: Vec<&'a TreeNode>, + // 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>). + node: *const TreeNode, + remaining_min: uint, + remaining_max: uint +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct RevEntries<'a, K, V> { iter: Entries<'a, K, V>, } -/// A lazy forward iterator over a map that allows for the mutation of -/// the values. +/// Lazy backward iterator over a map +#[cfg(not(stage0))] +pub struct RevEntries<'a, K:'a, V:'a> { + iter: Entries<'a, K, V>, +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct MutEntries<'a, K, V> { stack: Vec<&'a mut TreeNode>, // Unfortunately, we require some unsafe-ness to get around the @@ -712,11 +732,46 @@ pub struct MutEntries<'a, K, V> { remaining_max: uint } -/// Lazy backward iterator over a map. +/// Lazy forward iterator over a map that allows for the mutation of +/// the values. +#[cfg(not(stage0))] +pub struct MutEntries<'a, K:'a, V:'a> { + stack: Vec<&'a mut TreeNode>, + // 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, + remaining_min: uint, + remaining_max: uint +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct RevMutEntries<'a, K, V> { iter: MutEntries<'a, K, V>, } +/// Lazy backward iterator over a map +#[cfg(not(stage0))] +pub struct RevMutEntries<'a, K:'a, V:'a> { + iter: MutEntries<'a, K, V>, +} /// TreeMap keys iterator. pub type Keys<'a, K, V> = @@ -885,9 +940,7 @@ fn mut_deref(x: &mut Option>>) } } - - -/// A lazy forward iterator over a map that consumes the map while iterating. +/// Lazy forward iterator over a map that consumes the map while iterating pub struct MoveEntries { stack: Vec>, remaining: uint @@ -1322,45 +1375,90 @@ impl TreeSet { } } -/// A lazy forward iterator over a set. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct SetItems<'a, T> { iter: Entries<'a, T, ()> } -/// Lazy backward iterator over a set. +/// A lazy forward iterator over a set. +#[cfg(not(stage0))] +pub struct SetItems<'a, T:'a> { + iter: Entries<'a, T, ()> +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct RevSetItems<'a, T> { iter: RevEntries<'a, T, ()> } +/// A lazy backward iterator over a set. +#[cfg(not(stage0))] +pub struct RevSetItems<'a, T:'a> { + iter: RevEntries<'a, T, ()> +} + /// A lazy forward iterator over a set that consumes the set while iterating. pub type MoveSetItems = iter::Map<'static, (T, ()), T, MoveEntries>; -/// A lazy iterator producing elements in the set difference (in-order). +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct DifferenceItems<'a, T> { a: Peekable<&'a T, SetItems<'a, T>>, b: Peekable<&'a T, SetItems<'a, T>>, } -/// A lazy iterator producing elements in the set symmetric difference (in-order). +/// A lazy iterator producing elements in the set difference (in-order). +#[cfg(not(stage0))] +pub struct DifferenceItems<'a, T:'a> { + a: Peekable<&'a T, SetItems<'a, T>>, + b: Peekable<&'a T, SetItems<'a, T>>, +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct SymDifferenceItems<'a, T> { a: Peekable<&'a T, SetItems<'a, T>>, b: Peekable<&'a T, SetItems<'a, T>>, } -/// A lazy iterator producing elements in the set intersection (in-order). +/// A lazy iterator producing elements in the set symmetric difference (in-order). +#[cfg(not(stage0))] +pub struct SymDifferenceItems<'a, T:'a> { + a: Peekable<&'a T, SetItems<'a, T>>, + b: Peekable<&'a T, SetItems<'a, T>>, +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct IntersectionItems<'a, T> { a: Peekable<&'a T, SetItems<'a, T>>, b: Peekable<&'a T, SetItems<'a, T>>, } -/// A lazy iterator producing elements in the set union (in-order). +/// A lazy iterator producing elements in the set intersection (in-order). +#[cfg(not(stage0))] +pub struct IntersectionItems<'a, T:'a> { + a: Peekable<&'a T, SetItems<'a, T>>, + b: Peekable<&'a T, SetItems<'a, T>>, +} + +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct UnionItems<'a, T> { a: Peekable<&'a T, SetItems<'a, T>>, b: Peekable<&'a T, SetItems<'a, T>>, } -/// Compare `x` and `y`, but return `short` if x is None and `long` if y is -/// `None`. +/// A lazy iterator producing elements in the set union (in-order). +#[cfg(not(stage0))] +pub struct UnionItems<'a, T:'a> { + a: Peekable<&'a T, SetItems<'a, T>>, + b: Peekable<&'a T, SetItems<'a, T>>, +} + +/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { match (x, y) { diff --git a/src/libcollections/trie.rs b/src/libcollections/trie.rs index 7943c1da2c8..e79ec67cba0 100644 --- a/src/libcollections/trie.rs +++ b/src/libcollections/trie.rs @@ -857,7 +857,8 @@ fn remove(count: &mut uint, child: &mut Child, key: uint, return ret; } -/// A forward iterator over a map. +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] pub struct Entries<'a, T> { stack: [slice::Items<'a, Child>, .. NUM_CHUNKS], length: uint, @@ -865,9 +866,28 @@ pub struct Entries<'a, T> { remaining_max: uint } +/// A forward iterator over a map. +#[cfg(not(stage0))] +pub struct Entries<'a, T:'a> { + stack: [slice::Items<'a, Child>, .. 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>, .. NUM_CHUNKS], + length: uint, + remaining_min: uint, + remaining_max: uint +} + /// A forward iterator over the key-value pairs of a map, with the /// values being mutable. -pub struct MutEntries<'a, T> { +#[cfg(not(stage0))] +pub struct MutEntries<'a, T:'a> { stack: [slice::MutItems<'a, Child>, .. NUM_CHUNKS], length: uint, remaining_min: uint, diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d67a01b6dee..f383677ed14 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1620,9 +1620,13 @@ pub struct MoveItems { impl Iterator for MoveItems { #[inline] - fn next(&mut self) -> Option { + fn next<'a>(&'a mut self) -> Option { 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 Iterator for MoveItems { impl DoubleEndedIterator for MoveItems { #[inline] - fn next_back(&mut self) -> Option { + fn next_back<'a>(&'a mut self) -> Option { 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)) } } } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 1809988847b..625b89b3bae 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -132,7 +132,7 @@ pub trait AnyRefExt<'a> { } #[stable] -impl<'a> AnyRefExt<'a> for &'a Any { +impl<'a> AnyRefExt<'a> for &'a Any+'a { #[inline] #[stable] fn is(self) -> bool { @@ -181,7 +181,7 @@ pub trait AnyMutRefExt<'a> { } #[stable] -impl<'a> AnyMutRefExt<'a> for &'a mut Any { +impl<'a> AnyMutRefExt<'a> for &'a mut Any+'a { #[inline] #[unstable = "naming conventions around acquiring references may change"] fn downcast_mut(self) -> Option<&'a mut T> { diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 2a7b1630edf..4cbe7d6d963 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -324,6 +324,16 @@ impl PartialEq for RefCell { /// Wraps a borrowed reference to a value in a `RefCell` box. #[unstable] +#[cfg(not(stage0))] +pub struct Ref<'b, T:'b> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _parent: &'b RefCell +} + +/// Dox. +#[unstable] +#[cfg(stage0)] pub struct Ref<'b, T> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref @@ -369,6 +379,16 @@ pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> { /// Wraps a mutable borrowed reference to a value in a `RefCell` box. #[unstable] +#[cfg(not(stage0))] +pub struct RefMut<'b, T:'b> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _parent: &'b RefCell +} + +/// Dox. +#[unstable] +#[cfg(stage0)] pub struct RefMut<'b, T> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref diff --git a/src/libcore/finally.rs b/src/libcore/finally.rs index 514b3f90df7..c36150eb964 100644 --- a/src/libcore/finally.rs +++ b/src/libcore/finally.rs @@ -102,6 +102,13 @@ pub fn try_finally(mutate: &mut T, try_fn(&mut *f.mutate, drop) } +#[cfg(not(stage0))] +struct Finallyalizer<'a,A:'a> { + mutate: &'a mut A, + dtor: |&mut A|: 'a +} + +#[cfg(stage0)] struct Finallyalizer<'a,A> { mutate: &'a mut A, dtor: |&mut A|: 'a diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 85a289f1a30..f7ff92f5ce3 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -92,7 +92,7 @@ pub struct Formatter<'a> { /// Optionally specified precision for numeric types pub precision: Option, - buf: &'a mut FormatWriter, + buf: &'a mut FormatWriter+'a, curarg: slice::Items<'a, Argument<'a>>, args: &'a [Argument<'a>], } @@ -524,7 +524,7 @@ impl<'a, T: Show> Show for &'a T { impl<'a, T: Show> Show for &'a mut T { fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) } } -impl<'a> Show for &'a Show { +impl<'a> Show for &'a Show+'a { fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) } } @@ -692,7 +692,7 @@ macro_rules! tuple ( tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl<'a> Show for &'a any::Any { +impl<'a> Show for &'a any::Any+'a { fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") } } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index b2bd8d46fb5..7df8a7864d9 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -673,7 +673,7 @@ pub trait MutableDoubleEndedIterator { fn reverse_(&mut self); } -impl<'a, A, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T { +impl<'a, A:'a, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T { // FIXME: #5898: should be called `reverse` /// Use an iterator to reverse a container in-place fn reverse_(&mut self) { @@ -777,18 +777,26 @@ impl + RandomAccessIterator> RandomAccessIterato /// A mutable reference to an iterator #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[cfg(not(stage0))] +pub struct ByRef<'a, T:'a> { + iter: &'a mut T +} + +/// Dox +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[cfg(stage0)] pub struct ByRef<'a, T> { iter: &'a mut T } -impl<'a, A, T: Iterator> Iterator for ByRef<'a, T> { +impl<'a, A, T: Iterator+'a> Iterator for ByRef<'a, T> { #[inline] fn next(&mut self) -> Option { self.iter.next() } #[inline] fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } } -impl<'a, A, T: DoubleEndedIterator> DoubleEndedIterator for ByRef<'a, T> { +impl<'a, A, T: DoubleEndedIterator+'a> DoubleEndedIterator for ByRef<'a, T> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7e2ea492d4c..050e2348111 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -58,7 +58,7 @@ #![no_std] #![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)] -#![feature(simd, unsafe_destructor)] +#![feature(simd, unsafe_destructor, issue_5723_bootstrap)] #![deny(missing_doc)] mod macros; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f0c39766ebb..947fa2ec92e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -369,7 +369,7 @@ pub unsafe fn transmute_copy(src: &T) -> U { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T { +pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T { transmute(ptr) } @@ -377,7 +377,7 @@ pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T { #[inline] #[unstable = "this function may be removed in the future due to its \ questionable utility"] -pub unsafe fn copy_mut_lifetime<'a, S, T>(_ptr: &'a mut S, +pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T { transmute(ptr) } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 475c2e94ec7..5a70cd8c847 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -996,9 +996,6 @@ impl<'a, T> Default for &'a [T] { fn default() -> &'a [T] { &[] } } - - - // // Iterators // @@ -1128,7 +1125,16 @@ impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {} /// An iterator over the slices of a vector separated by elements that /// match a predicate function. +#[cfg(not(stage0))] #[experimental = "needs review"] +pub struct Splits<'a, T:'a> { + v: &'a [T], + pred: |t: &T|: 'a -> bool, + finished: bool +} + +/// Dox. +#[cfg(stage0)] pub struct Splits<'a, T> { v: &'a [T], pred: |t: &T|: 'a -> bool, @@ -1186,7 +1192,16 @@ impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> { /// An iterator over the subslices of the vector which are separated /// by elements that match `pred`. +#[cfg(not(stage0))] #[experimental = "needs review"] +pub struct MutSplits<'a, T:'a> { + v: &'a mut [T], + pred: |t: &T|: 'a -> bool, + finished: bool +} + +/// Dox +#[cfg(stage0)] pub struct MutSplits<'a, T> { v: &'a mut [T], pred: |t: &T|: 'a -> bool, @@ -1255,7 +1270,16 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> { /// An iterator over the slices of a vector separated by elements that /// match a predicate function, splitting at most a fixed number of times. +#[cfg(not(stage0))] #[experimental = "needs review"] +pub struct SplitsN<'a, T:'a> { + iter: Splits<'a, T>, + count: uint, + invert: bool +} + +/// Dox. +#[cfg(stage0)] pub struct SplitsN<'a, T> { iter: Splits<'a, T>, count: uint, @@ -1291,6 +1315,7 @@ impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> { /// An iterator over the (overlapping) slices of length `size` within /// a vector. +#[cfg(stage0)] #[deriving(Clone)] #[experimental = "needs review"] pub struct Windows<'a, T> { @@ -1298,7 +1323,16 @@ pub struct Windows<'a, T> { size: uint } +/// An iterator over the (overlapping) slices of length `size` within +/// a vector. +#[cfg(not(stage0))] +#[deriving(Clone)] #[experimental = "needs review"] +pub struct Windows<'a, T:'a> { + v: &'a [T], + size: uint +} + impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> { #[inline] fn next(&mut self) -> Option<&'a [T]> { @@ -1327,6 +1361,7 @@ impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> { /// /// When the vector len is not evenly divided by the chunk size, /// the last slice of the iteration will be the remainder. +#[cfg(stage0)] #[deriving(Clone)] #[experimental = "needs review"] pub struct Chunks<'a, T> { @@ -1334,6 +1369,18 @@ pub struct Chunks<'a, T> { size: uint } +/// An iterator over a vector in (non-overlapping) chunks (`size` +/// elements at a time). +/// +/// When the vector len is not evenly divided by the chunk size, +/// the last slice of the iteration will be the remainder. +#[cfg(not(stage0))] +#[deriving(Clone)] +pub struct Chunks<'a, T:'a> { + v: &'a [T], + size: uint +} + #[experimental = "needs review"] impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> { #[inline] @@ -1400,7 +1447,15 @@ impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> { /// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When /// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be /// the remainder. +#[cfg(not(stage0))] #[experimental = "needs review"] +pub struct MutChunks<'a, T:'a> { + v: &'a mut [T], + chunk_size: uint +} + +/// Dox. +#[cfg(stage0)] pub struct MutChunks<'a, T> { v: &'a mut [T], chunk_size: uint diff --git a/src/libdebug/lib.rs b/src/libdebug/lib.rs index 6341a380563..cc97eeffe7a 100644 --- a/src/libdebug/lib.rs +++ b/src/libdebug/lib.rs @@ -25,7 +25,7 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/master/")] #![experimental] -#![feature(managed_boxes, macro_rules)] +#![feature(managed_boxes, macro_rules, issue_5723_bootstrap)] #![allow(experimental)] pub mod fmt; diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index 20f96d24a5f..dbd2c09497b 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -95,7 +95,7 @@ pub struct ReprVisitor<'a> { ptr: *const u8, ptr_stk: Vec<*const u8>, var_stk: Vec, - writer: &'a mut io::Writer, + writer: &'a mut io::Writer+'a, last_err: Option, } diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs index e4d61c47cc2..9e46da56a8e 100644 --- a/src/libfourcc/lib.rs +++ b/src/libfourcc/lib.rs @@ -72,8 +72,8 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("fourcc", expand_syntax_ext); } -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { let (expr, endian) = parse_tts(cx, tts); let little = match endian { diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 7cac0d25abf..10cc7e8afe9 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -271,6 +271,7 @@ pub fn main() { #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] +#![feature(issue_5723_bootstrap)] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/master/")] @@ -499,7 +500,7 @@ pub trait GraphWalk<'a, N, E> { /// Renders directed graph `g` into the writer `w` in DOT syntax. /// (Main entry point for the library.) -pub fn render<'a, N, E, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( +pub fn render<'a, N:'a, E:'a, G:Labeller<'a,N,E>+GraphWalk<'a,N,E>, W:Writer>( g: &'a G, w: &mut W) -> io::IoResult<()> { diff --git a/src/libgraphviz/maybe_owned_vec.rs b/src/libgraphviz/maybe_owned_vec.rs index 987f214b153..17c75b76bc1 100644 --- a/src/libgraphviz/maybe_owned_vec.rs +++ b/src/libgraphviz/maybe_owned_vec.rs @@ -34,6 +34,14 @@ use std::slice; /// Some clients will have a pre-allocated vector ready to hand off in /// a slice; others will want to create the set on the fly and hand /// off ownership, via `Growable`. +#[cfg(not(stage0))] +pub enum MaybeOwnedVector<'a,T:'a> { + Growable(Vec), + Borrowed(&'a [T]), +} + +/// Stage0 only. +#[cfg(stage0)] pub enum MaybeOwnedVector<'a,T> { Growable(Vec), Borrowed(&'a [T]), @@ -45,7 +53,7 @@ pub trait IntoMaybeOwnedVector<'a,T> { fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T>; } -impl<'a,T> IntoMaybeOwnedVector<'a,T> for Vec { +impl<'a,T:'a> IntoMaybeOwnedVector<'a,T> for Vec { #[inline] fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) } } diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 6254e8c55f0..058a00bcd4b 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -82,7 +82,7 @@ impl Runtime for SimpleTask { fn local_io<'a>(&'a mut self) -> Option> { None } fn stack_bounds(&self) -> (uint, uint) { fail!() } fn can_block(&self) -> bool { true } - fn wrap(self: Box) -> Box { fail!() } + fn wrap(self: Box) -> Box { fail!() } } pub fn task() -> Box { diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index 73fe8f6a93f..ffd94e0b86f 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -488,7 +488,9 @@ impl Runtime for GreenTask { fn can_block(&self) -> bool { false } - fn wrap(self: Box) -> Box { self as Box } + fn wrap(self: Box) -> Box { + self as Box + } } #[cfg(test)] diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs index 936e7cb4403..03bd96fc260 100644 --- a/src/libhexfloat/lib.rs +++ b/src/libhexfloat/lib.rs @@ -105,7 +105,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, String)> { } pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let (expr, ty_lit) = parse_tts(cx, tts); let ty = match ty_lit { diff --git a/src/libnative/task.rs b/src/libnative/task.rs index 55806caaf13..5c3beeec8ab 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -145,8 +145,8 @@ impl rt::Runtime for Ops { Local::put(cur_task); } - fn wrap(self: Box) -> Box { - self as Box + fn wrap(self: Box) -> Box { + self as Box } fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds } diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 9d401d1307c..447e3eea061 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -79,6 +79,13 @@ pub struct Weighted { pub item: T, } +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] +pub struct WeightedChoice<'a, T> { + items: &'a mut [Weighted], + weight_range: Range +} + /// A distribution that selects from a finite collection of weighted items. /// /// Each item has an associated weight that influences how likely it @@ -105,7 +112,8 @@ pub struct Weighted { /// println!("{}", wc.ind_sample(&mut rng)); /// } /// ``` -pub struct WeightedChoice<'a, T> { +#[cfg(not(stage0))] +pub struct WeightedChoice<'a, T:'a> { items: &'a mut [Weighted], weight_range: Range } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 5f460225d39..f1ed9ae8997 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -269,10 +269,17 @@ pub trait Rng { } } +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] +pub struct Generator<'a, T, R> { + rng: &'a mut R, +} + /// Iterator which will generate a stream of random items. /// /// This iterator is created via the `gen_iter` method on `Rng`. -pub struct Generator<'a, T, R> { +#[cfg(not(stage0))] +pub struct Generator<'a, T, R:'a> { rng: &'a mut R, } @@ -282,10 +289,17 @@ impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { } } +/// Note: stage0-specific version. +#[cfg(stage0)] +pub struct AsciiGenerator<'a, R> { + rng: &'a mut R, +} + /// Iterator which will continuously generate random ascii characters. /// /// This iterator is created via the `gen_ascii_chars` method on `Rng`. -pub struct AsciiGenerator<'a, R> { +#[cfg(not(stage0))] +pub struct AsciiGenerator<'a, R:'a> { rng: &'a mut R, } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 4927a8293a4..a05c877a6a6 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -24,7 +24,7 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/master/", html_playground_url = "http://play.rust-lang.org/")] -#![feature(macro_rules, phase)] +#![feature(macro_rules, phase, issue_5723_bootstrap)] #![allow(missing_doc)] extern crate serialize; @@ -662,11 +662,19 @@ pub mod writer { pub type EncodeResult = io::IoResult<()>; // rbml writing + #[cfg(stage0)] pub struct Encoder<'a, W> { pub writer: &'a mut W, size_positions: Vec, } + // rbml writing + #[cfg(not(stage0))] + pub struct Encoder<'a, W:'a> { + pub writer: &'a mut W, + size_positions: Vec, + } + fn write_sized_vuint(w: &mut W, n: uint, size: uint) -> EncodeResult { match size { 1u => w.write(&[0x80u8 | (n as u8)]), diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index 8610621d30a..8aa9a2fc8fb 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -77,7 +77,7 @@ pub fn plugin_registrar(reg: &mut Registry) { /// strategy is identical and vm.rs has comments and will be easier to follow. #[allow(experimental)] fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let regex = match parse(cx, tts) { Some(r) => r, // error is logged in 'parse' with cx.span_err diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 261d4be86b4..14642a3708a 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -958,11 +958,11 @@ pub fn pretty_print_input(sess: Session, let mut rdr = MemReader::new(src); let out = match ofile { - None => box io::stdout() as Box, + None => box io::stdout() as Box, Some(p) => { let r = io::File::create(&p); match r { - Ok(w) => box w as Box, + Ok(w) => box w as Box, Err(e) => fail!("print-print failed to open {} due to {}", p.display(), e), } diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 7c19b25e01c..18f4b79de6e 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -74,7 +74,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ // A temporary feature gate used to enable parser extensions needed // to bootstrap fix for #5723. - ("issue_5723_bootstrap", Active), + ("issue_5723_bootstrap", Accepted), // These are used to test this portion of the compiler, they don't actually // mean anything @@ -97,7 +97,6 @@ enum Status { /// A set of features to be used by later passes. pub struct Features { pub default_type_params: Cell, - pub issue_5723_bootstrap: Cell, pub overloaded_calls: Cell, pub rustc_diagnostic_macros: Cell, pub import_shadowing: Cell, @@ -107,7 +106,6 @@ impl Features { pub fn new() -> Features { Features { default_type_params: Cell::new(false), - issue_5723_bootstrap: Cell::new(false), overloaded_calls: Cell::new(false), rustc_diagnostic_macros: Cell::new(false), import_shadowing: Cell::new(false), @@ -310,7 +308,7 @@ impl<'a> Visitor<()> for Context<'a> { fn visit_ty(&mut self, t: &ast::Ty, _: ()) { match t.node { - ast::TyClosure(closure, _) if closure.onceness == ast::Once => { + ast::TyClosure(closure) if closure.onceness == ast::Once => { self.gate_feature("once_fns", t.span, "once functions are \ experimental and likely to be removed"); @@ -439,7 +437,6 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) { sess.abort_if_errors(); sess.features.default_type_params.set(cx.has_feature("default_type_params")); - sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap")); sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls")); sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros")); sess.features.import_shadowing.set(cx.has_feature("import_shadowing")); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 239e858eeeb..9b3cc2b6a0a 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -31,6 +31,7 @@ This API is completely unstable and subject to change. #![allow(deprecated)] #![feature(macro_rules, globs, struct_variant, managed_boxes, quote)] #![feature(default_type_params, phase, unsafe_destructor)] +#![feature(issue_5723_bootstrap)] #![allow(unknown_features)] // NOTE: Remove after next snapshot #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 6a1c7c6c951..ca2f47328db 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -27,8 +27,6 @@ pub static tag_items_data_item: uint = 0x04; pub static tag_items_data_item_family: uint = 0x05; -pub static tag_items_data_item_ty_param_bounds: uint = 0x06; - pub static tag_items_data_item_type: uint = 0x07; pub static tag_items_data_item_symbol: uint = 0x08; @@ -179,7 +177,6 @@ pub static tag_lang_items_missing: uint = 0x74; pub static tag_item_unnamed_field: uint = 0x75; pub static tag_items_data_item_visibility: uint = 0x76; -pub static tag_items_data_item_sized: uint = 0x77; pub static tag_item_method_tps: uint = 0x79; pub static tag_item_method_fty: uint = 0x7a; @@ -222,12 +219,6 @@ pub struct LinkMeta { pub crate_hash: Svh, } -pub static tag_region_param_def: uint = 0x90; -pub static tag_region_param_def_ident: uint = 0x91; -pub static tag_region_param_def_def_id: uint = 0x92; -pub static tag_region_param_def_space: uint = 0x93; -pub static tag_region_param_def_index: uint = 0x94; - pub static tag_unboxed_closures: uint = 0x95; pub static tag_unboxed_closure: uint = 0x96; pub static tag_unboxed_closure_type: uint = 0x97; @@ -239,3 +230,18 @@ pub static tag_struct_field_id: uint = 0x9b; pub static tag_attribute_is_sugared_doc: uint = 0x9c; +pub static tag_trait_def_bounds: uint = 0x9d; + +pub static tag_items_data_region: uint = 0x9e; + +pub static tag_region_param_def: uint = 0xa0; +pub static tag_region_param_def_ident: uint = 0xa1; +pub static tag_region_param_def_def_id: uint = 0xa2; +pub static tag_region_param_def_space: uint = 0xa3; +pub static tag_region_param_def_index: uint = 0xa4; + +pub static tag_type_param_def: uint = 0xa5; + +pub static tag_item_generics: uint = 0xa6; +pub static tag_method_ty_generics: uint = 0xa7; + diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 74810261d4a..904ca2416e0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -18,9 +18,9 @@ use metadata::common::*; use metadata::csearch::StaticMethodInfo; use metadata::csearch; use metadata::cstore; -use metadata::tydecode::{parse_ty_data, parse_def_id}; -use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data}; -use metadata::tydecode::{parse_trait_ref_data}; +use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, + parse_type_param_def_data, parse_bounds_data, + parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::def; use middle::lang_items; use middle::resolve::TraitItemKind; @@ -242,48 +242,14 @@ fn item_trait_ref(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef { doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_defs(item: rbml::Doc, - tcx: &ty::ctxt, - cdata: Cmd, - tag: uint) - -> subst::VecPerParamSpace { - let mut bounds = subst::VecPerParamSpace::empty(); - reader::tagged_docs(item, tag, |p| { - let bd = parse_type_param_def_data( - p.data, p.start, cdata.cnum, tcx, - |_, did| translate_def_id(cdata, did)); - bounds.push(bd.space, bd); - true - }); - bounds +fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds { + parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx, + |_, did| translate_def_id(cdata, did)) } -fn item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd) - -> subst::VecPerParamSpace -{ - let mut v = subst::VecPerParamSpace::empty(); - reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| { - let ident_str_doc = reader::get_doc(rp_doc, - tag_region_param_def_ident); - let ident = item_name(&*token::get_ident_interner(), ident_str_doc); - let def_id_doc = reader::get_doc(rp_doc, - tag_region_param_def_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); - - let doc = reader::get_doc(rp_doc, tag_region_param_def_space); - let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint); - - let doc = reader::get_doc(rp_doc, tag_region_param_def_index); - let index = reader::doc_as_u64(doc) as uint; - - v.push(space, ty::RegionParameterDef { name: ident.name, - def_id: def_id, - space: space, - index: index }); - true - }); - v +fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds { + let d = reader::get_doc(doc, tag_trait_def_bounds); + doc_bounds(d, tcx, cdata) } fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec { @@ -382,24 +348,11 @@ pub fn get_trait_def(cdata: Cmd, tcx: &ty::ctxt) -> ty::TraitDef { let item_doc = lookup_item(item_id, cdata.data()); - let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, - tag_items_data_item_ty_param_bounds); - let rp_defs = item_region_param_defs(item_doc, cdata); - let mut bounds = ty::empty_builtin_bounds(); - // Collect the builtin bounds from the encoded supertraits. - // FIXME(#8559): They should be encoded directly. - reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| { - // NB. Bypasses real supertraits. See get_supertraits() if you wanted them. - let trait_ref = doc_trait_ref(trait_doc, tcx, cdata); - tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| { - bounds.add(bound); - }); - true - }); + let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); + let bounds = trait_def_bounds(item_doc, tcx, cdata); ty::TraitDef { - generics: ty::Generics {types: tp_defs, - regions: rp_defs}, + generics: generics, bounds: bounds, trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)) } @@ -413,12 +366,10 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx, cdata); - let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds); - let rp_defs = item_region_param_defs(item, cdata); + let generics = doc_generics(item, tcx, cdata, tag_item_generics); ty::Polytype { - generics: ty::Generics {types: tp_defs, - regions: rp_defs}, + generics: generics, ty: t } } @@ -794,6 +745,7 @@ pub fn get_impl_or_trait_item(intr: Rc, tcx: &ty::ctxt) -> ty::ImplOrTraitItem { let method_doc = lookup_item(id, cdata.data()); + let def_id = item_def_id(method_doc, cdata); let container_id = item_reqd_and_translated_parent_item(cdata.cnum, @@ -808,18 +760,13 @@ pub fn get_impl_or_trait_item(intr: Rc, match item_sort(method_doc) { 'r' | 'p' => { - let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, - tag_item_method_tps); - let rp_defs = item_region_param_defs(method_doc, cdata); + let generics = doc_generics(method_doc, tcx, cdata, + tag_method_ty_generics); let fty = doc_method_fty(method_doc, tcx, cdata); let vis = item_visibility(method_doc); let explicit_self = get_explicit_self(method_doc); let provided_source = get_provided_source(method_doc, cdata); - let generics = ty::Generics { - types: type_param_defs, - regions: rp_defs, - }; ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, fty, @@ -1392,3 +1339,57 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { _ => false, } } + +fn doc_generics(base_doc: rbml::Doc, + tcx: &ty::ctxt, + cdata: Cmd, + tag: uint) + -> ty::Generics +{ + let doc = reader::get_doc(base_doc, tag); + + let mut types = subst::VecPerParamSpace::empty(); + reader::tagged_docs(doc, tag_type_param_def, |p| { + let bd = parse_type_param_def_data( + p.data, p.start, cdata.cnum, tcx, + |_, did| translate_def_id(cdata, did)); + types.push(bd.space, bd); + true + }); + + let mut regions = subst::VecPerParamSpace::empty(); + reader::tagged_docs(doc, tag_region_param_def, |rp_doc| { + let ident_str_doc = reader::get_doc(rp_doc, + tag_region_param_def_ident); + let ident = item_name(&*token::get_ident_interner(), ident_str_doc); + let def_id_doc = reader::get_doc(rp_doc, + tag_region_param_def_def_id); + let def_id = reader::with_doc_data(def_id_doc, parse_def_id); + let def_id = translate_def_id(cdata, def_id); + + let doc = reader::get_doc(rp_doc, tag_region_param_def_space); + let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint); + + let doc = reader::get_doc(rp_doc, tag_region_param_def_index); + let index = reader::doc_as_u64(doc) as uint; + + let mut bounds = Vec::new(); + reader::tagged_docs(rp_doc, tag_items_data_region, |p| { + bounds.push( + parse_region_data( + p.data, cdata.cnum, p.start, tcx, + |_, did| translate_def_id(cdata, did))); + true + }); + + regions.push(space, ty::RegionParameterDef { name: ident.name, + def_id: def_id, + space: space, + index: index, + bounds: bounds }); + + true + }); + + ty::Generics { types: types, regions: regions } +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ffa4a1b5bf0..1386e23b77d 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -19,8 +19,7 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; use metadata::tyencode; -use middle::subst::VecPerParamSpace; -use middle::ty::{node_id_to_type, lookup_item_type}; +use middle::ty::{lookup_item_type}; use middle::astencode; use middle::ty; use middle::typeck; @@ -150,45 +149,6 @@ pub fn def_to_string(did: DefId) -> String { format!("{}:{}", did.krate, did.node) } -fn encode_ty_type_param_defs(rbml_w: &mut Encoder, - ecx: &EncodeContext, - params: &VecPerParamSpace, - 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) { - for param in params.iter() { - rbml_w.start_tag(tag_region_param_def); - - rbml_w.start_tag(tag_region_param_def_ident); - encode_name(rbml_w, param.name); - rbml_w.end_tag(); - - rbml_w.wr_tagged_str(tag_region_param_def_def_id, - def_to_string(param.def_id).as_slice()); - - rbml_w.wr_tagged_u64(tag_region_param_def_space, - param.space.to_uint() as u64); - - rbml_w.wr_tagged_u64(tag_region_param_def_index, - param.index as u64); - - rbml_w.end_tag(); - } -} - fn encode_item_variances(rbml_w: &mut Encoder, ecx: &EncodeContext, id: ast::NodeId) { @@ -201,9 +161,7 @@ fn encode_item_variances(rbml_w: &mut Encoder, fn encode_bounds_and_type(rbml_w: &mut Encoder, ecx: &EncodeContext, pty: &ty::Polytype) { - encode_ty_type_param_defs(rbml_w, ecx, &pty.generics.types, - tag_items_data_item_ty_param_bounds); - encode_region_param_defs(rbml_w, &pty.generics.regions); + encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics); encode_type(ecx, rbml_w, pty.ty); } @@ -238,6 +196,33 @@ pub fn write_type(ecx: &EncodeContext, tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ); } +pub fn write_region(ecx: &EncodeContext, + rbml_w: &mut Encoder, + r: ty::Region) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_region(rbml_w.writer, ty_str_ctxt, r); +} + +fn encode_bounds(rbml_w: &mut Encoder, + ecx: &EncodeContext, + bounds: &ty::ParamBounds, + tag: uint) { + rbml_w.start_tag(tag); + + let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs }; + tyencode::enc_bounds(rbml_w.writer, ty_str_ctxt, bounds); + + rbml_w.end_tag(); +} + fn encode_type(ecx: &EncodeContext, rbml_w: &mut Encoder, typ: ty::t) { @@ -246,6 +231,14 @@ fn encode_type(ecx: &EncodeContext, rbml_w.end_tag(); } +fn encode_region(ecx: &EncodeContext, + rbml_w: &mut Encoder, + r: ty::Region) { + rbml_w.start_tag(tag_items_data_region); + write_region(ecx, rbml_w, r); + rbml_w.end_tag(); +} + fn encode_method_fty(ecx: &EncodeContext, rbml_w: &mut Encoder, typ: &ty::BareFnTy) { @@ -728,7 +721,6 @@ fn encode_info_for_struct(ecx: &EncodeContext, /* Each class has its own index, since different classes may have fields with the same name */ let mut index = Vec::new(); - let tcx = ecx.tcx; /* We encode both private and public fields -- need to include private fields to get the offsets right */ for field in fields.iter() { @@ -745,7 +737,8 @@ fn encode_info_for_struct(ecx: &EncodeContext, token::get_name(nm), id); encode_struct_field_family(rbml_w, field.vis); encode_name(rbml_w, nm); - encode_type(ecx, rbml_w, node_id_to_type(tcx, id)); + encode_bounds_and_type(rbml_w, ecx, + &lookup_item_type(ecx.tcx, local_def(id))); encode_def_id(rbml_w, local_def(id)); let stab = stability::lookup(ecx.tcx, field.id); @@ -773,7 +766,6 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(ecx.tcx, local_def(ctor_id))); encode_name(rbml_w, name.name); - encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, ctor_id)); ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); encode_parent_item(rbml_w, local_def(struct_id)); @@ -793,13 +785,60 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, rbml_w.end_tag(); } +fn encode_generics(rbml_w: &mut Encoder, + ecx: &EncodeContext, + generics: &ty::Generics, + tag: uint) +{ + rbml_w.start_tag(tag); + + // Type parameters + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + for param in generics.types.iter() { + rbml_w.start_tag(tag_type_param_def); + tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param); + rbml_w.end_tag(); + } + + // Region parameters + for param in generics.regions.iter() { + rbml_w.start_tag(tag_region_param_def); + + rbml_w.start_tag(tag_region_param_def_ident); + encode_name(rbml_w, param.name); + rbml_w.end_tag(); + + rbml_w.wr_tagged_str(tag_region_param_def_def_id, + def_to_string(param.def_id).as_slice()); + + rbml_w.wr_tagged_u64(tag_region_param_def_space, + param.space.to_uint() as u64); + + rbml_w.wr_tagged_u64(tag_region_param_def_index, + param.index as u64); + + for &bound_region in param.bounds.iter() { + encode_region(ecx, rbml_w, bound_region); + } + + rbml_w.end_tag(); + } + + rbml_w.end_tag(); +} + fn encode_method_ty_fields(ecx: &EncodeContext, rbml_w: &mut Encoder, method_ty: &ty::Method) { encode_def_id(rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.ident.name); - encode_ty_type_param_defs(rbml_w, ecx, &method_ty.generics.types, - tag_item_method_tps); + encode_generics(rbml_w, ecx, &method_ty.generics, + tag_method_ty_generics); encode_method_fty(ecx, rbml_w, &method_ty.fty); encode_visibility(rbml_w, method_ty.vis); encode_explicit_self(rbml_w, &method_ty.explicit_self); @@ -982,7 +1021,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } else { encode_family(rbml_w, 'c'); } - encode_type(ecx, rbml_w, node_id_to_type(tcx, item.id)); + encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); encode_symbol(ecx, rbml_w, item.id); encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); @@ -1222,17 +1261,14 @@ fn encode_info_for_item(ecx: &EncodeContext, } } } - ItemTrait(_, _, ref super_traits, ref ms) => { + ItemTrait(_, _, _, ref ms) => { add_to_index(item, rbml_w, index); rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'I'); encode_item_variances(rbml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); - encode_ty_type_param_defs(rbml_w, ecx, - &trait_def.generics.types, - tag_items_data_item_ty_param_bounds); - encode_region_param_defs(rbml_w, &trait_def.generics.regions); + encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics); encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, item.attrs.as_slice()); @@ -1253,13 +1289,8 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.end_tag(); } encode_path(rbml_w, path.clone()); - // FIXME(#8559): This should use the tcx's supertrait cache instead of - // reading the AST's list, because the former has already filtered out - // the builtin-kinds-as-supertraits. See corresponding fixme in decoder. - for ast_trait_ref in super_traits.iter() { - let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); - encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_super_trait_ref); - } + + encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds); // Encode the implementations of this trait. encode_extension_implementations(ecx, rbml_w, def_id); @@ -1390,7 +1421,8 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, } else { encode_family(rbml_w, 'c'); } - encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, nitem.id)); + encode_bounds_and_type(rbml_w, ecx, + &lookup_item_type(ecx.tcx,local_def(nitem.id))); encode_symbol(ecx, rbml_w, nitem.id); encode_name(rbml_w, nitem.ident.name); } @@ -1434,7 +1466,7 @@ fn my_visit_foreign_item(ni: &ForeignItem, }); } -struct EncodeVisitor<'a,'b> { +struct EncodeVisitor<'a,'b:'a> { rbml_w_for_visit_item: &'a mut Encoder<'b>, ecx_ptr:*const int, index: &'a mut Vec>, @@ -1738,7 +1770,7 @@ fn encode_unboxed_closures<'a>( } fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) { - struct StructFieldVisitor<'a, 'b> { + struct StructFieldVisitor<'a, 'b:'a> { rbml_w: &'a mut Encoder<'b>, } @@ -1760,7 +1792,7 @@ fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) { -struct ImplVisitor<'a,'b,'c> { +struct ImplVisitor<'a,'b:'a,'c:'a> { ecx: &'a EncodeContext<'b>, rbml_w: &'a mut Encoder<'c>, } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 2ef5675caa1..c18d2a7ebf4 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -147,6 +147,13 @@ pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty: parse_ty(&mut st, conv) } +pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, + conv: conv_did) -> ty::Region { + debug!("parse_region_data {}", data_log_string(data, pos)); + let mut st = parse_state_from_data(data, crate_num, pos, tcx); + parse_region(&mut st, conv) +} + pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, conv: conv_did) -> ty::BareFnTy { debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos)); @@ -168,6 +175,27 @@ pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: parse_substs(&mut st, conv) } +pub fn parse_bounds_data(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt, conv: conv_did) + -> ty::ParamBounds { + let mut st = parse_state_from_data(data, crate_num, pos, tcx); + parse_bounds(&mut st, conv) +} + +pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt, conv: conv_did) + -> ty::ExistentialBounds { + let mut st = parse_state_from_data(data, crate_num, pos, tcx); + parse_existential_bounds(&mut st, conv) +} + +pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum, + pos: uint, tcx: &ty::ctxt, conv: conv_did) + -> ty::BuiltinBounds { + let mut st = parse_state_from_data(data, crate_num, pos, tcx); + parse_builtin_bounds(&mut st, conv) +} + fn parse_size(st: &mut PState) -> Option { assert_eq!(next(st), '/'); @@ -355,9 +383,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { assert_eq!(next(st), '['); let def = parse_def(st, NominalType, |x,y| conv(x,y)); let substs = parse_substs(st, |x,y| conv(x,y)); - let bounds = parse_bounds(st, |x,y| conv(x,y)); + let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - return ty::mk_trait(st.tcx, def, substs, bounds.builtin_bounds); + return ty::mk_trait(st.tcx, def, substs, bounds); } 'p' => { let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); @@ -515,14 +543,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let fn_style = parse_fn_style(next(st)); let onceness = parse_onceness(next(st)); let store = parse_trait_store(st, |x,y| conv(x,y)); - let bounds = parse_bounds(st, |x,y| conv(x,y)); + let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y)); let abi = parse_abi_set(st); ty::ClosureTy { fn_style: fn_style, onceness: onceness, store: store, - bounds: bounds.builtin_bounds, + bounds: bounds, sig: sig, abi: abi, } @@ -601,7 +629,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef assert_eq!(next(st), '|'); let index = parse_uint(st); assert_eq!(next(st), '|'); - let bounds = Rc::new(parse_bounds(st, |x,y| conv(x,y))); + let bounds = parse_bounds(st, |x,y| conv(x,y)); let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))); ty::TypeParameterDef { @@ -614,27 +642,51 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef } } +fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds { + let r = parse_region(st, |x,y| conv(x,y)); + let bb = parse_builtin_bounds(st, conv); + return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb }; +} + +fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds { + let mut builtin_bounds = ty::empty_builtin_bounds(); + + loop { + match next(st) { + 'S' => { + builtin_bounds.add(ty::BoundSend); + } + 'Z' => { + builtin_bounds.add(ty::BoundSized); + } + 'P' => { + builtin_bounds.add(ty::BoundCopy); + } + 'T' => { + builtin_bounds.add(ty::BoundSync); + } + '.' => { + return builtin_bounds; + } + c => { + fail!("parse_bounds: bad builtin bounds ('{}')", c) + } + } + } +} + fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { + let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y)); + let mut param_bounds = ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), + opt_region_bound: None, + builtin_bounds: builtin_bounds, trait_bounds: Vec::new() }; loop { match next(st) { - 'S' => { - param_bounds.builtin_bounds.add(ty::BoundSend); - } - 'O' => { - param_bounds.builtin_bounds.add(ty::BoundStatic); - } - 'Z' => { - param_bounds.builtin_bounds.add(ty::BoundSized); - } - 'P' => { - param_bounds.builtin_bounds.add(ty::BoundCopy); - } - 'T' => { - param_bounds.builtin_bounds.add(ty::BoundSync); + 'R' => { + param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y))); } 'I' => { param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y)))); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 84ee49c207b..09be5094dc5 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -127,7 +127,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio } } -fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { +pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { match r { ty::ReLateBound(id, br) => { mywrite!(w, "b[{}|", id); @@ -232,13 +232,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { ty::ty_trait(box ty::TyTrait { def_id, ref substs, - bounds + ref bounds }) => { mywrite!(w, "x[{}|", (cx.ds)(def_id)); enc_substs(w, cx, substs); - let bounds = ty::ParamBounds {builtin_bounds: bounds, - trait_bounds: Vec::new()}; - enc_bounds(w, cx, &bounds); + enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } ty::ty_tup(ref ts) => { @@ -328,9 +326,7 @@ pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy) enc_fn_style(w, ft.fn_style); enc_onceness(w, ft.onceness); enc_trait_store(w, cx, ft.store); - let bounds = ty::ParamBounds {builtin_bounds: ft.bounds, - trait_bounds: Vec::new()}; - enc_bounds(w, cx, &bounds); + enc_existential_bounds(w, cx, &ft.bounds); enc_fn_sig(w, cx, &ft.sig); enc_abi(w, ft.abi); } @@ -349,17 +345,32 @@ fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) { enc_ty(w, cx, fsig.output); } -fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) { - for bound in bs.builtin_bounds.iter() { +pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) { + for bound in bs.iter() { match bound { ty::BoundSend => mywrite!(w, "S"), - ty::BoundStatic => mywrite!(w, "O"), ty::BoundSized => mywrite!(w, "Z"), ty::BoundCopy => mywrite!(w, "P"), ty::BoundSync => mywrite!(w, "T"), } } + mywrite!(w, "."); +} + +pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) { + enc_region(w, cx, bs.region_bound); + enc_builtin_bounds(w, cx, &bs.builtin_bounds); +} + +pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) { + enc_builtin_bounds(w, cx, &bs.builtin_bounds); + + for &r in bs.opt_region_bound.iter() { + mywrite!(w, "R"); + enc_region(w, cx, r); + } + for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); enc_trait_ref(w, cx, &**tp); @@ -372,6 +383,6 @@ pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypePara mywrite!(w, "{}:{}|{}|{}|", token::get_ident(v.ident), (cx.ds)(v.def_id), v.space.to_uint(), v.index); - enc_bounds(w, cx, &*v.bounds); + enc_bounds(w, cx, &v.bounds); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 6a8ee267542..6acd79f2976 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -942,6 +942,8 @@ trait rbml_writer_helpers { ecx: &e::EncodeContext, pty: ty::Polytype); fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs); + fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds); + fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment); fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef); fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef); @@ -1001,6 +1003,18 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { }); } + fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds) { + self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer, + &ecx.ty_str_ctxt(), + bounds))); + } + + fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) { + self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this.writer, + &ecx.ty_str_ctxt(), + bounds))); + } + fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs) { self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer, &ecx.ty_str_ctxt(), @@ -1100,9 +1114,10 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { this.emit_enum_variant_arg(1, |this| idx.encode(this)) }) } - ty::UnsizeVtable(b, def_id, ref substs) => { + ty::UnsizeVtable(ref b, def_id, ref substs) => { this.emit_enum_variant("UnsizeVtable", 2, 3, |this| { - this.emit_enum_variant_arg(0, |this| b.encode(this)); + this.emit_enum_variant_arg( + 0, |this| Ok(this.emit_existential_bounds(ecx, b))); this.emit_enum_variant_arg(1, |this| def_id.encode(this)); this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs))) }) @@ -1131,7 +1146,7 @@ impl<'a> write_tag_and_id for Encoder<'a> { } } -struct SideTableEncodingIdVisitor<'a,'b> { +struct SideTableEncodingIdVisitor<'a,'b:'a> { ecx_ptr: *const libc::c_void, new_rbml_w: &'a mut Encoder<'b>, } @@ -1380,6 +1395,7 @@ trait rbml_decoder_decoder_helpers { -> ty::TypeParameterDef; fn read_polytype(&mut self, xcx: &ExtendedDecodeContext) -> ty::Polytype; + fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds; fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs; fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment; fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext) @@ -1514,6 +1530,17 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { }).unwrap() } + fn read_existential_bounds(&mut self, xcx: &ExtendedDecodeContext) -> ty::ExistentialBounds + { + self.read_opaque(|this, doc| { + Ok(tydecode::parse_existential_bounds_data(doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a))) + }).unwrap() + } + fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs { self.read_opaque(|this, doc| { Ok(tydecode::parse_substs_data(doc.data, @@ -1638,8 +1665,9 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { ty::UnsizeStruct(box uk, idx) } 2 => { - let b: ty::BuiltinBounds = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + let b = + this.read_enum_variant_arg( + 0, |this| Ok(this.read_existential_bounds(xcx))).unwrap(); let def_id: ast::DefId = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); let substs = this.read_enum_variant_arg(2, diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 0d77b01d970..2acc92cd227 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -79,12 +79,14 @@ impl<'a> CFGBuilder<'a> { fn stmt(&mut self, stmt: Gc, pred: CFGIndex) -> CFGIndex { match stmt.node { - ast::StmtDecl(ref decl, _) => { - self.decl(&**decl, pred) + ast::StmtDecl(ref decl, id) => { + let exit = self.decl(&**decl, pred); + self.add_node(id, [exit]) } - ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => { - self.expr(expr.clone(), pred) + ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => { + let exit = self.expr(expr.clone(), pred); + self.add_node(id, [exit]) } ast::StmtMac(..) => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 230668e7066..5cb7651e99a 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -1018,7 +1018,7 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) { visitor.visit_pat(pat, true); } -struct AtBindingPatternVisitor<'a,'b> { +struct AtBindingPatternVisitor<'a,'b:'a> { cx: &'a MatchCheckCtxt<'b>, } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7c5b001354d..91c227cd5bc 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -80,11 +80,18 @@ pub trait DataFlowOperator : BitwiseOperator { fn initial_value(&self) -> bool; } +#[cfg(stage0)] struct PropagationContext<'a, 'b, O> { dfcx: &'a mut DataFlowContext<'b, O>, changed: bool } +#[cfg(not(stage0))] +struct PropagationContext<'a, 'b:'a, O:'a> { + dfcx: &'a mut DataFlowContext<'b, O>, + changed: bool +} + fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap) -> CFGIndex { let opt_cfgindex = index.find(&id).map(|&i|i); opt_cfgindex.unwrap_or_else(|| { @@ -458,7 +465,7 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> { }); } - fn pretty_print_to(&self, wr: Box, + fn pretty_print_to(&self, wr: Box, blk: &ast::Block) -> io::IoResult<()> { let mut ps = pprust::rust_printer_annotated(wr, self); try!(ps.cbox(pprust::indent_unit)); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d72eeaef841..ae9a3fa6a67 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -192,10 +192,18 @@ impl OverloadedCallType { // supplies types from the tree. After type checking is complete, you // can just use the tcx as the typer. +#[cfg(stage0)] pub struct ExprUseVisitor<'d,'t,TYPER> { typer: &'t TYPER, mc: mc::MemCategorizationContext<'t,TYPER>, - delegate: &'d mut Delegate, + delegate: &'d mut Delegate+'d, +} + +#[cfg(not(stage0))] +pub struct ExprUseVisitor<'d,'t,TYPER:'t> { + typer: &'t TYPER, + mc: mc::MemCategorizationContext<'t,TYPER>, + delegate: &'d mut Delegate+'d, } // If the TYPER results in an error, it's because the type check diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 78eeb26997d..2c79c655a99 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -64,6 +64,7 @@ pub struct EdgeIndex(pub uint); pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX); // Use a private field here to guarantee no more instances are created: +#[deriving(Show)] pub struct Direction { repr: uint } pub static Outgoing: Direction = Direction { repr: 0 }; pub static Incoming: Direction = Direction { repr: 1 }; diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index b96a75cba94..08dde0c0607 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -144,14 +144,17 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t // If this trait has builtin-kind supertraits, meet them. let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id); debug!("checking impl with self type {}", ty::get(self_ty).sty); - check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| { - span_err!(cx.tcx.sess, self_type.span, E0142, - "the type `{}', which does not fulfill `{}`, cannot implement this trait", - ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx)); - span_note!(cx.tcx.sess, self_type.span, - "types implementing this trait must fulfill `{}`", - trait_def.bounds.user_string(cx.tcx)); - }); + check_builtin_bounds( + cx, self_ty, trait_def.bounds.builtin_bounds, + |missing| { + span_err!(cx.tcx.sess, self_type.span, E0142, + "the type `{}', which does not fulfill `{}`, \ + cannot implement this trait", + ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx)); + span_note!(cx.tcx.sess, self_type.span, + "types implementing this trait must fulfill `{}`", + trait_def.bounds.user_string(cx.tcx)); + }); // If this is a destructor, check kinds. if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) { @@ -297,17 +300,15 @@ fn with_appropriate_checker(cx: &Context, match ty::get(fty).sty { ty::ty_closure(box ty::ClosureTy { store: ty::UniqTraitStore, - bounds: mut bounds, .. + bounds: bounds, + .. }) => { - // Procs can't close over non-static references! - bounds.add(ty::BoundStatic); - - b(|cx, fv| check_for_uniq(cx, fv, bounds)) + b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds)) } ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(region, _), bounds, .. - }) => b(|cx, fv| check_for_block(cx, fv, bounds, region)), + }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)), ty::ty_bare_fn(_) => { b(check_for_bare) @@ -377,13 +378,6 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { expression_type); match e.node { - ExprBox(ref loc, ref interior) => { - let def = ty::resolve_expr(cx.tcx, &**loc); - if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() { - let interior_type = ty::expr_ty(cx.tcx, &**interior); - let _ = check_static(cx.tcx, interior_type, interior.span); - } - } ExprCast(ref source, _) => { let source_ty = ty::expr_ty(cx.tcx, &**source); let target_ty = ty::expr_ty(cx.tcx, e); @@ -562,7 +556,6 @@ fn check_trait_cast(cx: &mut Context, target_ty: ty::t, span: Span, method_call: MethodCall) { - check_cast_for_escaping_regions(cx, source_ty, target_ty, span); match ty::get(target_ty).sty { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => { match ty::get(ty).sty { @@ -580,7 +573,8 @@ fn check_trait_cast(cx: &mut Context, vtable_res) } }; - check_trait_cast_bounds(cx, span, source_ty, bounds); + check_trait_cast_bounds(cx, span, source_ty, + bounds.builtin_bounds); } _ => {} } @@ -620,7 +614,7 @@ pub fn check_builtin_bounds(cx: &Context, let kind = ty::type_contents(cx.tcx, ty); let mut missing = ty::empty_builtin_bounds(); for bound in bounds.iter() { - if !kind.meets_bound(cx.tcx, bound) { + if !kind.meets_builtin_bound(cx.tcx, bound) { missing.add(bound); } } @@ -764,132 +758,6 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) { } } -pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool { - if !ty::type_is_static(tcx, ty) { - match ty::get(ty).sty { - ty::ty_param(..) => { - span_err!(tcx.sess, sp, E0149, - "value may contain references; \ - add `'static` bound to `{}`", - ty_to_string(tcx, ty)); - } - _ => { - span_err!(tcx.sess, sp, E0150, - "value may contain references"); - } - } - false - } else { - true - } -} - -/// This is rather subtle. When we are casting a value to an instantiated -/// trait like `a as trait<'r>`, regionck already ensures that any references -/// that appear in the type of `a` are bounded by `'r` (ed.: rem -/// FIXME(#5723)). However, it is possible that there are *type parameters* -/// in the type of `a`, and those *type parameters* may have references -/// within them. We have to guarantee that the regions which appear in those -/// type parameters are not obscured. -/// -/// Therefore, we ensure that one of three conditions holds: -/// -/// (1) The trait instance cannot escape the current fn. This is -/// guaranteed if the region bound `&r` is some scope within the fn -/// itself. This case is safe because whatever references are -/// found within the type parameter, they must enclose the fn body -/// itself. -/// -/// (2) The type parameter appears in the type of the trait. For -/// example, if the type parameter is `T` and the trait type is -/// `deque`, then whatever references may appear in `T` also -/// appear in `deque`. -/// -/// (3) The type parameter is sendable (and therefore does not contain -/// references). -/// -/// FIXME(#5723)---This code should probably move into regionck. -pub fn check_cast_for_escaping_regions( - cx: &Context, - source_ty: ty::t, - target_ty: ty::t, - source_span: Span) -{ - // Determine what type we are casting to; if it is not a trait, then no - // worries. - if !ty::type_is_trait(target_ty) { - return; - } - - // Collect up the regions that appear in the target type. We want to - // ensure that these lifetimes are shorter than all lifetimes that are in - // the source type. See test `src/test/compile-fail/regions-trait-2.rs` - let mut target_regions = Vec::new(); - ty::walk_regions_and_ty( - cx.tcx, - target_ty, - |r| { - if !r.is_bound() { - target_regions.push(r); - } - }, - |_| ()); - - // Check, based on the region associated with the trait, whether it can - // possibly escape the enclosing fn item (note that all type parameters - // must have been declared on the enclosing fn item). - if target_regions.iter().any(|r| is_ReScope(*r)) { - return; /* case (1) */ - } - - // Assuming the trait instance can escape, then ensure that each parameter - // either appears in the trait type or is sendable. - let target_params = ty::param_tys_in_type(target_ty); - ty::walk_regions_and_ty( - cx.tcx, - source_ty, - - |_r| { - // FIXME(#5723) --- turn this check on once &Objects are usable - // - // if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) { - // cx.tcx.sess.span_err( - // source_span, - // format!("source contains reference with lifetime \ - // not found in the target type `{}`", - // ty_to_string(cx.tcx, target_ty))); - // note_and_explain_region( - // cx.tcx, "source data is only valid for ", r, ""); - // } - }, - - |ty| { - match ty::get(ty).sty { - ty::ty_param(source_param) => { - if source_param.space == subst::SelfSpace { - // FIXME (#5723) -- there is no reason that - // Self should be exempt from this check, - // except for historical accident. Bottom - // line, we need proper region bounding. - } else if target_params.iter().any(|x| x == &source_param) { - /* case (2) */ - } else { - check_static(cx.tcx, ty, source_span); /* case (3) */ - } - } - _ => {} - } - }); - - #[allow(non_snake_case_functions)] - fn is_ReScope(r: ty::Region) -> bool { - match r { - ty::ReScope(..) => true, - _ => false - } - } -} - // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound). fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) { if !ty::type_is_sized(tcx, ty) { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2d052feb672..662b55ba361 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -240,10 +240,16 @@ impl ast_node for ast::Pat { fn span(&self) -> Span { self.span } } +#[cfg(stage0)] pub struct MemCategorizationContext<'t,TYPER> { typer: &'t TYPER } +#[cfg(not(stage0))] +pub struct MemCategorizationContext<'t,TYPER:'t> { + typer: &'t TYPER +} + pub type McResult = Result; /** diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 61e6debb086..42d6cee9654 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -1221,8 +1221,8 @@ struct VisiblePrivateTypesVisitor<'a> { public_items: &'a PublicItems, } -struct CheckTypeForPrivatenessVisitor<'a, 'b> { - inner: &'b VisiblePrivateTypesVisitor<'a>, +struct CheckTypeForPrivatenessVisitor<'a, 'b:'a> { + inner: &'a VisiblePrivateTypesVisitor<'b>, /// whether the type refers to private types. contains_private: bool, /// whether we've recurred at all (i.e. if we're pointing at the diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 1a884eaea21..11dd3eee88e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -25,6 +25,7 @@ use driver::session::Session; use middle::ty::{FreeRegion}; use middle::ty; use util::nodemap::NodeMap; +use util::common::can_reach; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; @@ -78,7 +79,7 @@ The region maps encode information about region relationships. pub struct RegionMaps { scope_map: RefCell>, var_map: RefCell>, - free_region_map: RefCell >>, + free_region_map: RefCell>>, rvalue_scopes: RefCell>, terminating_scopes: RefCell>, } @@ -255,34 +256,7 @@ impl RegionMaps { * (that is, the user can give two different names to the same lifetime). */ - if sub == sup { - return true; - } - - // Do a little breadth-first-search here. The `queue` list - // doubles as a way to detect if we've seen a particular FR - // before. Note that we expect this graph to be an *extremely - // shallow* tree. - let mut queue = vec!(sub); - let mut i = 0; - while i < queue.len() { - match self.free_region_map.borrow().find(queue.get(i)) { - Some(parents) => { - for parent in parents.iter() { - if *parent == sup { - return true; - } - - if !queue.iter().any(|x| x == parent) { - queue.push(*parent); - } - } - } - None => {} - } - i += 1; - } - return false; + can_reach(&*self.free_region_map.borrow(), sub, sup) } pub fn is_subregion_of(&self, @@ -300,6 +274,7 @@ impl RegionMaps { sub_region == super_region || { match (sub_region, super_region) { + (ty::ReEmpty, _) | (_, ty::ReStatic) => { true } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index bd779b865d6..58be2c73bd9 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -30,10 +30,10 @@ use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod}; use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct}; use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method}; use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId}; -use syntax::ast::{OtherRegionTyParamBound, P, Pat, PatEnum, PatIdent, PatLit}; +use syntax::ast::{P, Pat, PatEnum, PatIdent, PatLit}; use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod}; use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic}; -use syntax::ast::{StaticRegionTyParamBound, StmtDecl, StructField}; +use syntax::ast::{RegionTyParamBound, StmtDecl, StructField}; use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound}; use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32}; use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt}; @@ -901,7 +901,7 @@ struct Resolver<'a> { used_imports: HashSet<(NodeId, Namespace)>, } -struct BuildReducedGraphVisitor<'a, 'b> { +struct BuildReducedGraphVisitor<'a, 'b:'a> { resolver: &'a mut Resolver<'b>, } @@ -933,7 +933,9 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } -struct UnusedImportCheckVisitor<'a, 'b> { resolver: &'a mut Resolver<'b> } +struct UnusedImportCheckVisitor<'a, 'b:'a> { + resolver: &'a mut Resolver<'b> +} impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> { fn visit_view_item(&mut self, vi: &ViewItem, _: ()) { @@ -3946,7 +3948,7 @@ impl<'a> Resolver<'a> { impl_items.as_slice()); } - ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { + ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => { // Create a new rib for the self type. let self_type_rib = Rib::new(ItemRibKind); @@ -3965,10 +3967,9 @@ impl<'a> Resolver<'a> { this.resolve_type_parameters(&generics.ty_params); this.resolve_where_clause(&generics.where_clause); - // Resolve derived traits. - for trt in traits.iter() { - this.resolve_trait_reference(item.id, trt, TraitDerivation); - } + this.resolve_type_parameter_bounds(item.id, bounds, + TraitDerivation); + match unbound { &Some(ast::TraitTyParamBound(ref tpb)) => { this.resolve_trait_reference(item.id, tpb, TraitDerivation); @@ -4199,10 +4200,13 @@ impl<'a> Resolver<'a> { type_parameters: &OwnedSlice) { for type_parameter in type_parameters.iter() { for bound in type_parameter.bounds.iter() { - self.resolve_type_parameter_bound(type_parameter.id, bound); + self.resolve_type_parameter_bound(type_parameter.id, bound, + TraitBoundingTypeParameter); } match &type_parameter.unbound { - &Some(ref unbound) => self.resolve_type_parameter_bound(type_parameter.id, unbound), + &Some(ref unbound) => + self.resolve_type_parameter_bound( + type_parameter.id, unbound, TraitBoundingTypeParameter), &None => {} } match type_parameter.default { @@ -4212,12 +4216,23 @@ impl<'a> Resolver<'a> { } } + fn resolve_type_parameter_bounds(&mut self, + id: NodeId, + type_parameter_bounds: &OwnedSlice, + reference_type: TraitReferenceType) { + for type_parameter_bound in type_parameter_bounds.iter() { + self.resolve_type_parameter_bound(id, type_parameter_bound, + reference_type); + } + } + fn resolve_type_parameter_bound(&mut self, id: NodeId, - type_parameter_bound: &TyParamBound) { + type_parameter_bound: &TyParamBound, + reference_type: TraitReferenceType) { match *type_parameter_bound { TraitTyParamBound(ref tref) => { - self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter) + self.resolve_trait_reference(id, tref, reference_type) } UnboxedFnTyParamBound(ref unboxed_function) => { for argument in unboxed_function.decl.inputs.iter() { @@ -4226,7 +4241,7 @@ impl<'a> Resolver<'a> { self.resolve_type(&*unboxed_function.decl.output); } - StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {} + RegionTyParamBound(..) => {} } } @@ -4240,7 +4255,7 @@ impl<'a> Resolver<'a> { let usage_str = match reference_type { TraitBoundingTypeParameter => "bound type parameter with", TraitImplementation => "implement", - TraitDerivation => "derive" + TraitDerivation => "derive", }; let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); @@ -4295,7 +4310,8 @@ impl<'a> Resolver<'a> { } for bound in predicate.bounds.iter() { - self.resolve_type_parameter_bound(predicate.id, bound); + self.resolve_type_parameter_bound(predicate.id, bound, + TraitBoundingTypeParameter); } } } @@ -4679,18 +4695,14 @@ impl<'a> Resolver<'a> { } bounds.as_ref().map(|bound_vec| { - for bound in bound_vec.iter() { - self.resolve_type_parameter_bound(ty.id, bound); - } + self.resolve_type_parameter_bounds(ty.id, bound_vec, + TraitBoundingTypeParameter); }); } - TyClosure(c, _) | TyProc(c) => { - c.bounds.as_ref().map(|bounds| { - for bound in bounds.iter() { - self.resolve_type_parameter_bound(ty.id, bound); - } - }); + TyClosure(c) | TyProc(c) => { + self.resolve_type_parameter_bounds(ty.id, &c.bounds, + TraitBoundingTypeParameter); visit::walk_ty(self, ty, ()); } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index abb67a6503e..1bc37e2f1e4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -21,7 +21,6 @@ use driver::session::Session; use middle::subst; use syntax::ast; use syntax::codemap::Span; -use syntax::owned_slice::OwnedSlice; use syntax::parse::token::special_idents; use syntax::parse::token; use syntax::print::pprust::{lifetime_to_string}; @@ -99,8 +98,10 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { ast::ItemStruct(_, ref generics) | ast::ItemImpl(ref generics, _, _, _) | ast::ItemTrait(ref generics, _, _, _) => { - self.check_lifetime_names(&generics.lifetimes); - EarlyScope(subst::TypeSpace, &generics.lifetimes, &root) + let scope: ScopeChain = + EarlyScope(subst::TypeSpace, &generics.lifetimes, &root); + self.check_lifetime_defs(&generics.lifetimes, &scope); + scope } }; debug!("entering scope {:?}", scope); @@ -126,7 +127,7 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) { match ty.node { - ast::TyClosure(c, _) | ast::TyProc(c) => { + ast::TyClosure(c) | ast::TyProc(c) => { push_fn_scope(self, ty, scope, &c.lifetimes); } ast::TyBareFn(c) => push_fn_scope(self, ty, scope, &c.lifetimes), @@ -137,8 +138,8 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { ty: &ast::Ty, scope: Scope, lifetimes: &Vec) { - let scope1 = LateScope(ty.id, lifetimes, scope); - this.check_lifetime_names(lifetimes); + let scope1: ScopeChain = LateScope(ty.id, lifetimes, scope); + this.check_lifetime_defs(lifetimes, &scope1); debug!("pushing fn scope id={} due to type", ty.id); visit::walk_ty(this, ty, &scope1); debug!("popping fn scope id={} due to type", ty.id); @@ -204,24 +205,22 @@ impl<'a> LifetimeContext<'a> { * the ordering is not important there. */ - self.check_lifetime_names(&generics.lifetimes); - - let referenced_idents = free_lifetimes(&generics.ty_params, - &generics.where_clause); + let referenced_idents = early_bound_lifetime_names(generics); debug!("pushing fn scope id={} due to fn item/method\ referenced_idents={:?}", n, referenced_idents.iter().map(lifetime_show).collect::>()); if referenced_idents.is_empty() { - let scope1 = LateScope(n, &generics.lifetimes, scope); - walk(self, &scope1) + let scope1: ScopeChain = LateScope(n, &generics.lifetimes, scope); + self.check_lifetime_defs(&generics.lifetimes, &scope1); + walk(self, &scope1); } else { let (early, late) = generics.lifetimes.clone().partition( |l| referenced_idents.iter().any(|&i| i == l.lifetime.name)); let scope1 = EarlyScope(subst::FnSpace, &early, scope); - let scope2 = LateScope(n, &late, &scope1); - + let scope2: ScopeChain = LateScope(n, &late, &scope1); + self.check_lifetime_defs(&generics.lifetimes, &scope2); walk(self, &scope2); } debug!("popping fn scope id={} due to fn item/method", n); @@ -335,7 +334,9 @@ impl<'a> LifetimeContext<'a> { token::get_name(lifetime_ref.name)).as_slice()); } - fn check_lifetime_names(&self, lifetimes: &Vec) { + fn check_lifetime_defs<'b>(&mut self, + lifetimes: &Vec, + scope: Scope<'b>) { for i in range(0, lifetimes.len()) { let lifetime_i = lifetimes.get(i); @@ -364,11 +365,7 @@ impl<'a> LifetimeContext<'a> { } for bound in lifetime_i.bounds.iter() { - if !self.sess.features.issue_5723_bootstrap.get() { - self.sess.span_err( - bound.span, - "region bounds require `issue_5723_bootstrap`"); - } + self.resolve_lifetime_ref(bound, scope); } } } @@ -404,8 +401,7 @@ fn search_lifetimes(lifetimes: &Vec, /////////////////////////////////////////////////////////////////////////// pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec { - let referenced_idents = free_lifetimes(&generics.ty_params, - &generics.where_clause); + let referenced_idents = early_bound_lifetime_names(generics); if referenced_idents.is_empty() { return Vec::new(); } @@ -416,34 +412,72 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec, - where_clause: &ast::WhereClause) - -> Vec { +fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec { /*! - * Gathers up and returns the names of any lifetimes that appear - * free in `ty_params`. Of course, right now, all lifetimes appear - * free, since we don't currently have any binders in type parameter - * declarations; just being forwards compatible with future extensions. + * Given a set of generic declarations, returns a list of names + * containing all early bound lifetime names for those + * generics. (In fact, this list may also contain other names.) */ - let mut collector = FreeLifetimeCollector { names: vec!() }; - for ty_param in ty_params.iter() { - visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ()); - } - for predicate in where_clause.predicates.iter() { - visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ()); - } - return collector.names; + // Create two lists, dividing the lifetimes into early/late bound. + // Initially, all of them are considered late, but we will move + // things from late into early as we go if we find references to + // them. + let mut early_bound = Vec::new(); + let mut late_bound = generics.lifetimes.iter() + .map(|l| l.lifetime.name) + .collect(); - struct FreeLifetimeCollector { - names: Vec, + // Any lifetime that appears in a type bound is early. + { + let mut collector = + FreeLifetimeCollector { early_bound: &mut early_bound, + late_bound: &mut late_bound }; + for ty_param in generics.ty_params.iter() { + visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ()); + } + for predicate in generics.where_clause.predicates.iter() { + visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ()); + } } - impl Visitor<()> for FreeLifetimeCollector { + // Any lifetime that either has a bound or is referenced by a + // bound is early. + for lifetime_def in generics.lifetimes.iter() { + if !lifetime_def.bounds.is_empty() { + shuffle(&mut early_bound, &mut late_bound, + lifetime_def.lifetime.name); + for bound in lifetime_def.bounds.iter() { + shuffle(&mut early_bound, &mut late_bound, + bound.name); + } + } + } + return early_bound; + + struct FreeLifetimeCollector<'a> { + early_bound: &'a mut Vec, + late_bound: &'a mut Vec, + } + + impl<'a> Visitor<()> for FreeLifetimeCollector<'a> { fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime, _: ()) { - self.names.push(lifetime_ref.name); + shuffle(self.early_bound, self.late_bound, + lifetime_ref.name); + } + } + + fn shuffle(early_bound: &mut Vec, + late_bound: &mut Vec, + name: ast::Name) { + match late_bound.iter().position(|n| *n == name) { + Some(index) => { + late_bound.swap_remove(index); + early_bound.push(name); + } + None => { } } } } diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 11b16f18533..cd3f47e8b2f 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -50,6 +50,7 @@ use syntax::attr; use syntax::codemap::*; use syntax::parse::token; use syntax::parse::token::{get_ident,keywords}; +use syntax::owned_slice::OwnedSlice; use syntax::visit; use syntax::visit::Visitor; use syntax::print::pprust::{path_to_string,ty_to_string}; @@ -653,7 +654,7 @@ impl <'l> DxrVisitor<'l> { item: &ast::Item, e: DxrVisitorEnv, generics: &ast::Generics, - trait_refs: &Vec, + trait_refs: &OwnedSlice, methods: &Vec) { let qualname = self.analysis.ty_cx.map.path_to_string(item.id); @@ -665,7 +666,16 @@ impl <'l> DxrVisitor<'l> { e.cur_scope); // super-traits - for trait_ref in trait_refs.iter() { + for super_bound in trait_refs.iter() { + let trait_ref = match *super_bound { + ast::TraitTyParamBound(ref trait_ref) => { + trait_ref + } + ast::UnboxedFnTyParamBound(..) | ast::RegionTyParamBound(..) => { + continue; + } + }; + match self.lookup_type_ref(trait_ref.ref_id) { Some(id) => { let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); @@ -1499,7 +1509,7 @@ pub fn process_crate(sess: &Session, collected_paths: vec!(), collecting: false, fmt: FmtStrs::new(box Recorder { - out: output_file as Box, + out: output_file as Box, dump_spans: false, }, SpanUtils { diff --git a/src/librustc/middle/save/recorder.rs b/src/librustc/middle/save/recorder.rs index 1af6fde02af..0695b6b360c 100644 --- a/src/librustc/middle/save/recorder.rs +++ b/src/librustc/middle/save/recorder.rs @@ -19,7 +19,7 @@ use syntax::codemap::*; pub struct Recorder { // output file - pub out: Box, + pub out: Box, pub dump_spans: bool, } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index ccc4dbb21e0..d992e840b46 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -611,7 +611,7 @@ impl<'a> TypeFolder for SubstFolder<'a> { let t1 = match ty::get(t).sty { ty::ty_param(p) => { - check(self, t, self.substs.types.opt_get(p.space, p.idx)) + check(self, p, t, self.substs.types.opt_get(p.space, p.idx)) } _ => { ty_fold::super_fold_ty(self, t) @@ -627,6 +627,7 @@ impl<'a> TypeFolder for SubstFolder<'a> { return t1; fn check(this: &SubstFolder, + p: ty::ParamTy, source_ty: ty::t, opt_ty: Option<&ty::t>) -> ty::t { @@ -636,8 +637,9 @@ impl<'a> TypeFolder for SubstFolder<'a> { let span = this.span.unwrap_or(DUMMY_SP); this.tcx().sess.span_bug( span, - format!("Type parameter {} out of range \ + format!("Type parameter `{}` ({}) out of range \ when substituting (root type={})", + p.repr(this.tcx()), source_ty.repr(this.tcx()), this.root_ty.repr(this.tcx())).as_slice()); } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 28f396c8bf7..bbd6c252849 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -340,6 +340,15 @@ struct ArmData<'a, 'b> { * As we proceed `bound_ptrs` are filled with pointers to values to be bound, * these pointers are stored in llmatch variables just before executing `data` arm. */ +#[cfg(not(stage0))] +struct Match<'a, 'b:'a> { + pats: Vec>, + data: &'a ArmData<'a, 'b>, + bound_ptrs: Vec<(Ident, ValueRef)> +} + +///Dox +#[cfg(stage0)] struct Match<'a, 'b> { pats: Vec>, data: &'a ArmData<'a, 'b>, diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs index cf2410f6571..b36887c80e9 100644 --- a/src/librustc/middle/trans/cleanup.rs +++ b/src/librustc/middle/trans/cleanup.rs @@ -25,7 +25,6 @@ use middle::ty; use syntax::ast; use util::ppaux::Repr; - pub struct CleanupScope<'a> { // The id of this cleanup scope. If the id is None, // this is a *temporary scope* that is pushed during trans to @@ -35,7 +34,7 @@ pub struct CleanupScope<'a> { kind: CleanupScopeKind<'a>, // Cleanups to run upon scope exit. - cleanups: Vec>, + cleanups: Vec, cached_early_exits: Vec, cached_landing_pad: Option, @@ -73,6 +72,8 @@ pub trait Cleanup { fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>; } +pub type CleanupObj = Box; + pub enum ScopeId { AstScope(ast::NodeId), CustomScope(CustomScopeIndex) @@ -238,7 +239,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { cleanup_scope, self.ccx.tn.val_to_string(val)); - self.schedule_clean(cleanup_scope, drop as Box); + self.schedule_clean(cleanup_scope, drop as CleanupObj); } fn schedule_drop_mem(&self, @@ -264,7 +265,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { self.ccx.tn.val_to_string(val), ty.repr(self.ccx.tcx())); - self.schedule_clean(cleanup_scope, drop as Box); + self.schedule_clean(cleanup_scope, drop as CleanupObj); } fn schedule_drop_and_zero_mem(&self, @@ -291,7 +292,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { ty.repr(self.ccx.tcx()), true); - self.schedule_clean(cleanup_scope, drop as Box); + self.schedule_clean(cleanup_scope, drop as CleanupObj); } fn schedule_drop_immediate(&self, @@ -316,7 +317,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { self.ccx.tn.val_to_string(val), ty.repr(self.ccx.tcx())); - self.schedule_clean(cleanup_scope, drop as Box); + self.schedule_clean(cleanup_scope, drop as CleanupObj); } fn schedule_free_value(&self, @@ -336,12 +337,12 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { self.ccx.tn.val_to_string(val), heap); - self.schedule_clean(cleanup_scope, drop as Box); + self.schedule_clean(cleanup_scope, drop as CleanupObj); } fn schedule_clean(&self, cleanup_scope: ScopeId, - cleanup: Box) { + cleanup: CleanupObj) { match cleanup_scope { AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup), CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup), @@ -350,7 +351,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { fn schedule_clean_in_ast_scope(&self, cleanup_scope: ast::NodeId, - cleanup: Box) { + cleanup: CleanupObj) { /*! * Schedules a cleanup to occur upon exit from `cleanup_scope`. * If `cleanup_scope` is not provided, then the cleanup is scheduled @@ -378,7 +379,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { fn schedule_clean_in_custom_scope(&self, custom_scope: CustomScopeIndex, - cleanup: Box) { + cleanup: CleanupObj) { /*! * Schedules a cleanup to occur in the top-most scope, * which must be a temporary scope. @@ -1021,13 +1022,13 @@ pub trait CleanupMethods<'a> { content_ty: ty::t); fn schedule_clean(&self, cleanup_scope: ScopeId, - cleanup: Box); + cleanup: CleanupObj); fn schedule_clean_in_ast_scope(&self, cleanup_scope: ast::NodeId, - cleanup: Box); + cleanup: CleanupObj); fn schedule_clean_in_custom_scope(&self, custom_scope: CustomScopeIndex, - cleanup: Box); + cleanup: CleanupObj); fn needs_invoke(&self) -> bool; fn get_landing_pad(&'a self) -> BasicBlockRef; } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 566f71220b0..26973910400 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -498,9 +498,8 @@ impl TypeMap { unique_type_id.push_char(':'); - for bound in bounds.iter() { + for bound in bounds.builtin_bounds.iter() { match bound { - ty::BoundStatic => unique_type_id.push_str("'static"), ty::BoundSend => unique_type_id.push_str("Send"), ty::BoundSized => unique_type_id.push_str("Sized"), ty::BoundCopy => unique_type_id.push_str("Copy"), diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 56841cd4044..24c939dc3be 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -35,7 +35,7 @@ use middle::trans::tvec; use middle::trans::type_::Type; use middle::trans::type_of::{type_of, sizing_type_of, align_of}; use middle::ty; -use util::ppaux::ty_to_short_str; +use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; use arena::TypedArena; @@ -131,6 +131,7 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) -> &'a Block<'a> { // NB: v is an *alias* of type t here, not a direct value. + debug!("drop_ty(t={})", t.repr(bcx.tcx())); let _icx = push_ctxt("drop_ty"); if ty::type_needs_drop(bcx.tcx(), t) { let ccx = bcx.ccx(); @@ -213,6 +214,7 @@ fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) let _icx = push_ctxt("make_visit_glue"); let mut bcx = bcx; let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(), + ty::ReStatic, ty::ReStatic) { Ok(pair) => pair, Err(s) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2d3096d13ea..c2d0d27be6d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -273,7 +273,7 @@ pub enum UnsizeKind { // An unsize coercion applied to the tail field of a struct. // The uint is the index of the type parameter which is unsized. UnsizeStruct(Box, uint), - UnsizeVtable(ty::BuiltinBounds, + UnsizeVtable(ty::ExistentialBounds, ast::DefId, /* Trait ID */ subst::Substs /* Trait substitutions */) } @@ -464,7 +464,6 @@ pub struct ctxt { pub lang_items: middle::lang_items::LanguageItems, /// A mapping of fake provided method def_ids to the default implementation pub provided_method_sources: RefCell>, - pub supertraits: RefCell>>>>, pub superstructs: RefCell>>, pub struct_fields: RefCell>>>, @@ -620,7 +619,7 @@ pub struct ClosureTy { pub fn_style: ast::FnStyle, pub onceness: ast::Onceness, pub store: TraitStore, - pub bounds: BuiltinBounds, + pub bounds: ExistentialBounds, pub sig: FnSig, pub abi: abi::Abi, } @@ -932,7 +931,7 @@ pub enum sty { pub struct TyTrait { pub def_id: DefId, pub substs: Substs, - pub bounds: BuiltinBounds + pub bounds: ExistentialBounds } #[deriving(PartialEq, Eq, Hash, Show)] @@ -995,18 +994,30 @@ pub enum type_err { terr_variadic_mismatch(expected_found) } -#[deriving(PartialEq, Eq, Hash, Show)] +/// Bounds suitable for a named type parameter like `A` in `fn foo` +/// as well as the existential type parameter in an object type. +#[deriving(PartialEq, Eq, Hash, Clone, Show)] pub struct ParamBounds { + pub opt_region_bound: Option, pub builtin_bounds: BuiltinBounds, pub trait_bounds: Vec> } +/// 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; #[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)] #[repr(uint)] pub enum BuiltinBound { - BoundStatic, BoundSend, BoundSized, BoundCopy, @@ -1019,13 +1030,21 @@ pub fn empty_builtin_bounds() -> BuiltinBounds { pub fn all_builtin_bounds() -> BuiltinBounds { let mut set = EnumSet::empty(); - set.add(BoundStatic); set.add(BoundSend); set.add(BoundSized); set.add(BoundSync); set } +pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds { + /*! + * An existential bound that does not implement any traits. + */ + + ty::ExistentialBounds { region_bound: r, + builtin_bounds: empty_builtin_bounds() } +} + impl CLike for BuiltinBound { fn to_uint(&self) -> uint { *self as uint @@ -1141,8 +1160,8 @@ pub struct TypeParameterDef { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: uint, - pub bounds: Rc, - pub default: Option + pub bounds: ParamBounds, + pub default: Option, } #[deriving(Encodable, Decodable, Clone, Show)] @@ -1151,6 +1170,7 @@ pub struct RegionParameterDef { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: uint, + pub bounds: Vec, } /// Information about the type/lifetime parameters associated with an @@ -1198,6 +1218,12 @@ pub struct ParameterEnvironment { /// Bounds on the various type parameters pub bounds: VecPerParamSpace, + + /// Each type parameter has an implicit region bound that + /// indicates it must outlive at least the function body (the user + /// may specify stronger requirements). This field indicates the + /// region of the callee. + pub implicit_region_bound: ty::Region, } impl ParameterEnvironment { @@ -1292,7 +1318,7 @@ pub struct Polytype { /// As `Polytype` but for a trait ref. pub struct TraitDef { pub generics: Generics, - pub bounds: BuiltinBounds, + pub bounds: ParamBounds, pub trait_ref: Rc, } @@ -1382,7 +1408,6 @@ pub fn mk_ctxt(s: Session, normalized_cache: RefCell::new(HashMap::new()), lang_items: lang_items, provided_method_sources: RefCell::new(DefIdMap::new()), - supertraits: RefCell::new(DefIdMap::new()), superstructs: RefCell::new(DefIdMap::new()), struct_fields: RefCell::new(DefIdMap::new()), destructor_for_type: RefCell::new(DefIdMap::new()), @@ -1459,6 +1484,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } return f; } + fn flags_for_bounds(bounds: &ExistentialBounds) -> uint { + rflags(bounds.region_bound) + } match &st { &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) | &ty_str => {} @@ -1483,8 +1511,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags |= sflags(substs); } - &ty_trait(box ty::TyTrait { ref substs, .. }) => { + &ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => { flags |= sflags(substs); + flags |= flags_for_bounds(bounds); } &ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => { flags |= get(tt).flags @@ -1514,6 +1543,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { flags |= get(f.sig.output).flags; // T -> _|_ is *not* _|_ ! flags &= !(has_ty_bot as uint); + flags |= flags_for_bounds(&f.bounds); } } @@ -1711,8 +1741,8 @@ pub fn mk_ctor_fn(cx: &ctxt, pub fn mk_trait(cx: &ctxt, did: ast::DefId, substs: Substs, - bounds: BuiltinBounds) - -> t { + bounds: ExistentialBounds) + -> t { // take a copy of substs so that we own the vectors inside let inner = box TyTrait { def_id: did, @@ -1800,6 +1830,27 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|) |t| { fldt(t); t }).fold_ty(ty) } +impl ParamTy { + pub fn new(space: subst::ParamSpace, + index: uint, + def_id: ast::DefId) + -> ParamTy { + ParamTy { space: space, idx: index, def_id: def_id } + } + + pub fn for_self(trait_def_id: ast::DefId) -> ParamTy { + ParamTy::new(subst::SelfSpace, 0, trait_def_id) + } + + pub fn for_def(def: &TypeParameterDef) -> ParamTy { + ParamTy::new(def.space, def.index, def.def_id) + } + + pub fn to_ty(self, tcx: &ty::ctxt) -> ty::t { + ty::mk_param(tcx, self.space, self.idx, self.def_id) + } +} + impl ItemSubsts { pub fn empty() -> ItemSubsts { ItemSubsts { substs: Substs::empty() } @@ -2115,9 +2166,6 @@ def_type_content_sets!( // that it neither reaches nor owns a managed pointer. Nonsendable = 0b0000_0111__0000_0100__0000, - // Things that prevent values from being considered 'static - Nonstatic = 0b0000_0010__0000_0000__0000, - // Things that prevent values from being considered sized Nonsized = 0b0000_0000__0000_0000__0001, @@ -2142,9 +2190,8 @@ def_type_content_sets!( ) impl TypeContents { - pub fn meets_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool { + pub fn meets_builtin_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool { match bb { - BoundStatic => self.is_static(cx), BoundSend => self.is_sendable(cx), BoundSized => self.is_sized(cx), BoundCopy => self.is_copy(cx), @@ -2160,10 +2207,6 @@ impl TypeContents { (self.bits & tc.bits) != 0 } - pub fn is_static(&self, _: &ctxt) -> bool { - !self.intersects(TC::Nonstatic) - } - pub fn is_sendable(&self, _: &ctxt) -> bool { !self.intersects(TC::Nonsendable) } @@ -2272,10 +2315,6 @@ impl fmt::Show for TypeContents { } } -pub fn type_is_static(cx: &ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_static(cx) -} - pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool { type_contents(cx, t).is_sendable(cx) } @@ -2482,10 +2521,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { let ty_param_defs = cx.ty_param_defs.borrow(); let tp_def = ty_param_defs.get(&p.def_id.node); - kind_bounds_to_contents(cx, - tp_def.bounds.builtin_bounds, - tp_def.bounds.trait_bounds.as_slice()) - } + kind_bounds_to_contents( + cx, + tp_def.bounds.builtin_bounds, + tp_def.bounds.trait_bounds.as_slice()) + } ty_infer(_) => { // This occurs during coherence, but shouldn't occur at other @@ -2577,10 +2617,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } fn object_contents(cx: &ctxt, - bounds: BuiltinBounds) + bounds: ExistentialBounds) -> TypeContents { // These are the type contents of the (opaque) interior - kind_bounds_to_contents(cx, bounds, []) + kind_bounds_to_contents(cx, bounds.builtin_bounds, []) } fn kind_bounds_to_contents(cx: &ctxt, @@ -2591,7 +2631,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { let mut tc = TC::All; each_inherited_builtin_bound(cx, bounds, traits, |bound| { tc = tc - match bound { - BoundStatic => TC::Nonstatic, BoundSend => TC::Nonsendable, BoundSized => TC::Nonsized, BoundCopy => TC::Noncopy, @@ -2612,7 +2651,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { each_bound_trait_and_supertraits(cx, traits, |trait_ref| { let trait_def = lookup_trait_def(cx, trait_ref.def_id); - for bound in trait_def.bounds.iter() { + for bound in trait_def.bounds.builtin_bounds.iter() { f(bound); } true @@ -3272,16 +3311,19 @@ pub fn adjust_ty(cx: &ctxt, AutoAddEnv(store) => { match ty::get(unadjusted_ty).sty { ty::ty_bare_fn(ref b) => { + let bounds = ty::ExistentialBounds { + region_bound: ReStatic, + builtin_bounds: all_builtin_bounds(), + }; + ty::mk_closure( cx, - ty::ClosureTy { - fn_style: b.fn_style, - onceness: ast::Many, - store: store, - bounds: ty::all_builtin_bounds(), - sig: b.sig.clone(), - abi: b.abi, - }) + ty::ClosureTy {fn_style: b.fn_style, + onceness: ast::Many, + store: store, + bounds: bounds, + sig: b.sig.clone(), + abi: b.abi}) } ref b => { cx.sess.bug( @@ -3920,30 +3962,6 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec> { } } -pub fn trait_supertraits(cx: &ctxt, id: ast::DefId) -> Rc>> { - // 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> { - 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( descr: &str, def_id: ast::DefId, @@ -4055,9 +4073,12 @@ pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId { def.def_id() } -pub fn try_add_builtin_trait(tcx: &ctxt, - trait_def_id: ast::DefId, - builtin_bounds: &mut BuiltinBounds) -> bool { +pub fn try_add_builtin_trait( + tcx: &ctxt, + trait_def_id: ast::DefId, + builtin_bounds: &mut EnumSet) + -> bool +{ //! Checks whether `trait_ref` refers to one of the builtin //! traits, like `Send`, and adds the corresponding //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` @@ -4343,6 +4364,18 @@ pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc { } } +/// Given a reference to a trait, returns the bounds declared on the +/// trait, with appropriate substitutions applied. +pub fn bounds_for_trait_ref(tcx: &ctxt, + trait_ref: &TraitRef) + -> ty::ParamBounds +{ + let trait_def = lookup_trait_def(tcx, trait_ref.def_id); + debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})", + trait_def.repr(tcx), trait_ref.repr(tcx)); + trait_def.bounds.subst(tcx, &trait_ref.substs) +} + /// Iterate over attributes of a definition. // (This should really be an iterator, but that would require csearch and // decoder to use iterators instead of higher-order functions.) @@ -4410,14 +4443,10 @@ pub fn lookup_field_type(tcx: &ctxt, node_id_to_type(tcx, id.node) } else { let mut tcache = tcx.tcache.borrow_mut(); - match tcache.find(&id) { - Some(&Polytype {ty, ..}) => ty, - None => { - let tpt = csearch::get_field_type(tcx, struct_id, id); - tcache.insert(id, tpt.clone()); - tpt.ty - } - } + let pty = tcache.find_or_insert_with(id, |_| { + csearch::get_field_type(tcx, struct_id, id) + }); + pty.ty }; t.subst(tcx, substs) } @@ -4745,9 +4774,10 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt, } // Add supertraits to supertrait_set - let supertrait_refs = trait_ref_supertraits(tcx, - &**trait_refs.get(i)); - for supertrait_ref in supertrait_refs.iter() { + let trait_ref = trait_refs.get(i).clone(); + let trait_def = lookup_trait_def(tcx, trait_ref.def_id); + for supertrait_ref in trait_def.bounds.trait_bounds.iter() { + let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs); debug!("each_bound_trait_and_supertraits(supertrait_ref={})", supertrait_ref.repr(tcx)); @@ -4765,6 +4795,61 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt, return true; } +pub fn required_region_bounds(tcx: &ctxt, + region_bounds: &[ty::Region], + builtin_bounds: BuiltinBounds, + trait_bounds: &[Rc]) + -> Vec +{ + /*! + * 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) { + 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 { tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| { tcx.intrinsic_defs.borrow().find_copy(&tydesc_lang_item) @@ -4780,7 +4865,10 @@ pub fn get_opaque_ty(tcx: &ctxt) -> Result { } pub fn visitor_object_ty(tcx: &ctxt, - region: ty::Region) -> Result<(Rc, t), String> { + ptr_region: ty::Region, + trait_region: ty::Region) + -> Result<(Rc, t), String> +{ let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) { Ok(id) => id, Err(s) => { return Err(s); } @@ -4788,11 +4876,12 @@ pub fn visitor_object_ty(tcx: &ctxt, let substs = Substs::empty(); let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs }); Ok((trait_ref.clone(), - mk_rptr(tcx, region, mt {mutbl: ast::MutMutable, - ty: mk_trait(tcx, - trait_ref.def_id, - trait_ref.substs.clone(), - empty_builtin_bounds()) }))) + mk_rptr(tcx, ptr_region, + mt {mutbl: ast::MutMutable, + ty: mk_trait(tcx, + trait_ref.def_id, + trait_ref.substs.clone(), + ty::region_existential_bound(trait_region))}))) } pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc { @@ -5184,6 +5273,18 @@ pub fn construct_parameter_environment( generics.types.get_slice(space)); } + // + // Compute region bounds. For now, these relations are stored in a + // global table on the tcx, so just enter them there. I'm not + // crazy about this scheme, but it's convenient, at least. + // + + for &space in subst::ParamSpace::all().iter() { + record_region_bounds_from_defs(tcx, space, &free_substs, + generics.regions.get_slice(space)); + } + + debug!("construct_parameter_environment: free_id={} \ free_subst={} \ bounds={}", @@ -5193,7 +5294,8 @@ pub fn construct_parameter_environment( return ty::ParameterEnvironment { free_substs: free_substs, - bounds: bounds + bounds: bounds, + implicit_region_bound: ty::ReScope(free_id), }; fn push_region_params(regions: &mut VecPerParamSpace, @@ -5222,10 +5324,41 @@ pub fn construct_parameter_environment( free_substs: &subst::Substs, defs: &[TypeParameterDef]) { for def in defs.iter() { - let b = (*def.bounds).subst(tcx, free_substs); + let b = def.bounds.subst(tcx, free_substs); bounds.push(space, b); } } + + fn record_region_bounds_from_defs(tcx: &ty::ctxt, + space: subst::ParamSpace, + free_substs: &subst::Substs, + defs: &[RegionParameterDef]) { + for (subst_region, def) in + free_substs.regions().get_slice(space).iter().zip( + defs.iter()) + { + // For each region parameter 'subst... + let bounds = def.bounds.subst(tcx, free_substs); + for bound_region in bounds.iter() { + // Which is declared with a bound like 'subst:'bound... + match (subst_region, bound_region) { + (&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => { + // Record that 'subst outlives 'bound. Or, put + // another way, 'bound <= 'subst. + tcx.region_maps.relate_free_regions(bound_fr, subst_fr); + }, + _ => { + // All named regions are instantiated with free regions. + tcx.sess.bug( + format!("push_region_bounds_from_defs: \ + non free region: {} / {}", + subst_region.repr(tcx), + bound_region.repr(tcx)).as_slice()); + } + } + } + } + } } impl BorrowKind { @@ -5346,4 +5479,3 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, } }) } - diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 2bfbc67bbeb..435c591f881 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -85,6 +85,11 @@ pub trait TypeFolder { super_fold_trait_store(self, s) } + fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds) + -> ty::ExistentialBounds { + super_fold_existential_bounds(self, s) + } + fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef { super_fold_autoref(self, ar) } @@ -236,9 +241,16 @@ impl TypeFoldable for ty::BuiltinBounds { } } +impl TypeFoldable for ty::ExistentialBounds { + fn fold_with(&self, folder: &mut F) -> ty::ExistentialBounds { + folder.fold_existential_bounds(*self) + } +} + impl TypeFoldable for ty::ParamBounds { fn fold_with(&self, folder: &mut F) -> ty::ParamBounds { ty::ParamBounds { + opt_region_bound: self.opt_region_bound.fold_with(folder), builtin_bounds: self.builtin_bounds.fold_with(folder), trait_bounds: self.trait_bounds.fold_with(folder), } @@ -259,8 +271,14 @@ impl TypeFoldable for ty::TypeParameterDef { } impl TypeFoldable for ty::RegionParameterDef { - fn fold_with(&self, _folder: &mut F) -> ty::RegionParameterDef { - *self + fn fold_with(&self, folder: &mut F) -> ty::RegionParameterDef { + ty::RegionParameterDef { + name: self.name, + def_id: self.def_id, + space: self.space, + index: self.index, + bounds: self.bounds.fold_with(folder) + } } } @@ -340,7 +358,7 @@ pub fn super_fold_closure_ty(this: &mut T, sig: fty.sig.fold_with(this), fn_style: fty.fn_style, onceness: fty.onceness, - bounds: fty.bounds, + bounds: fty.bounds.fold_with(this), abi: fty.abi, } } @@ -389,7 +407,7 @@ pub fn super_fold_sty(this: &mut T, ty::ty_trait(box ty::TyTrait { def_id: def_id, substs: substs.fold_with(this), - bounds: bounds + bounds: this.fold_existential_bounds(bounds), }) } ty::ty_tup(ref ts) => { @@ -430,6 +448,15 @@ pub fn super_fold_trait_store(this: &mut T, } } +pub fn super_fold_existential_bounds(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(this: &mut T, autoref: &ty::AutoRef) -> ty::AutoRef diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 08e78b35e4d..6cd61a8c3f8 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -57,19 +57,19 @@ use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty; -use middle::ty_fold::TypeFolder; -use middle::typeck::rscope::RegionScope; -use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope}; -use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope}; +use middle::typeck::lookup_def_tcx; +use middle::typeck::infer; +use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope}; +use middle::typeck::rscope; +use middle::typeck::TypeAndSubsts; use middle::typeck; -use util::ppaux::Repr; +use util::ppaux::{Repr, UserString}; +use std::collections::HashMap; use std::rc::Rc; use syntax::abi; use syntax::{ast, ast_util}; use syntax::codemap::Span; -use syntax::owned_slice::OwnedSlice; -use syntax::print::pprust::{lifetime_to_string, path_to_string}; pub trait AstConv { fn tcx<'a>(&'a self) -> &'a ty::ctxt; @@ -111,8 +111,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) }; debug!("ast_region_to_region(lifetime={} id={}) yields {}", - lifetime_to_string(lifetime), - lifetime.id, r.repr(tcx)); + lifetime.repr(tcx), + lifetime.id, + r.repr(tcx)); r } @@ -145,7 +146,7 @@ pub fn opt_ast_region_to_region( }; debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}", - opt_lifetime.as_ref().map(|e| lifetime_to_string(e)), + opt_lifetime.repr(this.tcx()), r.repr(this.tcx())); r @@ -284,11 +285,11 @@ pub fn ast_path_to_trait_ref( } pub fn ast_path_to_ty( - this: &AC, - rscope: &RS, - did: ast::DefId, - path: &ast::Path) - -> TypeAndSubsts + this: &AC, + rscope: &RS, + did: ast::DefId, + path: &ast::Path) + -> TypeAndSubsts { let tcx = this.tcx(); let ty::Polytype { @@ -370,7 +371,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option { None => { tcx.sess.span_bug(ast_ty.span, format!("unbound path {}", - path_to_string(path)).as_slice()) + path.repr(tcx)).as_slice()) } Some(&d) => d }; @@ -430,7 +431,7 @@ pub fn ast_ty_to_builtin_ty d }; @@ -520,6 +521,16 @@ enum PointerTy { Uniq } +impl PointerTy { + fn default_region(&self) -> ty::Region { + match *self { + Box => ty::ReStatic, + Uniq => ty::ReStatic, + RPtr(r) => r, + } + } +} + pub fn trait_ref_for_unboxed_function( this: &AC, @@ -589,10 +600,11 @@ fn mk_pointer { return ty::mk_uniq(this.tcx(), tr); @@ -612,7 +624,7 @@ fn mk_pointer { + ast::TyPath(ref path, ref opt_bounds, id) => { // Note that the "bounds must be empty if path is not a trait" // restriction is enforced in the below case for ty_path, which // will run after this as long as the path isn't a trait. @@ -636,14 +648,22 @@ fn mk_pointer { let result = ast_path_to_trait_ref( this, rscope, trait_def_id, None, path); - let static_region = match ptr_ty { - RPtr(r) if r == ty::ReStatic => true, - _ => false + let bounds = match *opt_bounds { + None => { + conv_existential_bounds(this, + rscope, + path.span, + [result.clone()].as_slice(), + [].as_slice()) + } + Some(ref bounds) => { + conv_existential_bounds(this, + rscope, + path.span, + [result.clone()].as_slice(), + bounds.as_slice()) + } }; - let bounds = conv_builtin_bounds(this.tcx(), - path.span, - bounds, - static_region); let tr = ty::mk_trait(tcx, result.def_id, result.substs.clone(), @@ -737,27 +757,22 @@ pub fn ast_ty_to_ty( ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style, bf.abi, &*bf.decl)) } - ast::TyClosure(ref f, ref region) => { - - // resolve the function bound region in the original region - // scope `rscope`, not the scope of the function parameters - let bound_region = opt_ast_region_to_region(this, rscope, - ast_ty.span, region); - + ast::TyClosure(ref f) => { // Use corresponding trait store to figure out default bounds // if none were specified. - let bounds = conv_builtin_bounds(this.tcx(), - ast_ty.span, - &f.bounds, - bound_region == ty::ReStatic); - - let store = ty::RegionTraitStore(bound_region, ast::MutMutable); + let bounds = conv_existential_bounds(this, + rscope, + ast_ty.span, + [].as_slice(), + f.bounds.as_slice()); let fn_decl = ty_of_closure(this, ast_ty.id, f.fn_style, f.onceness, bounds, - store, + ty::RegionTraitStore( + bounds.region_bound, + ast::MutMutable), &*f.decl, abi::Rust, None); @@ -766,10 +781,10 @@ pub fn ast_ty_to_ty( ast::TyProc(ref f) => { // Use corresponding trait store to figure out default bounds // if none were specified. - let bounds = conv_builtin_bounds(this.tcx(), - ast_ty.span, - &f.bounds, - false); + let bounds = conv_existential_bounds(this, rscope, + ast_ty.span, + [].as_slice(), + f.bounds.as_slice()); let fn_decl = ty_of_closure(this, ast_ty.id, @@ -780,6 +795,7 @@ pub fn ast_ty_to_ty( &*f.decl, abi::Rust, None); + ty::mk_closure(tcx, fn_decl) } ast::TyUnboxedFn(..) => { @@ -793,7 +809,7 @@ pub fn ast_ty_to_ty( tcx.sess .span_bug(ast_ty.span, format!("unbound path {}", - path_to_string(path)).as_slice()) + path.repr(tcx)).as_slice()) } Some(&d) => d }; @@ -808,16 +824,22 @@ pub fn ast_ty_to_ty( } match a_def { def::DefTrait(trait_def_id) => { - let result = ast_path_to_trait_ref( - this, rscope, trait_def_id, None, path); - let bounds = conv_builtin_bounds(this.tcx(), - path.span, - bounds, - false); - ty::mk_trait(tcx, - result.def_id, - result.substs.clone(), - bounds) + let result = ast_path_to_trait_ref( + this, rscope, trait_def_id, None, path); + let empty_bounds: &[ast::TyParamBound] = &[]; + let ast_bounds = match *bounds { + Some(ref b) => b.as_slice(), + None => empty_bounds + }; + let bounds = conv_existential_bounds(this, + rscope, + ast_ty.span, + &[result.clone()], + ast_bounds); + ty::mk_trait(tcx, + result.def_id, + result.substs.clone(), + bounds) } def::DefTy(did) | def::DefStruct(did) => { ast_path_to_ty(this, rscope, did, path).ty @@ -1022,9 +1044,7 @@ fn ty_of_method_or_bare_fn( _ => { match implied_output_region { Some(implied_output_region) => { - let rb = ImpliedSingleRscope { - region: implied_output_region, - }; + let rb = SpecificRscope::new(implied_output_region); ast_ty_to_ty(this, &rb, &*decl.output) } None => { @@ -1130,7 +1150,7 @@ pub fn ty_of_closure( id: ast::NodeId, fn_style: ast::FnStyle, onceness: ast::Onceness, - bounds: ty::BuiltinBounds, + bounds: ty::ExistentialBounds, store: ty::TraitStore, decl: &ast::FnDecl, abi: abi::Abi, @@ -1176,67 +1196,250 @@ pub fn ty_of_closure( } } -fn conv_builtin_bounds(tcx: &ty::ctxt, - span: Span, - ast_bounds: &Option>, - static_region: bool) - -> ty::BuiltinBounds { - //! Converts a list of bounds from the AST into a `BuiltinBounds` - //! struct. Reports an error if any of the bounds that appear - //! in the AST refer to general traits and not the built-in traits - //! like `Send`. Used to translate the bounds that - //! appear in closure and trait types, where only builtin bounds are - //! legal. - //! If no bounds were specified, we choose a "default" bound based on - //! the allocation type of the fn/trait, as per issue #7264. The user can - //! override this with an empty bounds list, e.g. "Box" or - //! "Box". +pub fn conv_existential_bounds( + this: &AC, + rscope: &RS, + span: Span, + main_trait_refs: &[Rc], + ast_bounds: &[ast::TyParamBound]) + -> ty::ExistentialBounds +{ + /*! + * Given an existential type like `Foo+'a+Bar`, this routine + * converts the `'a` and `Bar` intos an `ExistentialBounds` + * struct. The `main_trait_refs` argument specifies the `Foo` -- + * it is absent for closures. Eventually this should all be + * normalized, I think, so that there is no "main trait ref" and + * instead we just have a flat list of bounds as the existential + * type. + */ - match ast_bounds { - &Some(ref bound_vec) => { - let mut builtin_bounds = ty::empty_builtin_bounds(); - for ast_bound in bound_vec.iter() { - match *ast_bound { - ast::TraitTyParamBound(ref b) => { - match lookup_def_tcx(tcx, b.path.span, b.ref_id) { - def::DefTrait(trait_did) => { - if ty::try_add_builtin_trait(tcx, trait_did, - &mut builtin_bounds) { - continue; // success - } - } - _ => { } - } - tcx.sess.span_fatal( - b.path.span, - "only the builtin traits can be used as closure \ - or object bounds"); - } - ast::StaticRegionTyParamBound => { - builtin_bounds.add(ty::BoundStatic); - } - ast::UnboxedFnTyParamBound(_) => { - tcx.sess.span_err(span, - "unboxed functions are not allowed \ - here"); - } - ast::OtherRegionTyParamBound(span) => { - if !tcx.sess.features.issue_5723_bootstrap.get() { - tcx.sess.span_err( - span, - "only the 'static lifetime is accepted \ - here."); - } - } - } - } - builtin_bounds - }, - // &'static Trait is sugar for &'static Trait:'static. - &None if static_region => { - let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set - } - &None => ty::empty_builtin_bounds(), + let ast_bound_refs: Vec<&ast::TyParamBound> = + ast_bounds.iter().collect(); + + let PartitionedBounds { builtin_bounds, + trait_bounds, + region_bounds, + unboxed_fn_ty_bounds } = + partition_bounds(this.tcx(), span, ast_bound_refs.as_slice()); + + if !trait_bounds.is_empty() { + let b = trait_bounds.get(0); + this.tcx().sess.span_err( + b.path.span, + format!("only the builtin traits can be used \ + as closure or object bounds").as_slice()); + } + + if !unboxed_fn_ty_bounds.is_empty() { + this.tcx().sess.span_err( + span, + format!("only the builtin traits can be used \ + as closure or object bounds").as_slice()); + } + + // The "main trait refs", rather annoyingly, have no type + // specified for the `Self` parameter of the trait. The reason for + // this is that they are, after all, *existential* types, and + // hence that type is unknown. However, leaving this type missing + // causes the substitution code to go all awry when walking the + // bounds, so here we clone those trait refs and insert ty::err as + // the self type. Perhaps we should do this more generally, it'd + // be convenient (or perhaps something else, i.e., ty::erased). + let main_trait_refs: Vec> = + main_trait_refs.iter() + .map(|t| + Rc::new(ty::TraitRef { + def_id: t.def_id, + substs: t.substs.with_self_ty(ty::mk_err()) })) + .collect(); + + let region_bound = compute_region_bound(this, + rscope, + span, + builtin_bounds, + region_bounds.as_slice(), + main_trait_refs.as_slice()); + + ty::ExistentialBounds { + region_bound: region_bound, + builtin_bounds: builtin_bounds, + } +} + +pub fn compute_opt_region_bound(tcx: &ty::ctxt, + span: Span, + builtin_bounds: ty::BuiltinBounds, + region_bounds: &[&ast::Lifetime], + trait_bounds: &[Rc]) + -> Option +{ + /*! + * 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( + this: &AC, + rscope: &RS, + span: Span, + builtin_bounds: ty::BuiltinBounds, + region_bounds: &[&ast::Lifetime], + trait_bounds: &[Rc]) + -> 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 } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 6bb17c90da2..3c15135807b 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -87,7 +87,6 @@ use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty}; use middle::typeck::check; -use middle::typeck::infer::MiscVariable; use middle::typeck::infer; use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; @@ -240,6 +239,7 @@ fn construct_transformed_self_ty_for_object( span: Span, trait_def_id: ast::DefId, rcvr_substs: &subst::Substs, + rcvr_bounds: ty::ExistentialBounds, method_ty: &ty::Method) -> ty::t { @@ -276,8 +276,7 @@ fn construct_transformed_self_ty_for_object( tcx.sess.span_bug(span, "static method for object type receiver"); } ByValueExplicitSelfCategory => { - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - ty::empty_builtin_bounds()); + let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds); ty::mk_uniq(tcx, tr) } ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => { @@ -286,12 +285,12 @@ fn construct_transformed_self_ty_for_object( ty::ty_rptr(r, mt) => { // must be SelfRegion let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - ty::empty_builtin_bounds()); + rcvr_bounds); ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl }) } ty::ty_uniq(_) => { // must be SelfUniq let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - ty::empty_builtin_bounds()); + rcvr_bounds); ty::mk_uniq(tcx, tr) } _ => { @@ -442,8 +441,9 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| { match get(self_ty).sty { - ty_trait(box TyTrait { def_id, ref substs, .. }) => { - self.push_inherent_candidates_from_object(def_id, substs); + ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => { + self.push_inherent_candidates_from_object( + def_id, substs, bounds); self.push_inherent_impl_candidates_for_type(def_id); } ty_enum(did, _) | @@ -538,15 +538,13 @@ impl<'a> LookupContext<'a> { } let vcx = self.fcx.vtable_context(); - let region_params = - vec!(vcx.infcx.next_region_var(MiscVariable(self.span))); // Get the tupled type of the arguments. let arguments_type = *closure_function_type.sig.inputs.get(0); let return_type = closure_function_type.sig.output; let closure_region = - vcx.infcx.next_region_var(MiscVariable(self.span)); + vcx.infcx.next_region_var(infer::MiscVariable(self.span)); let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), closure_did, closure_region); @@ -555,7 +553,7 @@ impl<'a> LookupContext<'a> { RcvrMatchesIfSubtype(unboxed_closure_type), rcvr_substs: subst::Substs::new_trait( vec![arguments_type, return_type], - region_params, + vec![], *vcx.infcx.next_ty_vars(1).get(0)), method_ty: method, origin: MethodStaticUnboxedClosure(closure_did), @@ -595,11 +593,11 @@ impl<'a> LookupContext<'a> { fn push_inherent_candidates_from_object(&mut self, did: DefId, - substs: &subst::Substs) { + substs: &subst::Substs, + bounds: ty::ExistentialBounds) { debug!("push_inherent_candidates_from_object(did={}, substs={})", self.did_to_string(did), substs.repr(self.tcx())); - let _indenter = indenter(); let tcx = self.tcx(); let span = self.span; @@ -617,28 +615,30 @@ impl<'a> LookupContext<'a> { substs: rcvr_substs.clone() }); - self.push_inherent_candidates_from_bounds_inner(&[trait_ref.clone()], - |new_trait_ref, m, method_num, _bound_num| { - let vtable_index = get_method_index(tcx, &*new_trait_ref, - trait_ref.clone(), method_num); - let mut m = (*m).clone(); - // We need to fix up the transformed self type. - *m.fty.sig.inputs.get_mut(0) = - construct_transformed_self_ty_for_object( - tcx, span, did, &rcvr_substs, &m); + self.push_inherent_candidates_from_bounds_inner( + &[trait_ref.clone()], + |_this, new_trait_ref, m, method_num, _bound_num| { + let vtable_index = + get_method_index(tcx, &*new_trait_ref, + trait_ref.clone(), method_num); + let mut m = (*m).clone(); + // We need to fix up the transformed self type. + *m.fty.sig.inputs.get_mut(0) = + construct_transformed_self_ty_for_object( + tcx, span, did, &rcvr_substs, bounds, &m); - Some(Candidate { - rcvr_match_condition: RcvrMatchesIfObject(did), - rcvr_substs: new_trait_ref.substs.clone(), - method_ty: Rc::new(m), - origin: MethodObject(MethodObject { + Some(Candidate { + rcvr_match_condition: RcvrMatchesIfObject(did), + rcvr_substs: new_trait_ref.substs.clone(), + method_ty: Rc::new(m), + origin: MethodObject(MethodObject { trait_id: new_trait_ref.def_id, object_trait_id: did, method_num: method_num, real_index: vtable_index }) - }) - }); + }) + }); } fn push_inherent_candidates_from_param(&mut self, @@ -666,7 +666,7 @@ impl<'a> LookupContext<'a> { self.fcx.inh.param_env.bounds.get(space, index).trait_bounds .as_slice(); self.push_inherent_candidates_from_bounds_inner(bounds, - |trait_ref, m, method_num, bound_num| { + |this, trait_ref, m, method_num, bound_num| { match restrict_to { Some(trait_did) => { if trait_did != trait_ref.def_id { @@ -675,6 +675,18 @@ impl<'a> LookupContext<'a> { } _ => {} } + debug!("found match: trait_ref={} substs={} m={}", + trait_ref.repr(this.tcx()), + trait_ref.substs.repr(this.tcx()), + m.repr(this.tcx())); + assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(), + trait_ref.substs.types.get_slice(subst::TypeSpace).len()); + assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(), + trait_ref.substs.regions().get_slice(subst::TypeSpace).len()); + assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(), + trait_ref.substs.types.get_slice(subst::SelfSpace).len()); + assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), + trait_ref.substs.regions().get_slice(subst::SelfSpace).len()); Some(Candidate { rcvr_match_condition: RcvrMatchesIfSubtype(self_ty), rcvr_substs: trait_ref.substs.clone(), @@ -691,13 +703,15 @@ impl<'a> LookupContext<'a> { // Do a search through a list of bounds, using a callback to actually // create the candidates. - fn push_inherent_candidates_from_bounds_inner(&mut self, - bounds: &[Rc], - mk_cand: |tr: Rc, - m: Rc, - method_num: uint, - bound_num: uint| - -> Option) { + fn push_inherent_candidates_from_bounds_inner( + &mut self, + bounds: &[Rc], + mk_cand: |this: &mut LookupContext, + tr: Rc, + m: Rc, + method_num: uint, + bound_num: uint| + -> Option) { let tcx = self.tcx(); let mut next_bound_idx = 0; // count only trait bounds @@ -719,7 +733,8 @@ impl<'a> LookupContext<'a> { ty::MethodTraitItem(ref method) => (*method).clone(), }; - match mk_cand(bound_trait_ref, + match mk_cand(self, + bound_trait_ref, method, pos, this_bound_idx) { @@ -1338,6 +1353,11 @@ impl<'a> LookupContext<'a> { } } + self.fcx.add_region_obligations_for_parameters( + self.span, + &all_substs, + &candidate.method_ty.generics); + MethodCallee { origin: candidate.origin, ty: fty, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 02464e17bac..b9e96c78533 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -102,7 +102,6 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods}; use middle::typeck::check::method::{DontAutoderefReceiver}; use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; -use middle::typeck::check::regionmanip::relate_free_regions; use middle::typeck::check::vtable::VtableContext; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; @@ -173,6 +172,43 @@ pub struct Inherited<'a> { vtable_map: vtable_map, upvar_borrow_map: RefCell, unboxed_closures: RefCell>, + + // A mapping from each fn's id to its signature, with all bound + // regions replaced with free ones. Unlike the other tables, this + // one is never copied into the tcx: it is only used by regionck. + fn_sig_map: RefCell>>, + + // A set of constraints that regionck must validate. Each + // constraint has the form `T:'a`, meaning "some type `T` must + // outlive the lifetime 'a". These constraints derive from + // instantiated type parameters. So if you had a struct defined + // like + // + // struct Foo { ... } + // + // then in some expression `let x = Foo { ... }` it will + // instantiate the type parameter `T` with a fresh type `$0`. At + // the same time, it will record a region obligation of + // `$0:'static`. This will get checked later by regionck. (We + // can't generally check these things right away because we have + // to wait until types are resolved.) + // + // These are stored in a map keyed to the id of the innermost + // enclosing fn body / static initializer expression. This is + // because the location where the obligation was incurred can be + // relevant with respect to which sublifetime assumptions are in + // place. The reason that we store under the fn-id, and not + // something more fine-grained, is so that it is easier for + // regionck to be sure that it has found *all* the region + // obligations (otherwise, it's easy to fail to walk to a + // particular node-id). + region_obligations: RefCell>>, +} + +struct RegionObligation { + sub_region: ty::Region, + sup_type: ty::t, + origin: infer::SubregionOrigin, } /// When type-checking an expression, we propagate downward @@ -232,6 +268,8 @@ enum IsBinopAssignment{ #[deriving(Clone)] pub struct FnCtxt<'a> { + body_id: ast::NodeId, + // This flag is set to true if, during the writeback phase, we encounter // a type error in this function. writeback_errors: Cell, @@ -243,22 +281,8 @@ pub struct FnCtxt<'a> { err_count_on_creation: uint, ret_ty: ty::t, - ps: RefCell, - // Sometimes we generate region pointers where the precise region - // to use is not known. For example, an expression like `&x.f` - // where `x` is of type `@T`: in this case, we will be rooting - // `x` onto the stack frame, and we could choose to root it until - // the end of (almost) any enclosing block or expression. We - // want to pick the narrowest block that encompasses all uses. - // - // What we do in such cases is to generate a region variable with - // `region_lb` as a lower bound. The regionck pass then adds - // other constraints based on how the variable is used and region - // inference selects the ultimate value. Finally, borrowck is - // charged with guaranteeing that the value whose address was taken - // can actually be made to live as long as it needs to live. - region_lb: Cell, + ps: RefCell, inh: &'a Inherited<'a>, @@ -313,6 +337,8 @@ impl<'a> Inherited<'a> { vtable_map: RefCell::new(FnvHashMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), + fn_sig_map: RefCell::new(NodeMap::new()), + region_obligations: RefCell::new(NodeMap::new()), } } } @@ -322,25 +348,26 @@ pub fn blank_fn_ctxt<'a>( ccx: &'a CrateCtxt<'a>, inh: &'a Inherited<'a>, rty: ty::t, - region_bnd: ast::NodeId) + body_id: ast::NodeId) -> FnCtxt<'a> { FnCtxt { + body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)), - region_lb: Cell::new(region_bnd), inh: inh, ccx: ccx } } -fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> { +fn static_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> { // It's kind of a kludge to manufacture a fake function context // and statement context, but we might as well do write the code only once let param_env = ty::ParameterEnvironment { free_substs: subst::Substs::empty(), - bounds: subst::VecPerParamSpace::empty() + bounds: subst::VecPerParamSpace::empty(), + implicit_region_bound: ty::ReStatic, }; Inherited::new(ccx.tcx, param_env) } @@ -355,6 +382,15 @@ impl<'a> ExprTyProvider for FnCtxt<'a> { } } +struct CheckTypeWellFormedVisitor<'a> { ccx: &'a CrateCtxt<'a> } + +impl<'a> Visitor<()> for CheckTypeWellFormedVisitor<'a> { + fn visit_item(&mut self, i: &ast::Item, _: ()) { + check_type_well_formed(self.ccx, i); + visit::walk_item(self, i, ()); + } +} + struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> } impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> { @@ -374,6 +410,13 @@ impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> { } pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) { + let mut visit = CheckTypeWellFormedVisitor { ccx: ccx }; + visit::walk_crate(&mut visit, krate, ()); + + // If types are not well-formed, it leads to all manner of errors + // downstream, so stop reporting errors at this point. + ccx.tcx.sess.abort_if_errors(); + let mut visit = CheckItemTypesVisitor { ccx: ccx }; visit::walk_crate(&mut visit, krate, ()); @@ -396,11 +439,11 @@ fn check_bare_fn(ccx: &CrateCtxt, match ty::get(fty).sty { ty::ty_bare_fn(ref fn_ty) => { let inh = Inherited::new(ccx.tcx, param_env); - let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig, + let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig, decl, id, body, &inh); vtable::resolve_in_block(&fcx, body); - regionck::regionck_fn(&fcx, body); + regionck::regionck_fn(&fcx, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); } _ => ccx.tcx.sess.impossible_case(body.span, @@ -465,7 +508,7 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> { // non-obvious: the `blk` variable maps to region lb, so // we have to keep this up-to-date. This // is... unfortunate. It'd be nice to not need this. - self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ())); + visit::walk_block(self, b, ()); } // Since an expr occurs as part of the type fixed size arrays we @@ -487,13 +530,16 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> { } -fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, - fn_style: ast::FnStyle, - fn_sig: &ty::FnSig, - decl: &ast::FnDecl, - id: ast::NodeId, - body: &ast::Block, - inherited: &'a Inherited<'a>) -> FnCtxt<'a> +fn check_fn<'a>( + ccx: &'a CrateCtxt<'a>, + fn_style: ast::FnStyle, + fn_style_id: ast::NodeId, + fn_sig: &ty::FnSig, + decl: &ast::FnDecl, + fn_id: ast::NodeId, + body: &ast::Block, + inherited: &'a Inherited<'a>) + -> FnCtxt<'a> { /*! * Helper used by check_bare_fn and check_expr_fn. Does the @@ -514,30 +560,42 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br}) }); - relate_free_regions(tcx, &fn_sig); - let arg_tys = fn_sig.inputs.as_slice(); let ret_ty = fn_sig.output; - debug!("check_fn(arg_tys={}, ret_ty={})", + debug!("check_fn(arg_tys={}, ret_ty={}, fn_id={})", arg_tys.repr(tcx), - ret_ty.repr(tcx)); + ret_ty.repr(tcx), + fn_id); // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. let fcx = FnCtxt { + body_id: body.id, writeback_errors: Cell::new(false), err_count_on_creation: err_count_on_creation, ret_ty: ret_ty, - ps: RefCell::new(FnStyleState::function(fn_style, id)), - region_lb: Cell::new(body.id), + ps: RefCell::new(FnStyleState::function(fn_style, fn_style_id)), inh: inherited, ccx: ccx }; - { + // Remember return type so that regionck can access it later. + let fn_sig_tys: Vec = + arg_tys.iter() + .chain([ret_ty].iter()) + .map(|&ty| ty) + .collect(); + debug!("fn-sig-map: fn_id={} fn_sig_tys={}", + fn_id, + fn_sig_tys.repr(tcx)); + inherited.fn_sig_map + .borrow_mut() + .insert(fn_id, fn_sig_tys); + { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; + // Add formal parameters. for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) { // Create type variables for each argument. @@ -662,6 +720,71 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { } } +fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) { + /*! + * Checks that the field types (in a struct def'n) or + * argument types (in an enum def'n) are well-formed, + * meaning that they do not require any constraints not + * declared in the struct definition itself. + * For example, this definition would be illegal: + * + * struct Ref<'a, T> { x: &'a T } + * + * because the type did not declare that `T:'a`. + * + * We do this check as a pre-pass before checking fn bodies + * because if these constraints are not included it frequently + * leads to confusing errors in fn bodies. So it's better to check + * the types first. + */ + + debug!("check_type_well_formed(it.id={}, it.ident={})", + item.id, + ty::item_path_str(ccx.tcx, local_def(item.id))); + + match item.node { + ast::ItemStruct(..) => { + check_type_defn(ccx, item, |fcx| { + ty::struct_fields(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .map(|f| f.mt.ty) + .collect() + }); + } + ast::ItemEnum(..) => { + check_type_defn(ccx, item, |fcx| { + ty::substd_enum_variants(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .flat_map(|variant| { + variant.args + .iter() + .map(|&arg_ty| arg_ty) + }) + .collect() + }); + } + _ => {} + } + + fn check_type_defn(ccx: &CrateCtxt, + item: &ast::Item, + lookup_fields: |&FnCtxt| -> Vec) + { + let item_def_id = local_def(item.id); + let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); + let param_env = + ty::construct_parameter_environment(ccx.tcx, + &polytype.generics, + item.id); + let inh = Inherited::new(ccx.tcx, param_env); + let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); + let field_tys = lookup_fields(&fcx); + regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice()); + } +} + pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) { debug!("check_item(it.id={}, it.ident={})", it.id, @@ -977,9 +1100,6 @@ fn compare_impl_method(tcx: &ty::ctxt, return; } - let it = trait_m.generics.types.get_slice(subst::FnSpace).iter() - .zip(impl_m.generics.types.get_slice(subst::FnSpace).iter()); - // This code is best explained by example. Consider a trait: // // trait Trait { @@ -1041,20 +1161,27 @@ fn compare_impl_method(tcx: &ty::ctxt, let impl_to_skol_substs = subst::Substs::new(skol_tps.clone(), skol_regions.clone()); - // Compute skolemized form of impl method ty. - let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); - let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); - - // Compute skolemized form of trait method ty. + // Create mapping from trait to skolemized. let trait_to_skol_substs = trait_to_impl_substs .subst(tcx, &impl_to_skol_substs) .with_method(Vec::from_slice(skol_tps.get_slice(subst::FnSpace)), Vec::from_slice(skol_regions.get_slice(subst::FnSpace))); - let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); - let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); + + // Check region bounds. + if !check_region_bounds_on_impl_method(tcx, + impl_m_span, + impl_m, + &trait_m.generics, + &impl_m.generics, + &trait_to_skol_substs, + &impl_to_skol_substs) { + return; + } // Check bounds. + let it = trait_m.generics.types.get_slice(subst::FnSpace).iter() + .zip(impl_m.generics.types.get_slice(subst::FnSpace).iter()); for (i, (trait_param_def, impl_param_def)) in it.enumerate() { // Check that the impl does not require any builtin-bounds // that the trait does not guarantee: @@ -1110,6 +1237,12 @@ fn compare_impl_method(tcx: &ty::ctxt, } } + // Compute skolemized form of impl and trait method tys. + let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); + let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); + let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); + let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); + // Check the impl method type IM is a subtype of the trait method // type TM. To see why this makes sense, think of a vtable. The // expected type of the function pointers in the vtable is the @@ -1134,6 +1267,152 @@ fn compare_impl_method(tcx: &ty::ctxt, // Finally, resolve all regions. This catches wily misuses of lifetime // parameters. infcx.resolve_regions_and_report_errors(); + + fn check_region_bounds_on_impl_method(tcx: &ty::ctxt, + span: Span, + impl_m: &ty::Method, + trait_generics: &ty::Generics, + impl_generics: &ty::Generics, + trait_to_skol_substs: &Substs, + impl_to_skol_substs: &Substs) + -> bool + { + /*! + + Check that region bounds on impl method are the same as those + on the trait. In principle, it could be ok for there to be + fewer region bounds on the impl method, but this leads to an + annoying corner case that is painful to handle (described + below), so for now we can just forbid it. + + Example (see + `src/test/compile-fail/regions-bound-missing-bound-in-impl.rs`): + + trait Foo<'a> { + fn method1<'b>(); + fn method2<'b:'a>(); + } + + impl<'a> Foo<'a> for ... { + fn method1<'b:'a>() { .. case 1, definitely bad .. } + fn method2<'b>() { .. case 2, could be ok .. } + } + + The "definitely bad" case is case #1. Here, the impl adds an + extra constraint not present in the trait. + + The "maybe bad" case is case #2. Here, the impl adds an extra + constraint not present in the trait. We could in principle + allow this, but it interacts in a complex way with early/late + bound resolution of lifetimes. Basically the presence or + absence of a lifetime bound affects whether the lifetime is + early/late bound, and right now the code breaks if the trait + has an early bound lifetime parameter and the method does not. + + */ + + let trait_params = trait_generics.regions.get_slice(subst::FnSpace); + let impl_params = impl_generics.regions.get_slice(subst::FnSpace); + + debug!("check_region_bounds_on_impl_method: \ + trait_generics={} \ + impl_generics={}", + trait_generics.repr(tcx), + impl_generics.repr(tcx)); + + // Must have same number of early-bound lifetime parameters. + // Unfortunately, if the user screws up the bounds, then this + // will change classification between early and late. E.g., + // if in trait we have `<'a,'b:'a>`, and in impl we just have + // `<'a,'b>`, then we have 2 early-bound lifetime parameters + // in trait but 0 in the impl. But if we report "expected 2 + // but found 0" it's confusing, because it looks like there + // are zero. Since I don't quite know how to phrase things at + // the moment, give a kind of vague error message. + if trait_params.len() != impl_params.len() { + tcx.sess.span_err( + span, + format!("lifetime parameters or bounds on method `{}` do \ + not match the trait declaration", + token::get_ident(impl_m.ident)).as_slice()); + return false; + } + + // Each parameter `'a:'b+'c+'d` in trait should have the same + // set of bounds in the impl, after subst. + for (trait_param, impl_param) in + trait_params.iter().zip( + impl_params.iter()) + { + let trait_bounds = + trait_param.bounds.subst(tcx, trait_to_skol_substs); + let impl_bounds = + impl_param.bounds.subst(tcx, impl_to_skol_substs); + + debug!("check_region_bounds_on_impl_method: \ + trait_param={} \ + impl_param={} \ + trait_bounds={} \ + impl_bounds={}", + trait_param.repr(tcx), + impl_param.repr(tcx), + trait_bounds.repr(tcx), + impl_bounds.repr(tcx)); + + // Collect the set of bounds present in trait but not in + // impl. + let missing: Vec = + trait_bounds.iter() + .filter(|&b| !impl_bounds.contains(b)) + .map(|&b| b) + .collect(); + + // Collect set present in impl but not in trait. + let extra: Vec = + impl_bounds.iter() + .filter(|&b| !trait_bounds.contains(b)) + .map(|&b| b) + .collect(); + + debug!("missing={} extra={}", + missing.repr(tcx), extra.repr(tcx)); + + let err = if missing.len() != 0 || extra.len() != 0 { + tcx.sess.span_err( + span, + format!( + "the lifetime parameter `{}` declared in the impl \ + has a distinct set of bounds \ + from its counterpart `{}` \ + declared in the trait", + impl_param.name.user_string(tcx), + trait_param.name.user_string(tcx)).as_slice()); + true + } else { + false + }; + + if missing.len() != 0 { + tcx.sess.span_note( + span, + format!("the impl is missing the following bounds: `{}`", + missing.user_string(tcx)).as_slice()); + } + + if extra.len() != 0 { + tcx.sess.span_note( + span, + format!("the impl has the following extra bounds: `{}`", + extra.user_string(tcx)).as_slice()); + } + + if err { + return false; + } + } + + return true; + } } fn check_cast(fcx: &FnCtxt, @@ -1163,6 +1442,7 @@ fn check_cast(fcx: &FnCtxt, fcx.write_error(id); return } + if ty::type_is_bot(t_e) { fcx.write_bot(id); return @@ -1301,6 +1581,8 @@ impl<'a> AstConv for FnCtxt<'a> { } impl<'a> FnCtxt<'a> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx } + pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> { &self.inh.infcx } @@ -1319,6 +1601,10 @@ impl<'a> FnCtxt<'a> { } impl<'a> RegionScope for infer::InferCtxt<'a> { + fn default_region_bound(&self, span: Span) -> Option { + Some(self.next_region_var(infer::MiscVariable(span))) + } + fn anon_regions(&self, span: Span, count: uint) -> Result , ()> { Ok(Vec::from_fn(count, |_| { @@ -1494,19 +1780,10 @@ impl<'a> FnCtxt<'a> { } pub fn mk_subr(&self, - a_is_expected: bool, origin: infer::SubregionOrigin, sub: ty::Region, sup: ty::Region) { - infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup) - } - - pub fn with_region_lb(&self, lb: ast::NodeId, f: || -> R) -> R { - let old_region_lb = self.region_lb.get(); - self.region_lb.set(lb); - let v = f(); - self.region_lb.set(old_region_lb); - v + infer::mk_subr(self.infcx(), origin, sub, sup) } pub fn type_error_message(&self, @@ -1536,6 +1813,112 @@ impl<'a> FnCtxt<'a> { err: &ty::type_err) { self.infcx().report_mismatched_types(sp, e, a, err) } + + pub fn register_region_obligation(&self, + origin: infer::SubregionOrigin, + ty: ty::t, + r: ty::Region) + { + /*! + * Registers an obligation for checking later, during + * regionck, that the type `ty` must outlive the region `r`. + */ + + let mut region_obligations = self.inh.region_obligations.borrow_mut(); + let v = region_obligations.find_or_insert_with(self.body_id, + |_| Vec::new()); + v.push(RegionObligation { sub_region: r, + sup_type: ty, + origin: origin }); + } + + pub fn add_region_obligations_for_parameters(&self, + span: Span, + substs: &Substs, + generics: &ty::Generics) + { + /*! + * Given a set of generic parameter definitions (`generics`) + * and the values provided for each of them (`substs`), + * creates and registers suitable region obligations. + * + * For example, if there is a function: + * + * fn foo<'a,T:'a>(...) + * + * and a reference: + * + * let f = foo; + * + * Then we will create a fresh region variable `'$0` and a + * fresh type variable `$1` for `'a` and `T`. This routine + * will add a region obligation `$1:'$0` and register it + * locally. + */ + + debug!("add_region_obligations_for_parameters(substs={}, generics={})", + substs.repr(self.tcx()), + generics.repr(self.tcx())); + + assert_eq!(generics.types.iter().len(), + substs.types.iter().len()); + for (type_def, &type_param) in + generics.types.iter().zip( + substs.types.iter()) + { + let param_ty = ty::ParamTy { space: type_def.space, + idx: type_def.index, + def_id: type_def.def_id }; + let bounds = type_def.bounds.subst(self.tcx(), substs); + add_region_obligations_for_type_parameter( + self, span, param_ty, &bounds, type_param); + } + + assert_eq!(generics.regions.iter().len(), + substs.regions().iter().len()); + for (region_def, ®ion_param) in + generics.regions.iter().zip( + substs.regions().iter()) + { + let bounds = region_def.bounds.subst(self.tcx(), substs); + add_region_obligations_for_region_parameter( + self, span, bounds.as_slice(), region_param); + } + + fn add_region_obligations_for_type_parameter( + fcx: &FnCtxt, + span: Span, + param_ty: ty::ParamTy, + param_bound: &ty::ParamBounds, + ty: ty::t) + { + // For each declared region bound `T:r`, `T` must outlive `r`. + let region_bounds = + ty::required_region_bounds( + fcx.tcx(), + param_bound.opt_region_bound.as_slice(), + param_bound.builtin_bounds, + param_bound.trait_bounds.as_slice()); + for &r in region_bounds.iter() { + let origin = infer::RelateParamBound(span, param_ty, ty); + fcx.register_region_obligation(origin, ty, r); + } + } + + fn add_region_obligations_for_region_parameter( + fcx: &FnCtxt, + span: Span, + region_bounds: &[ty::Region], + region_param: ty::Region) + { + for &b in region_bounds.iter() { + // For each bound `region:b`, `b <= region` must hold + // (i.e., `region` must outlive `b`). + let origin = infer::RelateRegionParamBound(span); + fcx.mk_subr(origin, b, region_param); + } + } + } } pub enum LvaluePreference { @@ -2269,7 +2652,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, lvalue_pref: LvaluePreference, unifier: ||) { - debug!(">> typechecking"); + debug!(">> typechecking: expr={} expected={}", + expr.repr(fcx.tcx()), expected.repr(fcx.tcx())); // A generic function for doing all of the checking for call expressions fn check_call(fcx: &FnCtxt, @@ -2674,17 +3058,19 @@ fn check_expr_with_unifier(fcx: &FnCtxt, kind: ast::UnboxedClosureKind, decl: &ast::FnDecl, body: ast::P) { - // The `RegionTraitStore` is a lie, but we ignore it so it doesn't - // matter. - // - // FIXME(pcwalton): Refactor this API. let mut fn_ty = astconv::ty_of_closure( fcx, expr.id, ast::NormalFn, ast::Many, - ty::empty_builtin_bounds(), + + // The `RegionTraitStore` and region_existential_bounds + // are lies, but we ignore them so it doesn't matter. + // + // FIXME(pcwalton): Refactor this API. + ty::region_existential_bound(ty::ReStatic), ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable), + decl, abi::RustCall, None); @@ -2703,6 +3089,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_fn(fcx.ccx, ast::NormalFn, + expr.id, &fn_ty.sig, decl, expr.id, @@ -2776,13 +3163,17 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } _ => { // Not an error! Means we're inferring the closure type - let mut bounds = ty::empty_builtin_bounds(); - let onceness = match expr.node { + let (bounds, onceness) = match expr.node { ast::ExprProc(..) => { - bounds.add(ty::BoundSend); - ast::Once + let mut bounds = ty::region_existential_bound(ty::ReStatic); + bounds.builtin_bounds.add(ty::BoundSend); // FIXME + (bounds, ast::Once) + } + _ => { + let region = fcx.infcx().next_region_var( + infer::AddrOfRegion(expr.span)); + (ty::region_existential_bound(region), ast::Many) } - _ => ast::Many }; (None, onceness, bounds) } @@ -2808,7 +3199,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // If the closure is a stack closure and hasn't had some non-standard // style inferred for it, then check it under its parent's style. // Otherwise, use its own - let (inherited_style, id) = match store { + let (inherited_style, inherited_style_id) = match store { ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style, fcx.ps.borrow().def), ty::UniqTraitStore => (ast::NormalFn, expr.id) @@ -2816,9 +3207,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_fn(fcx.ccx, inherited_style, + inherited_style_id, &fty_sig, - decl, - id, + &*decl, + expr.id, &*body, fcx.inh); } @@ -3080,13 +3472,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // places: the exchange heap and the managed heap. let definition = lookup_def(fcx, path.span, place.id); let def_id = definition.def_id(); + let referent_ty = fcx.expr_ty(&**subexpr); if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_uniq(tcx, - fcx.expr_ty(&**subexpr))); + fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); checked = true } else if tcx.lang_items.managed_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_box(tcx, - fcx.expr_ty(&**subexpr))); + fcx.register_region_obligation(infer::Managed(expr.span), + referent_ty, + ty::ReStatic); + fcx.write_ty(id, ty::mk_box(tcx, referent_ty)); checked = true } } @@ -3270,7 +3664,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt, //ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd), // Empty slices live in static memory. ast::ExprVec(ref elements) if elements.len() == 0 => { - ty::mk_rptr(tcx, ty::ReStatic, tm) + // Note: we do not assign a lifetime of + // static. This is because the resulting type + // `&'static [T]` would require that T outlives + // `'static`! + let region = fcx.infcx().next_region_var( + infer::AddrOfSlice(expr.span)); + ty::mk_rptr(tcx, region, tm) } _ => { let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); @@ -3281,9 +3681,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt, fcx.write_ty(id, oprnd_t); } ast::ExprPath(ref pth) => { - let defn = lookup_def(fcx, pth.span, id); - let pty = polytype_for_def(fcx, expr.span, defn); - instantiate_path(fcx, pth, pty, defn, expr.span, expr.id); + let defn = lookup_def(fcx, pth.span, id); + let pty = polytype_for_def(fcx, expr.span, defn); + instantiate_path(fcx, pth, pty, defn, expr.span, expr.id); + + // We always require that the type provided as the value for + // a type parameter outlives the moment of instantiation. + constrain_path_type_parameters(fcx, expr); } ast::ExprInlineAsm(ref ia) => { for &(_, ref input) in ia.inputs.iter() { @@ -3708,6 +4112,18 @@ fn check_expr_with_unifier(fcx: &FnCtxt, unifier(); } +fn constrain_path_type_parameters(fcx: &FnCtxt, + expr: &ast::Expr) +{ + fcx.opt_node_ty_substs(expr.id, |item_substs| { + for &ty in item_substs.substs.types.iter() { + let default_bound = ty::ReScope(expr.id); + let origin = infer::RelateDefaultParamBound(expr.span, ty); + fcx.register_region_obligation(origin, ty, default_bound); + } + }); +} + impl Expectation { fn only_has_type(self) -> Expectation { match self { @@ -3889,80 +4305,78 @@ fn check_block_with_expected(fcx: &FnCtxt, replace(&mut *fcx_ps, fn_style_state) }; - fcx.with_region_lb(blk.id, || { - let mut warned = false; - let mut last_was_bot = false; - let mut any_bot = false; - let mut any_err = false; - for s in blk.stmts.iter() { - check_stmt(fcx, &**s); - let s_id = ast_util::stmt_id(&**s); - let s_ty = fcx.node_ty(s_id); - if last_was_bot && !warned && match s.node { - ast::StmtDecl(decl, _) => { - match decl.node { - ast::DeclLocal(_) => true, - _ => false, - } - } - ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true, - _ => false - } { - fcx.ccx - .tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - s_id, - s.span, - "unreachable statement".to_string()); - warned = true; + let mut warned = false; + let mut last_was_bot = false; + let mut any_bot = false; + let mut any_err = false; + for s in blk.stmts.iter() { + check_stmt(fcx, &**s); + let s_id = ast_util::stmt_id(&**s); + let s_ty = fcx.node_ty(s_id); + if last_was_bot && !warned && match s.node { + ast::StmtDecl(decl, _) => { + match decl.node { + ast::DeclLocal(_) => true, + _ => false, + } } - if ty::type_is_bot(s_ty) { - last_was_bot = true; - } - any_bot = any_bot || ty::type_is_bot(s_ty); - any_err = any_err || ty::type_is_error(s_ty); + ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true, + _ => false + } { + fcx.ccx + .tcx + .sess + .add_lint(lint::builtin::UNREACHABLE_CODE, + s_id, + s.span, + "unreachable statement".to_string()); + warned = true; } - match blk.expr { - None => if any_err { - fcx.write_error(blk.id); - } - else if any_bot { - fcx.write_bot(blk.id); - } - else { - fcx.write_nil(blk.id); - }, - Some(e) => { - if any_bot && !warned { - fcx.ccx - .tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); - } - let ety = match expected { - ExpectHasType(ety) => { - check_expr_coercable_to_type(fcx, &*e, ety); - ety - } - _ => { - check_expr_with_expectation(fcx, &*e, expected); - fcx.expr_ty(&*e) - } - }; - - fcx.write_ty(blk.id, ety); - if any_err { - fcx.write_error(blk.id); - } else if any_bot { - fcx.write_bot(blk.id); - } + if ty::type_is_bot(s_ty) { + last_was_bot = true; + } + any_bot = any_bot || ty::type_is_bot(s_ty); + any_err = any_err || ty::type_is_error(s_ty); + } + match blk.expr { + None => if any_err { + fcx.write_error(blk.id); + } + else if any_bot { + fcx.write_bot(blk.id); + } + else { + fcx.write_nil(blk.id); + }, + Some(e) => { + if any_bot && !warned { + fcx.ccx + .tcx + .sess + .add_lint(lint::builtin::UNREACHABLE_CODE, + e.id, + e.span, + "unreachable expression".to_string()); } - }; - }); + let ety = match expected { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &*e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &*e, expected); + fcx.expr_ty(&*e) + } + }; + + fcx.write_ty(blk.id, ety); + if any_err { + fcx.write_error(blk.id); + } else if any_bot { + fcx.write_bot(blk.id); + } + } + }; *fcx.ps.borrow_mut() = prev; } @@ -3980,7 +4394,7 @@ pub fn check_const_in_type(tcx: &ty::ctxt, trait_map: NodeMap::new(), tcx: tcx, }; - let inh = blank_inherited_fields(&ccx); + let inh = static_inherited_fields(&ccx); let fcx = blank_fn_ctxt(&ccx, &inh, expected_type, expr.id); check_const_with_ty(&fcx, expr.span, expr, expected_type); } @@ -3989,7 +4403,7 @@ pub fn check_const(ccx: &CrateCtxt, sp: Span, e: &ast::Expr, id: ast::NodeId) { - let inh = blank_inherited_fields(ccx); + let inh = static_inherited_fields(ccx); let rty = ty::node_id_to_type(ccx.tcx, id); let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id); let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty; @@ -4184,7 +4598,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt, Some(e) => { debug!("disr expr, checking {}", pprust::expr_to_string(&*e)); - let inh = blank_inherited_fields(ccx); + let inh = static_inherited_fields(ccx); let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id); let declty = match hint { attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(), @@ -4495,6 +4909,9 @@ pub fn instantiate_path(fcx: &FnCtxt, assert_eq!(substs.regions().len(space), region_defs.len(space)); } + fcx.add_region_obligations_for_parameters( + span, &substs, &polytype.generics); + fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts { substs: substs, }); @@ -4888,11 +5305,13 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { Ok(t) => t, Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); } }; - let region = ty::ReLateBound(it.id, ty::BrAnon(0)); - let visitor_object_ty = match ty::visitor_object_ty(tcx, region) { - Ok((_, vot)) => vot, - Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); } - }; + let region0 = ty::ReLateBound(it.id, ty::BrAnon(0)); + let region1 = ty::ReLateBound(it.id, ty::BrAnon(1)); + let visitor_object_ty = + match ty::visitor_object_ty(tcx, region0, region1) { + Ok((_, vot)) => vot, + Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); } + }; let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { ty: tydesc_ty, @@ -5097,3 +5516,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { } } +impl Repr for RegionObligation { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("RegionObligation(sub_region={}, sup_type={}, origin={})", + self.sub_region.repr(tcx), + self.sup_type.repr(tcx), + self.origin.repr(tcx)) + } +} diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 4f77c89e86c..72f33a2f984 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -126,14 +126,14 @@ use middle::ty::{ReScope}; use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; -use middle::typeck::check::regionmanip::relate_nested_regions; +use middle::typeck::check::regionmanip; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::MethodCall; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap}; -use util::ppaux::{ty_to_string, region_to_string, Repr}; +use util::ppaux::{ty_to_string, Repr}; use syntax::ast; use syntax::codemap::Span; @@ -143,6 +143,46 @@ use syntax::visit::Visitor; use std::cell::RefCell; use std::gc::Gc; +/////////////////////////////////////////////////////////////////////////// +// PUBLIC ENTRY POINTS + +pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { + let mut rcx = Rcx::new(fcx, e.id); + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + rcx.visit_expr(e, ()); + rcx.visit_region_obligations(e.id); + } + fcx.infcx().resolve_regions_and_report_errors(); +} + +pub fn regionck_type_defn(fcx: &FnCtxt, + span: Span, + component_tys: &[ty::t]) { + let mut rcx = Rcx::new(fcx, 0); + for &component_ty in component_tys.iter() { + // Check that each type outlives the empty region. Since the + // empty region is a subregion of all others, this can't fail + // unless the type does not meet the well-formedness + // requirements. + type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), + component_ty, ty::ReEmpty); + } + fcx.infcx().resolve_regions_and_report_errors(); +} + +pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) { + let mut rcx = Rcx::new(fcx, blk.id); + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded + rcx.visit_fn_body(id, blk); + } + fcx.infcx().resolve_regions_and_report_errors(); +} + +/////////////////////////////////////////////////////////////////////////// +// INTERNALS + // If mem categorization results in an error, it's because the type // check failed (or will fail, when the error is uncovered and // reported during writeback). In this case, we just ignore this part @@ -159,10 +199,32 @@ macro_rules! ignore_err( pub struct Rcx<'a> { fcx: &'a FnCtxt<'a>, + region_param_pairs: Vec<(ty::Region, ty::ParamTy)>, + // id of innermost fn or loop repeating_scope: ast::NodeId, } +/// When entering a function, we can derive relationships from the +/// signature between various regions and type parameters. Consider +/// a function like: +/// +/// fn foo<'a, A>(x: &'a A) { ... } +/// +/// Here, we can derive that `A` must outlive `'a`, because otherwise +/// the caller would be illegal. We record this by storing a series of +/// pairs (in this case, `('a, A)`). These pairs will be consulted +/// later during regionck. +/// +/// In the case of nested fns, additional relationships may be +/// derived. The result is a link list walking up the stack (hence +/// the `previous` field). +#[deriving(Clone)] +pub struct RegionSubParamConstraints<'a> { + pairs: Vec<(ty::Region, ty::ParamTy)>, + previous: Option<&'a RegionSubParamConstraints<'a>>, +} + fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { /*! * Returns the validity region of `def` -- that is, how long @@ -189,6 +251,13 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { } impl<'a> Rcx<'a> { + pub fn new(fcx: &'a FnCtxt<'a>, + initial_repeating_scope: ast::NodeId) -> Rcx<'a> { + Rcx { fcx: fcx, + repeating_scope: initial_repeating_scope, + region_param_pairs: Vec::new() } + } + pub fn tcx(&self) -> &'a ty::ctxt { self.fcx.ccx.tcx } @@ -259,6 +328,114 @@ impl<'a> Rcx<'a> { |method_call| self.resolve_method_type(method_call)) } } + + fn visit_fn_body(&mut self, + id: ast::NodeId, + body: &ast::Block) + { + // When we enter a function, we can derive + + let fn_sig_map = self.fcx.inh.fn_sig_map.borrow(); + let fn_sig = match fn_sig_map.find(&id) { + Some(f) => f, + None => { + self.tcx().sess.bug( + format!("No fn-sig entry for id={}", id).as_slice()); + } + }; + + let len = self.region_param_pairs.len(); + self.relate_free_regions(fn_sig.as_slice(), body.id); + self.visit_block(body, ()); + self.visit_region_obligations(body.id); + self.region_param_pairs.truncate(len); + } + + fn visit_region_obligations(&mut self, node_id: ast::NodeId) + { + debug!("visit_region_obligations: node_id={}", node_id); + let region_obligations = self.fcx.inh.region_obligations.borrow(); + match region_obligations.find(&node_id) { + None => { } + Some(vec) => { + for r_o in vec.iter() { + debug!("visit_region_obligations: r_o={}", + r_o.repr(self.tcx())); + let sup_type = self.resolve_type(r_o.sup_type); + type_must_outlive(self, r_o.origin.clone(), + sup_type, r_o.sub_region); + } + } + } + } + + fn relate_free_regions(&mut self, + fn_sig_tys: &[ty::t], + body_id: ast::NodeId) { + /*! + * This method populates the region map's `free_region_map`. + * It walks over the transformed argument and return types for + * each function just before we check the body of that + * function, looking for types where you have a borrowed + * pointer to other borrowed data (e.g., `&'a &'b [uint]`. We + * do not allow references to outlive the things they point + * at, so we can assume that `'a <= 'b`. This holds for both + * the argument and return types, basically because, on the caller + * side, the caller is responsible for checking that the type of + * every expression (including the actual values for the arguments, + * as well as the return type of the fn call) is well-formed. + * + * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` + */ + + debug!("relate_free_regions >>"); + let tcx = self.tcx(); + + for &ty in fn_sig_tys.iter() { + let ty = self.resolve_type(ty); + debug!("relate_free_regions(t={})", ty.repr(tcx)); + let body_scope = ty::ReScope(body_id); + let constraints = + regionmanip::region_wf_constraints( + tcx, + ty, + body_scope); + for constraint in constraints.iter() { + debug!("constraint: {}", constraint.repr(tcx)); + match *constraint { + regionmanip::RegionSubRegionConstraint(_, + ty::ReFree(free_a), + ty::ReFree(free_b)) => { + tcx.region_maps.relate_free_regions(free_a, free_b); + } + regionmanip::RegionSubRegionConstraint(_, + ty::ReFree(free_a), + ty::ReInfer(ty::ReVar(vid_b))) => { + self.fcx.inh.infcx.add_given(free_a, vid_b); + } + regionmanip::RegionSubRegionConstraint(..) => { + // In principle, we could record (and take + // advantage of) every relationship here, but + // we are also free not to -- it simply means + // strictly less that we can successfully type + // check. (It may also be that we should + // revise our inference system to be more + // general and to make use of *every* + // relationship that arises here, but + // presently we do not.) + } + regionmanip::RegionSubParamConstraint(_, r_a, p_b) => { + debug!("RegionSubParamConstraint: {} <= {}", + r_a.repr(tcx), p_b.repr(tcx)); + + self.region_param_pairs.push((r_a, p_b)); + } + } + } + } + + debug!("<< relate_free_regions"); + } } impl<'fcx> mc::Typer for Rcx<'fcx> { @@ -302,26 +479,6 @@ impl<'fcx> mc::Typer for Rcx<'fcx> { } } -pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id }; - let rcx = &mut rcx; - if fcx.err_count_since_creation() == 0 { - // regionck assumes typeck succeeded - rcx.visit_expr(e, ()); - } - fcx.infcx().resolve_regions_and_report_errors(); -} - -pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) { - let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id }; - let rcx = &mut rcx; - if fcx.err_count_since_creation() == 0 { - // regionck assumes typeck succeeded - rcx.visit_block(blk, ()); - } - fcx.infcx().resolve_regions_and_report_errors(); -} - impl<'a> Visitor<()> for Rcx<'a> { // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, // However, right now we run into an issue whereby some free @@ -331,6 +488,11 @@ impl<'a> Visitor<()> for Rcx<'a> { // hierarchy, and in particular the relationships between free // regions, until regionck, as described in #3238. + fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl, + b: &ast::Block, _s: Span, id: ast::NodeId, _e: ()) { + self.visit_fn_body(id, b) + } + fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); } fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); } @@ -396,9 +558,9 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { // variable's type enclose at least the variable's scope. let var_region = tcx.region_maps.var_region(id); - constrain_regions_in_type_of_node( - rcx, id, var_region, - infer::BindingTypeIsNotValidAtDecl(span)); + type_of_node_must_outlive( + rcx, infer::BindingTypeIsNotValidAtDecl(span), + id, var_region); }) } @@ -406,6 +568,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { debug!("regionck::visit_expr(e={}, repeating_scope={:?})", expr.repr(rcx.fcx.tcx()), rcx.repeating_scope); + // No matter what, the type of each expression must outlive the + // scope of that expression. This also guarantees basic WF. + let expr_ty = rcx.resolve_node_type(expr.id); + + type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), + expr_ty, ty::ReScope(expr.id)); + let method_call = MethodCall::expr(expr.id); let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call); @@ -416,40 +585,28 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - match ty::adjusted_object_region(adjustment) { - Some(trait_region) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - // - // Note: there is a subtle point here concerning type - // parameters. It is possible that the type of `source` - // contains type parameters, which in turn may contain - // regions that are not visible to us (only the caller - // knows about them). The kind checker is ultimately - // responsible for guaranteeing region safety in that - // particular case. There is an extensive comment on the - // function check_cast_for_escaping_regions() in kind.rs - // explaining how it goes about doing that. + for autoref in opt_autoref.iter() { + link_autoref(rcx, expr, autoderefs, autoref); - constrain_regions_in_type(rcx, trait_region, - infer::RelateObjectBound(expr.span), expr_ty); - } - None => { - for autoref in opt_autoref.iter() { - link_autoref(rcx, expr, autoderefs, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - constrain_regions_in_type_of_node( - rcx, expr.id, ty::ReScope(expr.id), - infer::AutoBorrow(expr.span)); - } - } + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + type_of_node_must_outlive( + rcx, infer::AutoBorrow(expr.span), + expr.id, ty::ReScope(expr.id)); } } + /* + ty::AutoObject(_, ref bounds, _, _) => { + // Determine if we are casting `expr` to a trait + // instance. If so, we have to be sure that the type + // of the source obeys the new region bound. + let source_ty = rcx.resolve_node_type(expr.id); + type_must_outlive(rcx, infer::RelateObjectBound(expr.span), + source_ty, bounds.region_bound); + } + */ _ => {} } } @@ -457,12 +614,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { match expr.node { ast::ExprCall(ref callee, ref args) => { if has_method_map { - constrain_call(rcx, None, expr, Some(*callee), + constrain_call(rcx, expr, Some(*callee), args.as_slice(), false); } else { constrain_callee(rcx, callee.id, expr, &**callee); constrain_call(rcx, - Some(callee.id), expr, None, args.as_slice(), @@ -473,7 +629,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { } ast::ExprMethodCall(_, _, ref args) => { - constrain_call(rcx, None, expr, Some(*args.get(0)), + constrain_call(rcx, expr, Some(*args.get(0)), args.slice_from(1), false); visit::walk_expr(rcx, expr, ()); @@ -486,7 +642,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprAssignOp(_, ref lhs, ref rhs) => { if has_method_map { - constrain_call(rcx, None, expr, Some(lhs.clone()), + constrain_call(rcx, expr, Some(lhs.clone()), [rhs.clone()], true); } @@ -501,7 +657,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // overloaded op. Note that we (sadly) currently use an // implicit "by ref" sort of passing style here. This // should be converted to an adjustment! - constrain_call(rcx, None, expr, Some(lhs.clone()), + constrain_call(rcx, expr, Some(lhs.clone()), [rhs.clone()], true); visit::walk_expr(rcx, expr, ()); @@ -509,17 +665,25 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprUnary(_, ref lhs) if has_method_map => { // As above. - constrain_call(rcx, None, expr, Some(lhs.clone()), [], true); + constrain_call(rcx, expr, Some(lhs.clone()), [], true); visit::walk_expr(rcx, expr, ()); } + ast::ExprUnary(ast::UnBox, ref base) => { + // Managed data must not have borrowed pointers within it: + let base_ty = rcx.resolve_node_type(base.id); + type_must_outlive(rcx, infer::Managed(expr.span), + base_ty, ty::ReStatic); + visit::walk_expr(rcx, expr, ()); + } + ast::ExprUnary(ast::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref let method_call = MethodCall::expr(expr.id); let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) { Some(method) => { - constrain_call(rcx, None, expr, Some(base.clone()), [], true); + constrain_call(rcx, expr, Some(base.clone()), [], true); ty::ty_fn_ret(method.ty) } None => rcx.resolve_node_type(base.id) @@ -547,34 +711,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // Determine if we are casting `source` to a trait // instance. If so, we have to be sure that the type of // the source obeys the trait's region bound. - // - // Note: there is a subtle point here concerning type - // parameters. It is possible that the type of `source` - // contains type parameters, which in turn may contain - // regions that are not visible to us (only the caller - // knows about them). The kind checker is ultimately - // responsible for guaranteeing region safety in that - // particular case. There is an extensive comment on the - // function check_cast_for_escaping_regions() in kind.rs - // explaining how it goes about doing that. - let target_ty = rcx.resolve_node_type(expr.id); - match ty::get(target_ty).sty { - ty::ty_rptr(trait_region, ty::mt{ty, ..}) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - let source_ty = rcx.resolve_expr_type_adjusted(&**source); - constrain_regions_in_type( - rcx, - trait_region, - infer::RelateObjectBound(expr.span), - source_ty); - } - _ => {} - } - } - _ => () - } - + constrain_cast(rcx, expr, &**source); visit::walk_expr(rcx, expr, ()); } @@ -589,8 +726,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); - constrain_regions_in_type(rcx, ty::ReScope(expr.id), - infer::AddrOf(expr.span), ty0); + type_must_outlive(rcx, infer::AddrOf(expr.span), + ty0, ty::ReScope(expr.id)); visit::walk_expr(rcx, expr, ()); } @@ -644,42 +781,108 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { } } +fn constrain_cast(rcx: &mut Rcx, + cast_expr: &ast::Expr, + source_expr: &ast::Expr) +{ + debug!("constrain_cast(cast_expr={}, source_expr={})", + cast_expr.repr(rcx.tcx()), + source_expr.repr(rcx.tcx())); + + let source_ty = rcx.resolve_node_type(source_expr.id); + let target_ty = rcx.resolve_node_type(cast_expr.id); + + walk_cast(rcx, cast_expr, source_ty, target_ty); + + fn walk_cast(rcx: &mut Rcx, + cast_expr: &ast::Expr, + from_ty: ty::t, + to_ty: ty::t) { + debug!("walk_cast(from_ty={}, to_ty={})", + from_ty.repr(rcx.tcx()), + to_ty.repr(rcx.tcx())); + match (&ty::get(from_ty).sty, &ty::get(to_ty).sty) { + /*From:*/ (&ty::ty_rptr(from_r, ref from_mt), + /*To: */ &ty::ty_rptr(to_r, ref to_mt)) => { + // Target cannot outlive source, naturally. + rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), to_r, from_r); + walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty); + } + + /*From:*/ (_, + /*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => { + // When T is existentially quantified as a trait + // `Foo+'to`, it must outlive the region bound `'to`. + type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span), + from_ty, bounds.region_bound); + } + + /*From:*/ (&ty::ty_uniq(from_referent_ty), + /*To: */ &ty::ty_uniq(to_referent_ty)) => { + walk_cast(rcx, cast_expr, from_referent_ty, to_referent_ty); + } + + _ => { } + } + } +} + fn check_expr_fn_block(rcx: &mut Rcx, expr: &ast::Expr, body: &ast::Block) { let tcx = rcx.fcx.tcx(); let function_type = rcx.resolve_node_type(expr.id); + match ty::get(function_type).sty { - ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(region, _), ..}) => { + ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..), + bounds: ref bounds, + ..}) => { + // For closure, ensure that the variables outlive region + // bound, since they are captured by reference. freevars::with_freevars(tcx, expr.id, |freevars| { if freevars.is_empty() { // No free variables means that the environment // will be NULL at runtime and hence the closure // has static lifetime. } else { - // Closure must not outlive the variables it closes over. - constrain_free_variables(rcx, region, expr, freevars); + // Variables being referenced must outlive closure. + constrain_free_variables_in_stack_closure( + rcx, bounds.region_bound, expr, freevars); - // Closure cannot outlive the appropriate temporary scope. + // Closure is stack allocated and hence cannot + // outlive the appropriate temporary scope. let s = rcx.repeating_scope; - rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span), - region, ty::ReScope(s)); + rcx.fcx.mk_subr(infer::InfStackClosure(expr.span), + bounds.region_bound, ty::ReScope(s)); } }); } + ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore, + bounds: ref bounds, + ..}) => { + // For proc, ensure that the *types* of the variables + // outlive region bound, since they are captured by value. + freevars::with_freevars(tcx, expr.id, |freevars| { + ensure_free_variable_types_outlive_closure_bound( + rcx, bounds.region_bound, expr, freevars); + }); + } ty::ty_unboxed_closure(_, region) => { freevars::with_freevars(tcx, expr.id, |freevars| { // No free variables means that there is no environment and // hence the closure has static lifetime. Otherwise, the // closure must not outlive the variables it closes over // by-reference. + // + // NDM -- this seems wrong, discuss with pcwalton, should + // be straightforward enough. if !freevars.is_empty() { - constrain_free_variables(rcx, region, expr, freevars); + ensure_free_variable_types_outlive_closure_bound( + rcx, region, expr, freevars); } }) } - _ => () + _ => { } } let repeating_scope = rcx.set_repeating_scope(body.id); @@ -698,36 +901,74 @@ fn check_expr_fn_block(rcx: &mut Rcx, _ => () } - fn constrain_free_variables(rcx: &mut Rcx, - region: ty::Region, - expr: &ast::Expr, - freevars: &[freevars::freevar_entry]) { + fn ensure_free_variable_types_outlive_closure_bound( + rcx: &mut Rcx, + region_bound: ty::Region, + expr: &ast::Expr, + freevars: &[freevars::freevar_entry]) + { /*! - * Make sure that all free variables referenced inside the closure - * outlive the closure itself. Also, create an entry in the - * upvar_borrows map with a region. + * Make sure that the type of all free variables referenced + * inside a closure/proc outlive the closure/proc's lifetime + * bound. This is just a special case of the usual rules about + * closed over values outliving the object's lifetime bound. + */ + + let tcx = rcx.fcx.ccx.tcx; + + debug!("ensure_free_variable_types_outlive_closure_bound({}, {})", + region_bound.repr(tcx), expr.repr(tcx)); + + for freevar in freevars.iter() { + let var_node_id = { + let def_id = freevar.def.def_id(); + assert!(def_id.krate == ast::LOCAL_CRATE); + def_id.node + }; + + let var_ty = rcx.resolve_node_type(var_node_id); + + type_must_outlive( + rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty), + var_ty, region_bound); + } + } + + fn constrain_free_variables_in_stack_closure( + rcx: &mut Rcx, + region_bound: ty::Region, + expr: &ast::Expr, + freevars: &[freevars::freevar_entry]) + { + /*! + * Make sure that all free variables referenced inside the + * closure outlive the closure's lifetime bound. Also, create + * an entry in the upvar_borrows map with a region. */ let tcx = rcx.fcx.ccx.tcx; let infcx = rcx.fcx.infcx(); debug!("constrain_free_variables({}, {})", - region.repr(tcx), expr.repr(tcx)); + region_bound.repr(tcx), expr.repr(tcx)); for freevar in freevars.iter() { debug!("freevar def is {:?}", freevar.def); // Identify the variable being closed over and its node-id. let def = freevar.def; - let def_id = def.def_id(); - assert!(def_id.krate == ast::LOCAL_CRATE); - let upvar_id = ty::UpvarId { var_id: def_id.node, + let var_node_id = { + let def_id = def.def_id(); + assert!(def_id.krate == ast::LOCAL_CRATE); + def_id.node + }; + let upvar_id = ty::UpvarId { var_id: var_node_id, closure_expr_id: expr.id }; // Create a region variable to represent this borrow. This borrow // must outlive the region on the closure. let origin = infer::UpvarRegion(upvar_id, expr.span); let freevar_region = infcx.next_region_var(origin); - rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node), - region, freevar_region); + rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), + region_bound, freevar_region); // Create a UpvarBorrow entry. Note that we begin with a // const borrow_kind, but change it to either mut or @@ -738,10 +979,10 @@ fn check_expr_fn_block(rcx: &mut Rcx, upvar_borrow); // Guarantee that the closure does not outlive the variable itself. - let en_region = region_of_def(rcx.fcx, def); - debug!("en_region = {}", en_region.repr(tcx)); - rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node), - region, en_region); + let enclosing_region = region_of_def(rcx.fcx, def); + debug!("enclosing_region = {}", enclosing_region.repr(tcx)); + rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), + region_bound, enclosing_region); } } @@ -817,7 +1058,7 @@ fn constrain_callee(rcx: &mut Rcx, } ty::UniqTraitStore => ty::ReStatic }; - rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span), + rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span), call_region, region); } _ => { @@ -832,9 +1073,6 @@ fn constrain_callee(rcx: &mut Rcx, } fn constrain_call(rcx: &mut Rcx, - // might be expr_call, expr_method_call, or an overloaded - // operator - fn_expr_id: Option, call_expr: &ast::Expr, receiver: Option>, arg_exprs: &[Gc], @@ -853,16 +1091,6 @@ fn constrain_call(rcx: &mut Rcx, receiver.repr(tcx), arg_exprs.repr(tcx), implicitly_ref_args); - let callee_ty = match fn_expr_id { - Some(id) => rcx.resolve_node_type(id), - None => rcx.resolve_method_type(MethodCall::expr(call_expr.id)) - .expect("call should have been to a method") - }; - if ty::type_is_error(callee_ty) { - // Bail, as function type is unknown - return; - } - let fn_sig = ty::ty_fn_sig(callee_ty); // `callee_region` is the scope representing the time in which the // call occurs. @@ -871,14 +1099,16 @@ fn constrain_call(rcx: &mut Rcx, let callee_scope = call_expr.id; let callee_region = ty::ReScope(callee_scope); + debug!("callee_region={}", callee_region.repr(tcx)); + for arg_expr in arg_exprs.iter() { - debug!("Argument"); + debug!("Argument: {}", arg_expr.repr(tcx)); // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: - constrain_regions_in_type_of_node( - rcx, arg_expr.id, callee_region, - infer::CallArg(arg_expr.span)); + type_of_node_must_outlive( + rcx, infer::CallArg(arg_expr.span), + arg_expr.id, callee_region); // unfortunately, there are two means of taking implicit // references, and we need to propagate constraints as a @@ -891,19 +1121,14 @@ fn constrain_call(rcx: &mut Rcx, // as loop above, but for receiver for r in receiver.iter() { - debug!("Receiver"); - constrain_regions_in_type_of_node( - rcx, r.id, callee_region, infer::CallRcvr(r.span)); + debug!("receiver: {}", r.repr(tcx)); + type_of_node_must_outlive( + rcx, infer::CallRcvr(r.span), + r.id, callee_region); if implicitly_ref_args { link_by_ref(rcx, &**r, callee_scope); } } - - // constrain regions that may appear in the return type to be - // valid for the function call: - constrain_regions_in_type( - rcx, callee_region, infer::CallReturn(call_expr.span), - fn_sig.output); } fn constrain_autoderefs(rcx: &mut Rcx, @@ -942,12 +1167,10 @@ fn constrain_autoderefs(rcx: &mut Rcx, } // Specialized version of constrain_call. - constrain_regions_in_type(rcx, r_deref_expr, - infer::CallRcvr(deref_expr.span), - self_ty); - constrain_regions_in_type(rcx, r_deref_expr, - infer::CallReturn(deref_expr.span), - fn_sig.output); + type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), + self_ty, r_deref_expr); + type_must_outlive(rcx, infer::CallReturn(deref_expr.span), + fn_sig.output, r_deref_expr); fn_sig.output } None => derefd_ty @@ -974,7 +1197,7 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, deref_span: Span, minimum_lifetime: ty::Region, maximum_lifetime: ty::Region) { - rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span), + rcx.fcx.mk_subr(infer::DerefPointer(deref_span), minimum_lifetime, maximum_lifetime) } @@ -996,7 +1219,7 @@ fn constrain_index(rcx: &mut Rcx, match ty::get(indexed_ty).sty { ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty { ty::ty_vec(_, None) | ty::ty_str => { - rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span), + rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span), r_index_expr, r_ptr); } _ => {} @@ -1006,14 +1229,17 @@ fn constrain_index(rcx: &mut Rcx, } } -fn constrain_regions_in_type_of_node( +fn type_of_node_must_outlive( rcx: &mut Rcx, + origin: infer::SubregionOrigin, id: ast::NodeId, - minimum_lifetime: ty::Region, - origin: infer::SubregionOrigin) { - //! Guarantees that any lifetimes which appear in the type of - //! the node `id` (after applying adjustments) are valid for at - //! least `minimum_lifetime` + minimum_lifetime: ty::Region) +{ + /*! + * Guarantees that any lifetimes which appear in the type of + * the node `id` (after applying adjustments) are valid for at + * least `minimum_lifetime` + */ let tcx = rcx.fcx.tcx(); @@ -1028,54 +1254,7 @@ fn constrain_regions_in_type_of_node( ty={}, ty0={}, id={}, minimum_lifetime={:?})", ty_to_string(tcx, ty), ty_to_string(tcx, ty0), id, minimum_lifetime); - constrain_regions_in_type(rcx, minimum_lifetime, origin, ty); -} - -fn constrain_regions_in_type( - rcx: &mut Rcx, - minimum_lifetime: ty::Region, - origin: infer::SubregionOrigin, - ty: ty::t) { - /*! - * Requires that any regions which appear in `ty` must be - * superregions of `minimum_lifetime`. Also enforces the constraint - * that given a pointer type `&'r T`, T must not contain regions - * that outlive 'r, as well as analogous constraints for other - * lifetime'd types. - * - * This check prevents regions from being used outside of the block in - * which they are valid. Recall that regions represent blocks of - * code or expressions: this requirement basically says "any place - * that uses or may use a region R must be within the block of - * code that R corresponds to." - */ - - let tcx = rcx.fcx.ccx.tcx; - - debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})", - region_to_string(tcx, "", false, minimum_lifetime), - ty_to_string(tcx, ty)); - - relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| { - debug!("relate_nested_regions(r_sub={}, r_sup={})", - r_sub.repr(tcx), - r_sup.repr(tcx)); - - if r_sup.is_bound() || r_sub.is_bound() { - // a bound region is one which appears inside an fn type. - // (e.g., the `&` in `fn(&T)`). Such regions need not be - // constrained by `minimum_lifetime` as they are placeholders - // for regions that are as-yet-unknown. - } else if r_sub == minimum_lifetime { - rcx.fcx.mk_subr( - true, origin.clone(), - r_sub, r_sup); - } else { - rcx.fcx.mk_subr( - true, infer::ReferenceOutlivesReferent(ty, origin.span()), - r_sub, r_sup); - } - }); + type_must_outlive(rcx, origin, ty, minimum_lifetime); } fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr, @@ -1290,7 +1469,7 @@ fn link_region(rcx: &Rcx, debug!("link_region: {} <= {}", region_min.repr(rcx.tcx()), r_borrowed.repr(rcx.tcx())); - rcx.fcx.mk_subr(true, cause, region_min, r_borrowed); + rcx.fcx.mk_subr(cause, region_min, r_borrowed); if kind != ty::ImmBorrow { // If this is a mutable borrow, then the thing @@ -1522,3 +1701,99 @@ fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId, } } } + +fn type_must_outlive(rcx: &mut Rcx, + origin: infer::SubregionOrigin, + ty: ty::t, + region: ty::Region) +{ + /*! + * Ensures that all borrowed data reachable via `ty` outlives `region`. + */ + + debug!("type_must_outlive(ty={}, region={})", + ty.repr(rcx.tcx()), + region.repr(rcx.tcx())); + + let constraints = + regionmanip::region_wf_constraints( + rcx.tcx(), + ty, + region); + for constraint in constraints.iter() { + debug!("constraint: {}", constraint.repr(rcx.tcx())); + match *constraint { + regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => { + rcx.fcx.mk_subr(origin.clone(), r_a, r_b); + } + regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => { + let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); + rcx.fcx.mk_subr(o1, r_a, r_b); + } + regionmanip::RegionSubParamConstraint(None, r_a, param_b) => { + param_must_outlive(rcx, origin.clone(), r_a, param_b); + } + regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => { + let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); + param_must_outlive(rcx, o1, r_a, param_b); + } + } + } +} + +fn param_must_outlive(rcx: &Rcx, + origin: infer::SubregionOrigin, + region: ty::Region, + param_ty: ty::ParamTy) { + let param_env = &rcx.fcx.inh.param_env; + + debug!("param_must_outlive(region={}, param_ty={})", + region.repr(rcx.tcx()), + param_ty.repr(rcx.tcx())); + + // Collect all regions that `param_ty` is known to outlive into + // this vector: + let mut param_bounds; + + // To start, collect bounds from user: + let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx); + param_bounds = + ty::required_region_bounds(rcx.tcx(), + param_bound.opt_region_bound.as_slice(), + param_bound.builtin_bounds, + param_bound.trait_bounds.as_slice()); + + // Collect default bound of fn body that applies to all in scope + // type parameters: + param_bounds.push(param_env.implicit_region_bound); + + // Finally, collect regions we scraped from the well-formedness + // constraints in the fn signature. To do that, we walk the list + // of known relations from the fn ctxt. + // + // This is crucial because otherwise code like this fails: + // + // fn foo<'a, A>(x: &'a A) { x.bar() } + // + // The problem is that the type of `x` is `&'a A`. To be + // well-formed, then, A must be lower-bounded by `'a`, but we + // don't know that this holds from first principles. + for &(ref r, ref p) in rcx.region_param_pairs.iter() { + debug!("param_ty={}/{} p={}/{}", + param_ty.repr(rcx.tcx()), + param_ty.def_id, + p.repr(rcx.tcx()), + p.def_id); + if param_ty == *p { + param_bounds.push(*r); + } + } + + // Inform region inference that this parameter type must be + // properly bounded. + infer::verify_param_bound(rcx.fcx.infcx(), + origin, + param_ty, + region, + param_bounds); +} diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 53e26f8696f..577da159162 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -10,13 +10,15 @@ // #![warn(deprecated_mode)] +use middle::subst::{ParamSpace, Subst, Substs}; use middle::ty; use middle::ty_fold; use middle::ty_fold::TypeFolder; +use syntax::ast; + use std::collections::HashMap; use util::ppaux::Repr; -use util::ppaux; // Helper functions related to manipulating region types. @@ -44,125 +46,363 @@ pub fn replace_late_bound_regions_in_fn_sig( (map, fn_sig) } -pub fn relate_nested_regions(tcx: &ty::ctxt, - opt_region: Option, - ty: ty::t, - relate_op: |ty::Region, ty::Region|) { +pub enum WfConstraint { + RegionSubRegionConstraint(Option, ty::Region, ty::Region), + RegionSubParamConstraint(Option, ty::Region, ty::ParamTy), +} + +struct Wf<'a> { + tcx: &'a ty::ctxt, + stack: Vec<(ty::Region, Option)>, + out: Vec, +} + +pub fn region_wf_constraints( + tcx: &ty::ctxt, + ty: ty::t, + outer_region: ty::Region) + -> Vec +{ /*! - * This rather specialized function walks each region `r` that appear - * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl` - * here is the region of any enclosing `&'r T` pointer. If there is - * no enclosing pointer, and `opt_region` is Some, then `opt_region.get()` - * is used instead. Otherwise, no callback occurs at all). - * - * Here are some examples to give you an intution: - * - * - `relate_nested_regions(Some('r1), &'r2 uint)` invokes - * - `relate_op('r1, 'r2)` - * - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes - * - `relate_op('r1, 'r2)` - * - `relate_op('r2, 'r3)` - * - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes - * - `relate_op('r2, 'r3)` - * - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes - * - `relate_op('r2, 'r3)` - * - `relate_op('r2, 'r4)` - * - `relate_op('r3, 'r4)` - * - * This function is used in various pieces of code because we enforce the - * constraint that a region pointer cannot outlive the things it points at. - * Hence, in the second example above, `'r2` must be a subregion of `'r3`. + * This routine computes the well-formedness constraints that must + * hold for the type `ty` to appear in a context with lifetime + * `outer_region` */ - let mut rr = RegionRelator { tcx: tcx, - stack: Vec::new(), - relate_op: relate_op }; - match opt_region { - Some(o_r) => { rr.stack.push(o_r); } - None => {} - } - rr.fold_ty(ty); + let mut stack = Vec::new(); + stack.push((outer_region, None)); + let mut wf = Wf { tcx: tcx, + stack: stack, + out: Vec::new() }; + wf.accumulate_from_ty(ty); + wf.out +} - struct RegionRelator<'a> { - tcx: &'a ty::ctxt, - stack: Vec, - relate_op: |ty::Region, ty::Region|: 'a, - } +impl<'a> Wf<'a> { + fn accumulate_from_ty(&mut self, ty: ty::t) { + debug!("Wf::accumulate_from_ty(ty={})", + ty.repr(self.tcx)); - // FIXME(#10151) -- Define more precisely when a region is - // considered "nested". Consider taking variance into account as - // well. + match ty::get(ty).sty { + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_char | + ty::ty_int(..) | + ty::ty_uint(..) | + ty::ty_float(..) | + ty::ty_bare_fn(..) | + ty::ty_err | + ty::ty_str => { + // No borrowed content reachable here. + } - impl<'a> TypeFolder for RegionRelator<'a> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt { - self.tcx + ty::ty_closure(box ref c) => { + self.accumulate_from_closure_ty(ty, c); + } + + ty::ty_unboxed_closure(_, region) => { + // An "unboxed closure type" is basically + // modeled here as equivalent to a struct like + // + // struct TheClosure<'b> { + // ... + // } + // + // where the `'b` is the lifetime bound of the + // contents (i.e., all contents must outlive 'b). + self.push_region_constraint_from_top(region); + } + + ty::ty_trait(ref t) => { + self.accumulate_from_object_ty(ty, &t.bounds) + } + + ty::ty_enum(def_id, ref substs) | + ty::ty_struct(def_id, ref substs) => { + self.accumulate_from_adt(ty, def_id, substs) + } + + ty::ty_vec(t, _) | + ty::ty_ptr(ty::mt { ty: t, .. }) | + ty::ty_box(t) | + ty::ty_uniq(t) => { + self.accumulate_from_ty(t) + } + + ty::ty_rptr(r_b, mt) => { + self.accumulate_from_rptr(ty, r_b, mt.ty); + } + + ty::ty_param(p) => { + self.push_param_constraint_from_top(p); + } + + ty::ty_tup(ref tuptys) => { + for &tupty in tuptys.iter() { + self.accumulate_from_ty(tupty); + } + } + + ty::ty_infer(_) => { + // This should not happen, BUT: + // + // Currently we uncover region relationships on + // entering the fn check. We should do this after + // the fn check, then we can call this case a bug(). + } + + ty::ty_open(_) => { + self.tcx.sess.bug( + format!("Unexpected type encountered while doing wf check: {}", + ty.repr(self.tcx)).as_slice()); + } } + } - fn fold_ty(&mut self, ty: ty::t) -> ty::t { - match ty::get(ty).sty { - ty::ty_rptr(r, ty::mt {ty, ..}) => { - self.relate(r); - self.stack.push(r); - ty_fold::super_fold_ty(self, ty); + fn accumulate_from_rptr(&mut self, + ty: ty::t, + r_b: ty::Region, + ty_b: ty::t) { + // We are walking down a type like this, and current + // position is indicated by caret: + // + // &'a &'b ty_b + // ^ + // + // At this point, top of stack will be `'a`. We must + // require that `'a <= 'b`. + + self.push_region_constraint_from_top(r_b); + + // Now we push `'b` onto the stack, because it must + // constrain any borrowed content we find within `T`. + + self.stack.push((r_b, Some(ty))); + self.accumulate_from_ty(ty_b); + self.stack.pop().unwrap(); + } + + fn push_region_constraint_from_top(&mut self, + r_b: ty::Region) { + /*! + * Pushes a constraint that `r_b` must outlive the + * top region on the stack. + */ + + // Indicates that we have found borrowed content with a lifetime + // of at least `r_b`. This adds a constraint that `r_b` must + // outlive the region `r_a` on top of the stack. + // + // As an example, imagine walking a type like: + // + // &'a &'b T + // ^ + // + // when we hit the inner pointer (indicated by caret), `'a` will + // be on top of stack and `'b` will be the lifetime of the content + // we just found. So we add constraint that `'a <= 'b`. + + let &(r_a, opt_ty) = self.stack.last().unwrap(); + self.push_sub_region_constraint(opt_ty, r_a, r_b); + } + + fn push_sub_region_constraint(&mut self, + opt_ty: Option, + 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, + param_ty: ty::ParamTy) { + /*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */ + self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty)); + } + + fn accumulate_from_adt(&mut self, + ty: ty::t, + def_id: ast::DefId, + substs: &Substs) + { + // The generic declarations from the type, appropriately + // substituted for the actual substitutions. + let generics = + ty::lookup_item_type(self.tcx, def_id) + .generics + .subst(self.tcx, substs); + + // Variance of each type/region parameter. + let variances = ty::item_variances(self.tcx, def_id); + + for &space in ParamSpace::all().iter() { + let region_params = substs.regions().get_slice(space); + let region_variances = variances.regions.get_slice(space); + let region_param_defs = generics.regions.get_slice(space); + assert_eq!(region_params.len(), region_variances.len()); + for (®ion_param, (®ion_variance, region_param_def)) in + region_params.iter().zip( + region_variances.iter().zip( + region_param_defs.iter())) + { + match region_variance { + ty::Covariant | ty::Bivariant => { + // Ignore covariant or bivariant region + // parameters. To understand why, consider a + // struct `Foo<'a>`. If `Foo` contains any + // references with lifetime `'a`, then `'a` must + // be at least contravariant (and possibly + // invariant). The only way to have a covariant + // result is if `Foo` contains only a field with a + // type like `fn() -> &'a T`; i.e., a bare + // function that can produce a reference of + // lifetime `'a`. In this case, there is no + // *actual data* with lifetime `'a` that is + // reachable. (Presumably this bare function is + // really returning static data.) + } + + ty::Contravariant | ty::Invariant => { + // If the parameter is contravariant or + // invariant, there may indeed be reachable + // data with this lifetime. See other case for + // more details. + self.push_region_constraint_from_top(region_param); + } + } + + for ®ion_bound in region_param_def.bounds.iter() { + // The type declared a constraint like + // + // 'b : 'a + // + // which means that `'a <= 'b` (after + // substitution). So take the region we + // substituted for `'a` (`region_bound`) and make + // it a subregion of the region we substituted + // `'b` (`region_param`). + self.push_sub_region_constraint( + Some(ty), region_bound, region_param); + } + } + + let types = substs.types.get_slice(space); + let type_variances = variances.types.get_slice(space); + let type_param_defs = generics.types.get_slice(space); + assert_eq!(types.len(), type_variances.len()); + for (&type_param_ty, (&variance, type_param_def)) in + types.iter().zip( + type_variances.iter().zip( + type_param_defs.iter())) + { + debug!("type_param_ty={} variance={}", + type_param_ty.repr(self.tcx), + variance.repr(self.tcx)); + + match variance { + ty::Contravariant | ty::Bivariant => { + // As above, except that in this it is a + // *contravariant* reference that indices that no + // actual data of type T is reachable. + } + + ty::Covariant | ty::Invariant => { + self.accumulate_from_ty(type_param_ty); + } + } + + // Inspect bounds on this type parameter for any + // region bounds. + for &r in type_param_def.bounds.opt_region_bound.iter() { + self.stack.push((r, Some(ty))); + self.accumulate_from_ty(type_param_ty); self.stack.pop().unwrap(); } - - _ => { - ty_fold::super_fold_ty(self, ty); - } } - - ty - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - self.relate(r); - r } } - impl<'a> RegionRelator<'a> { - fn relate(&mut self, r_sub: ty::Region) { - for &r in self.stack.iter() { - if !r.is_bound() && !r_sub.is_bound() { - (self.relate_op)(r, r_sub); - } + fn accumulate_from_closure_ty(&mut self, + ty: ty::t, + c: &ty::ClosureTy) + { + match c.store { + ty::RegionTraitStore(r_b, _) => { + self.push_region_constraint_from_top(r_b); } + ty::UniqTraitStore => { } + } + + self.accumulate_from_object_ty(ty, &c.bounds) + } + + fn accumulate_from_object_ty(&mut self, + ty: ty::t, + bounds: &ty::ExistentialBounds) + { + // Imagine a type like this: + // + // trait Foo { } + // trait Bar<'c> : 'c { } + // + // &'b (Foo+'c+Bar<'d>) + // ^ + // + // In this case, the following relationships must hold: + // + // 'b <= 'c + // 'd <= 'c + // + // The first conditions is due to the normal region pointer + // rules, which say that a reference cannot outlive its + // referent. + // + // The final condition may be a bit surprising. In particular, + // you may expect that it would have been `'c <= 'd`, since + // usually lifetimes of outer things are conservative + // approximations for inner things. However, it works somewhat + // differently with trait objects: here the idea is that if the + // user specifies a region bound (`'c`, in this case) it is the + // "master bound" that *implies* that bounds from other traits are + // all met. (Remember that *all bounds* in a type like + // `Foo+Bar+Zed` must be met, not just one, hence if we write + // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and + // 'y.) + // + // Note: in fact we only permit builtin traits, not `Bar<'d>`, I + // am looking forward to the future here. + + // The content of this object type must outlive + // `bounds.region_bound`: + let r_c = bounds.region_bound; + self.push_region_constraint_from_top(r_c); + + // And then, in turn, to be well-formed, the + // `region_bound` that user specified must imply the + // region bounds required from all of the trait types: + let required_region_bounds = + ty::required_region_bounds(self.tcx, + [], + bounds.builtin_bounds, + []); + for &r_d in required_region_bounds.iter() { + // Each of these is an instance of the `'c <= 'b` + // constraint above + self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c)); } } } - -pub fn relate_free_regions(tcx: &ty::ctxt, fn_sig: &ty::FnSig) { - /*! - * This function populates the region map's `free_region_map`. - * It walks over the transformed self type and argument types - * for each function just before we check the body of that - * function, looking for types where you have a borrowed - * pointer to other borrowed data (e.g., `&'a &'b [uint]`. - * We do not allow references to outlive the things they - * point at, so we can assume that `'a <= 'b`. - * - * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` - */ - - debug!("relate_free_regions >>"); - - let mut all_tys = Vec::new(); - for arg in fn_sig.inputs.iter() { - all_tys.push(*arg); - } - - for &t in all_tys.iter() { - debug!("relate_free_regions(t={})", ppaux::ty_to_string(tcx, t)); - relate_nested_regions(tcx, None, t, |a, b| { - match (&a, &b) { - (&ty::ReFree(free_a), &ty::ReFree(free_b)) => { - tcx.region_maps.relate_free_regions(free_a, free_b); - } - _ => {} - } - }) - } - - debug!("<< relate_free_regions"); -} diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 530f8dd4b9e..2d4022a2eaa 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -94,7 +94,7 @@ fn lookup_vtables(vcx: &VtableContext, let result = type_param_defs.map_rev(|def| { let ty = *substs.types.get(def.space, def.index); lookup_vtables_for_param(vcx, span, Some(substs), - &*def.bounds, ty, is_early) + &def.bounds, ty, is_early) }); debug!("lookup_vtables result(\ @@ -564,7 +564,7 @@ fn fixup_substs(vcx: &VtableContext, // use a dummy type just to package up the substs that need fixing up let t = ty::mk_trait(tcx, id, substs, - ty::empty_builtin_bounds()); + ty::region_existential_bound(ty::ReStatic)); fixup_ty(vcx, span, t, is_early).map(|t_f| { match ty::get(t_f).sty { ty::ty_trait(ref inner) => inner.substs.clone(), @@ -644,7 +644,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { (&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {} (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { infer::mk_subr(fcx.infcx(), - false, infer::RelateObjectBound(ex.span), r_t, r_s); @@ -702,9 +701,11 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { }); let param_bounds = ty::ParamBounds { + opt_region_bound: None, builtin_bounds: ty::empty_builtin_bounds(), trait_bounds: vec!(target_trait_ref) }; + let vtables = lookup_vtables_for_param(&vcx, ex.span, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 5c3317972cd..e7bc06d4972 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -42,47 +42,31 @@ use middle::ty::{Polytype}; use middle::ty; use middle::ty_fold::TypeFolder; use middle::typeck::astconv::{AstConv, ty_of_arg}; -use middle::typeck::astconv::{ast_ty_to_ty}; +use middle::typeck::astconv::{ast_ty_to_ty, ast_region_to_region}; use middle::typeck::astconv; use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; use middle::typeck; use util::ppaux; -use util::ppaux::Repr; +use util::ppaux::{Repr,UserString}; use std::collections::{HashMap, HashSet}; use std::rc::Rc; use std::gc::Gc; use syntax::abi; -use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound}; -use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod}; use syntax::codemap::Span; -use syntax::codemap; -use syntax::owned_slice::OwnedSlice; -use syntax::parse::token::special_idents; +use syntax::parse::token::{special_idents}; use syntax::parse::token; use syntax::print::pprust::{path_to_string}; use syntax::visit; -struct CollectItemTypesVisitor<'a> { - ccx: &'a CrateCtxt<'a> -} - -impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> { - fn visit_item(&mut self, i: &ast::Item, _: ()) { - convert(self.ccx, i); - visit::walk_item(self, i, ()); - } - fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) { - convert_foreign(self.ccx, i); - visit::walk_foreign_item(self, i, ()); - } -} +/////////////////////////////////////////////////////////////////////////// +// Main entry point pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) { fn collect_intrinsic_type(ccx: &CrateCtxt, @@ -99,10 +83,57 @@ pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) { Some(id) => { collect_intrinsic_type(ccx, id); } None => {} } + let mut visitor = CollectTraitDefVisitor{ ccx: ccx }; + visit::walk_crate(&mut visitor, krate, ()); + let mut visitor = CollectItemTypesVisitor{ ccx: ccx }; visit::walk_crate(&mut visitor, krate, ()); } +/////////////////////////////////////////////////////////////////////////// +// First phase: just collect *trait definitions* -- basically, the set +// of type parameters and supertraits. This is information we need to +// know later when parsing field defs. + +struct CollectTraitDefVisitor<'a> { + ccx: &'a CrateCtxt<'a> +} + +impl<'a> visit::Visitor<()> for CollectTraitDefVisitor<'a> { + fn visit_item(&mut self, i: &ast::Item, _: ()) { + match i.node { + ast::ItemTrait(..) => { + // computing the trait def also fills in the table + let _ = trait_def_of_item(self.ccx, i); + } + _ => { } + } + + visit::walk_item(self, i, ()); + } +} + +/////////////////////////////////////////////////////////////////////////// +// Second phase: collection proper. + +struct CollectItemTypesVisitor<'a> { + ccx: &'a CrateCtxt<'a> +} + +impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> { + fn visit_item(&mut self, i: &ast::Item, _: ()) { + convert(self.ccx, i); + visit::walk_item(self, i, ()); + } + fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) { + convert_foreign(self.ccx, i); + visit::walk_foreign_item(self, i, ()); + } +} + +/////////////////////////////////////////////////////////////////////////// +// Utility types and common code for the above passes. + pub trait ToTy { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t; } @@ -193,9 +224,9 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, } } -pub fn ensure_trait_methods(ccx: &CrateCtxt, - trait_id: ast::NodeId, - trait_def: &ty::TraitDef) { +fn collect_trait_methods(ccx: &CrateCtxt, + trait_id: ast::NodeId, + trait_def: &ty::TraitDef) { let tcx = ccx.tcx; match tcx.map.get(trait_id) { ast_map::NodeItem(item) => { @@ -360,7 +391,13 @@ fn convert_methods(ccx: &CrateCtxt, ms: &[Gc], untransformed_rcvr_ty: ty::t, rcvr_ty_generics: &ty::Generics, - rcvr_visibility: ast::Visibility) { + rcvr_visibility: ast::Visibility) +{ + debug!("convert_methods(untransformed_rcvr_ty={}, \ + rcvr_ty_generics={})", + untransformed_rcvr_ty.repr(ccx.tcx), + rcvr_ty_generics.repr(ccx.tcx)); + let tcx = ccx.tcx; let mut seen_methods = HashSet::new(); for m in ms.iter() { @@ -388,6 +425,9 @@ fn convert_methods(ccx: &CrateCtxt, write_ty_to_tcx(tcx, m.id, fty); + debug!("writing method type: def_id={} mty={}", + mty.def_id, mty.repr(ccx.tcx)); + tcx.impl_or_trait_items .borrow_mut() .insert(mty.def_id, ty::MethodTraitItem(mty)); @@ -448,9 +488,20 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, generics: &ast::Generics, thing: &'static str) { for ty_param in generics.ty_params.iter() { - if ty_param.bounds.len() > 0 { - span_err!(ccx.tcx.sess, span, E0122, - "trait bounds are not allowed in {} definitions", thing); + for bound in ty_param.bounds.iter() { + match *bound { + ast::TraitTyParamBound(..) | ast::UnboxedFnTyParamBound(..) => { + // According to accepted RFC #XXX, we should + // eventually accept these, but it will not be + // part of this PR. Still, convert to warning to + // make bootstrapping easier. + span_warn!(ccx.tcx.sess, span, E0122, + "trait bounds are not (yet) enforced \ + in {} definitions", + thing); + } + ast::RegionTyParamBound(..) => { } + } } } } @@ -520,6 +571,10 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); + debug!("trait_def: ident={} trait_def={}", + it.ident.repr(ccx.tcx), + trait_def.repr(ccx.tcx())); + for trait_method in trait_methods.iter() { let self_type = ty::mk_param(ccx.tcx, subst::SelfSpace, @@ -556,7 +611,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { // We need to do this *after* converting methods, since // convert_methods produces a tcache entry that is wrong for // static trait methods. This is somewhat unfortunate. - ensure_trait_methods(ccx, it.id, &*trait_def); + collect_trait_methods(ccx, it.id, &*trait_def); }, ast::ItemStruct(struct_def, _) => { // Write the class type. @@ -739,6 +794,19 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt, } } +pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt, + unboxed_function: &ast::UnboxedFnTy, + param_ty: ty::ParamTy) + -> Rc +{ + 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 { if trait_id.krate != ast::LOCAL_CRATE { return ty::lookup_trait_def(ccx.tcx, trait_id) @@ -761,9 +829,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { _ => {} } - let (generics, unbound, supertraits) = match it.node { - ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => { - (generics, unbound, supertraits) + let (generics, unbound, bounds) = match it.node { + ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => { + (generics, unbound, bounds) } ref s => { tcx.sess.span_bug( @@ -779,13 +847,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { &substs, generics); - let builtin_bounds = - ensure_supertraits(ccx, it.id, it.span, supertraits, unbound); + let self_param_ty = ty::ParamTy::for_self(def_id); + + let bounds = compute_bounds(ccx, token::SELF_KEYWORD_NAME, self_param_ty, + bounds.as_slice(), unbound, it.span, + &generics.where_clause); let substs = mk_item_substs(ccx, &ty_generics); let trait_def = Rc::new(ty::TraitDef { generics: ty_generics, - bounds: builtin_bounds, + bounds: bounds, trait_ref: Rc::new(ty::TraitRef { def_id: def_id, substs: substs @@ -824,55 +895,6 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { subst::Substs::new_trait(types, regions, self_ty) } - - fn ensure_supertraits(ccx: &CrateCtxt, - id: ast::NodeId, - sp: codemap::Span, - ast_trait_refs: &Vec, - unbound: &Option) - -> 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> = Vec::new(); - let mut bounds = ty::empty_builtin_bounds(); - for ast_trait_ref in ast_trait_refs.iter() { - let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref); - - // FIXME(#8559): Need to instantiate the trait_ref whether - // or not it's a builtin trait, so that the trait's node - // id appears in the tcx trait_ref map. This is only - // needed for metadata; see the similar fixme in - // encoder.rs. - - let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty); - if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) { - - // FIXME(#5527) Could have same trait multiple times - if ty_trait_refs.iter().any( - |other_trait| other_trait.def_id == trait_ref.def_id) - { - // This means a trait inherited from the same - // supertrait more than once. - span_err!(tcx.sess, sp, E0127, - "duplicate supertrait in trait declaration"); - break; - } else { - ty_trait_refs.push(trait_ref); - } - } - } - - add_unsized_bound(ccx, unbound, &mut bounds, "trait", sp); - tcx.supertraits.borrow_mut().insert(local_def(id), - Rc::new(ty_trait_refs)); - bounds - } } pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item) @@ -984,11 +1006,12 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, fn ty_generics_for_type(ccx: &CrateCtxt, generics: &ast::Generics) - -> ty::Generics { + -> ty::Generics +{ ty_generics(ccx, subst::TypeSpace, - &generics.lifetimes, - &generics.ty_params, + generics.lifetimes.as_slice(), + generics.ty_params.as_slice(), ty::Generics::empty(), &generics.where_clause) } @@ -1000,8 +1023,8 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, -> ty::Generics { let mut generics = ty_generics(ccx, subst::TypeSpace, - &generics.lifetimes, - &generics.ty_params, + generics.lifetimes.as_slice(), + generics.ty_params.as_slice(), ty::Generics::empty(), &generics.where_clause); @@ -1018,10 +1041,11 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, index: 0, ident: special_idents::type_self, def_id: local_def(param_id), - bounds: Rc::new(ty::ParamBounds { + bounds: ty::ParamBounds { + opt_region_bound: None, builtin_bounds: ty::empty_builtin_bounds(), trait_bounds: vec!(self_trait_ref), - }), + }, default: None }; @@ -1039,8 +1063,8 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); ty_generics(ccx, subst::FnSpace, - &early_lifetimes, - &generics.ty_params, + early_lifetimes.as_slice(), + generics.ty_params.as_slice(), base_generics, &generics.where_clause) } @@ -1053,7 +1077,7 @@ fn add_unsized_bound(ccx: &CrateCtxt, span: Span) { let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); match unbound { - &Some(TraitTyParamBound(ref tpb)) => { + &Some(ast::TraitTyParamBound(ref tpb)) => { // #FIXME(8559) currently requires the unbound to be built-in. let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); match kind_id { @@ -1084,18 +1108,23 @@ fn add_unsized_bound(ccx: &CrateCtxt, fn ty_generics(ccx: &CrateCtxt, space: subst::ParamSpace, - lifetimes: &Vec, - types: &OwnedSlice, + lifetime_defs: &[ast::LifetimeDef], + types: &[ast::TyParam], base_generics: ty::Generics, where_clause: &ast::WhereClause) - -> ty::Generics { + -> ty::Generics +{ let mut result = base_generics; - for (i, l) in lifetimes.iter().enumerate() { + for (i, l) in lifetime_defs.iter().enumerate() { + let bounds = l.bounds.iter() + .map(|l| ast_region_to_region(ccx.tcx, l)) + .collect(); let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, index: i, - def_id: local_def(l.lifetime.id) }; + def_id: local_def(l.lifetime.id), + bounds: bounds }; debug!("ty_generics: def for region param: {}", def); result.regions.push(space, def); } @@ -1123,19 +1152,17 @@ fn ty_generics(ccx: &CrateCtxt, None => { } } - let param_ty = ty::ParamTy {space: space, - idx: index, - def_id: local_def(param.id)}; - let bounds = Rc::new(compute_bounds(ccx, - param_ty, - ¶m.bounds, - ¶m.unbound, - param.ident, - param.span, - where_clause)); + let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); + let bounds = compute_bounds(ccx, + param.ident.name, + param_ty, + param.bounds.as_slice(), + ¶m.unbound, + param.span, + where_clause); let default = param.default.map(|path| { let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path); - let cur_idx = param_ty.idx; + let cur_idx = index; ty::walk_ty(ty, |t| { match ty::get(t).sty { @@ -1164,130 +1191,139 @@ fn ty_generics(ccx: &CrateCtxt, def } +} - fn compute_bounds(ccx: &CrateCtxt, - param_ty: ty::ParamTy, - ast_bounds: &OwnedSlice, - unbound: &Option, - ident: ast::Ident, - span: Span, - where_clause: &ast::WhereClause) - -> ty::ParamBounds { - /*! - * Translate the AST's notion of ty param bounds (which are an - * enum consisting of a newtyped Ty or a region) to ty's - * notion of ty param bounds, which can either be user-defined - * traits, or the built-in trait (formerly known as kind): Send. - */ +fn compute_bounds( + ccx: &CrateCtxt, + name_of_bounded_thing: ast::Name, + param_ty: ty::ParamTy, + ast_bounds: &[ast::TyParamBound], + unbound: &Option, + span: Span, + where_clause: &ast::WhereClause) + -> ty::ParamBounds +{ + /*! + * Translate the AST's notion of ty param bounds (which are an + * enum consisting of a newtyped Ty or a region) to ty's + * notion of ty param bounds, which can either be user-defined + * traits, or the built-in trait (formerly known as kind): Send. + */ - let mut param_bounds = ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: Vec::new() - }; - for ast_bound in ast_bounds.iter() { - compute_bound(ccx, &mut param_bounds, param_ty, ast_bound); - } - for predicate in where_clause.predicates.iter() { - let predicate_param_id = ccx.tcx - .def_map - .borrow() - .find(&predicate.id) - .expect("compute_bounds(): resolve \ - didn't resolve the type \ - parameter identifier in a \ - `where` clause") - .def_id(); - if param_ty.def_id != predicate_param_id { - continue - } - for bound in predicate.bounds.iter() { - compute_bound(ccx, &mut param_bounds, param_ty, bound); - } - } + let mut param_bounds = conv_param_bounds(ccx, + span, + param_ty, + ast_bounds, + where_clause); - add_unsized_bound(ccx, - unbound, - &mut param_bounds.builtin_bounds, - "type parameter", - span); - check_bounds_compatible(ccx.tcx, ¶m_bounds, ident, span); + add_unsized_bound(ccx, + unbound, + &mut param_bounds.builtin_bounds, + "type parameter", + span); - param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); + check_bounds_compatible(ccx.tcx, name_of_bounded_thing, + ¶m_bounds, span); - param_bounds - } + param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); - /// Translates the AST's notion of a type parameter bound to - /// typechecking's notion of the same, and pushes the resulting bound onto - /// the appropriate section of `param_bounds`. - fn compute_bound(ccx: &CrateCtxt, - param_bounds: &mut ty::ParamBounds, - param_ty: ty::ParamTy, - ast_bound: &ast::TyParamBound) { - match *ast_bound { - TraitTyParamBound(ref b) => { - let ty = ty::mk_param(ccx.tcx, param_ty.space, - param_ty.idx, param_ty.def_id); - let trait_ref = instantiate_trait_ref(ccx, b, ty); - if !ty::try_add_builtin_trait( - ccx.tcx, trait_ref.def_id, - &mut param_bounds.builtin_bounds) { - // Must be a user-defined trait - param_bounds.trait_bounds.push(trait_ref); - } - } + param_bounds +} - StaticRegionTyParamBound => { - param_bounds.builtin_bounds.add(ty::BoundStatic); - } - - UnboxedFnTyParamBound(ref unboxed_function) => { - let rscope = ExplicitRscope; - let self_ty = ty::mk_param(ccx.tcx, - param_ty.space, - param_ty.idx, - param_ty.def_id); - let trait_ref = - astconv::trait_ref_for_unboxed_function(ccx, - &rscope, - unboxed_function, - Some(self_ty)); - param_bounds.trait_bounds.push(Rc::new(trait_ref)); - } - - OtherRegionTyParamBound(span) => { - if !ccx.tcx.sess.features.issue_5723_bootstrap.get() { - ccx.tcx.sess.span_err( - span, - "only the 'static lifetime is accepted here."); - } - } - } - } - - fn check_bounds_compatible(tcx: &ty::ctxt, - param_bounds: &ty::ParamBounds, - ident: ast::Ident, - span: Span) { - // Currently the only bound which is incompatible with other bounds is - // Sized/Unsized. - if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) { - ty::each_bound_trait_and_supertraits(tcx, - param_bounds.trait_bounds.as_slice(), - |trait_ref| { +fn check_bounds_compatible(tcx: &ty::ctxt, + name_of_bounded_thing: ast::Name, + param_bounds: &ty::ParamBounds, + span: Span) { + // Currently the only bound which is incompatible with other bounds is + // Sized/Unsized. + if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) { + ty::each_bound_trait_and_supertraits( + tcx, + param_bounds.trait_bounds.as_slice(), + |trait_ref| { let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); - if trait_def.bounds.contains_elem(ty::BoundSized) { + if trait_def.bounds.builtin_bounds.contains_elem(ty::BoundSized) { span_err!(tcx.sess, span, E0129, - "incompatible bounds on type parameter {}, \ - bound {} does not allow unsized type", - token::get_ident(ident), + "incompatible bounds on type parameter `{}`, \ + bound `{}` does not allow unsized type", + name_of_bounded_thing.user_string(tcx), ppaux::trait_ref_to_string(tcx, &*trait_ref)); } true }); + } +} + +fn conv_param_bounds(ccx: &CrateCtxt, + span: Span, + param_ty: ty::ParamTy, + ast_bounds: &[ast::TyParamBound], + where_clause: &ast::WhereClause) + -> ty::ParamBounds +{ + let all_bounds = + merge_param_bounds(ccx, param_ty, ast_bounds, where_clause); + let astconv::PartitionedBounds { builtin_bounds, + trait_bounds, + region_bounds, + unboxed_fn_ty_bounds } = + astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice()); + let unboxed_fn_ty_bounds = + unboxed_fn_ty_bounds.move_iter() + .map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty)); + let trait_bounds: Vec> = + 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, diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index a57dec90455..47085877ad7 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -221,7 +221,7 @@ pub trait Combine { }; let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style)); let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness)); - let bounds = if_ok!(self.bounds(a.bounds, b.bounds)); + let bounds = if_ok!(self.existential_bounds(a.bounds, b.bounds)); let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig)); let abi = if_ok!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { @@ -251,9 +251,26 @@ pub trait Combine { } fn oncenesses(&self, a: Onceness, b: Onceness) -> cres; - fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres; + + fn existential_bounds(&self, + a: ty::ExistentialBounds, + b: ty::ExistentialBounds) + -> cres + { + 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; + fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres; + fn regions(&self, a: ty::Region, b: ty::Region) -> cres; fn trait_stores(&self, @@ -479,7 +496,7 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { if a_.def_id == b_.def_id => { debug!("Trying to match traits {:?} and {:?}", a, b); let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs)); - let bounds = if_ok!(this.bounds(a_.bounds, b_.bounds)); + let bounds = if_ok!(this.existential_bounds(a_.bounds, b_.bounds)); Ok(ty::mk_trait(tcx, a_.def_id, substs.clone(), diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 920fa23f31d..2883a960df9 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -75,6 +75,7 @@ use middle::typeck::infer::region_inference::RegionResolutionError; use middle::typeck::infer::region_inference::ConcreteFailure; use middle::typeck::infer::region_inference::SubSupConflict; use middle::typeck::infer::region_inference::SupSupConflict; +use middle::typeck::infer::region_inference::ParamBoundFailure; use middle::typeck::infer::region_inference::ProcessedErrors; use middle::typeck::infer::region_inference::SameRegions; use std::cell::{Cell, RefCell}; @@ -89,10 +90,13 @@ use syntax::owned_slice::OwnedSlice; use syntax::codemap; use syntax::parse::token; use syntax::print::pprust; -use util::ppaux::UserString; use util::ppaux::bound_region_to_string; use util::ppaux::note_and_explain_region; +// Note: only import UserString, not Repr, since user-facing error +// messages shouldn't include debug serializations. +use util::ppaux::UserString; + pub trait ErrorReporting { fn report_region_errors(&self, errors: &Vec); @@ -118,6 +122,12 @@ pub trait ErrorReporting { sub: Region, sup: Region); + fn report_param_bound_failure(&self, + origin: SubregionOrigin, + param_ty: ty::ParamTy, + sub: Region, + sups: Vec); + fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, sub_origin: SubregionOrigin, @@ -145,7 +155,7 @@ trait ErrorReportingHelpers { var_origin: RegionVariableOrigin); fn note_region_origin(&self, - origin: SubregionOrigin); + origin: &SubregionOrigin); fn give_expl_lifetime_param(&self, decl: &ast::FnDecl, @@ -167,6 +177,10 @@ impl<'a> ErrorReporting for InferCtxt<'a> { self.report_concrete_failure(origin, sub, sup); } + ParamBoundFailure(origin, param_ty, sub, sups) => { + self.report_param_bound_failure(origin, param_ty, sub, sups); + } + SubSupConflict(var_origin, sub_origin, sub_r, sup_origin, sup_r) => { @@ -410,6 +424,62 @@ impl<'a> ErrorReporting for InferCtxt<'a> { found.user_string(self.tcx))) } + fn report_param_bound_failure(&self, + origin: SubregionOrigin, + param_ty: ty::ParamTy, + sub: Region, + _sups: Vec) { + + // FIXME: it would be better to report the first error message + // with the span of the parameter itself, rather than the span + // where the error was detected. But that span is not readily + // accessible. + + match sub { + ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { + // Does the required lifetime have a nice name we can print? + self.tcx.sess.span_err( + origin.span(), + format!( + "the parameter type `{}` may not live long enough; \ + consider adding an explicit lifetime bound `{}:{}`...", + param_ty.user_string(self.tcx), + param_ty.user_string(self.tcx), + sub.user_string(self.tcx)).as_slice()); + } + + ty::ReStatic => { + // Does the required lifetime have a nice name we can print? + self.tcx.sess.span_err( + origin.span(), + format!( + "the parameter type `{}` may not live long enough; \ + consider adding an explicit lifetime bound `{}:'static`...", + param_ty.user_string(self.tcx), + param_ty.user_string(self.tcx)).as_slice()); + } + + _ => { + // If not, be less specific. + self.tcx.sess.span_err( + origin.span(), + format!( + "the parameter type `{}` may not live long enough; \ + consider adding an explicit lifetime bound to `{}`", + param_ty.user_string(self.tcx), + param_ty.user_string(self.tcx)).as_slice()); + note_and_explain_region( + self.tcx, + format!("the parameter type `{}` must be valid for ", + param_ty.user_string(self.tcx)).as_slice(), + sub, + "..."); + } + } + + self.note_region_origin(&origin); + } + fn report_concrete_failure(&self, origin: SubregionOrigin, sub: Region, @@ -538,6 +608,67 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sup, ""); } + infer::RelateProcBound(span, var_node_id, ty) => { + self.tcx.sess.span_err( + span, + format!( + "the type `{}` of captured variable `{}` \ + outlives the `proc()` it \ + is captured in", + self.ty_to_string(ty), + ty::local_var_name_str(self.tcx, + var_node_id)).as_slice()); + note_and_explain_region( + self.tcx, + "`proc()` is valid for ", + sub, + ""); + note_and_explain_region( + self.tcx, + format!("the type `{}` is only valid for ", + self.ty_to_string(ty)).as_slice(), + sup, + ""); + } + infer::RelateParamBound(span, param_ty, ty) => { + self.tcx.sess.span_err( + span, + format!("the type `{}` (provided as the value of \ + the parameter `{}`) does not fulfill the \ + required lifetime", + self.ty_to_string(ty), + param_ty.user_string(self.tcx)).as_slice()); + note_and_explain_region(self.tcx, + "type must outlive ", + sub, + ""); + } + infer::RelateRegionParamBound(span) => { + self.tcx.sess.span_err( + span, + "declared lifetime bound not satisfied"); + note_and_explain_region( + self.tcx, + "lifetime parameter instantiated with ", + sup, + ""); + note_and_explain_region( + self.tcx, + "but lifetime parameter must outlive ", + sub, + ""); + } + infer::RelateDefaultParamBound(span, ty) => { + self.tcx.sess.span_err( + span, + format!("the type `{}` (provided as the value of \ + a type parameter) is not valid at this point", + self.ty_to_string(ty)).as_slice()); + note_and_explain_region(self.tcx, + "type must outlive ", + sub, + ""); + } infer::CallRcvr(span) => { self.tcx.sess.span_err( span, @@ -593,6 +724,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sup, ""); } + infer::ExprTypeIsNotInScope(t, span) => { + self.tcx.sess.span_err( + span, + format!("type of expression contains references \ + that are not valid during the expression: `{}`", + self.ty_to_string(t)).as_slice()); + note_and_explain_region( + self.tcx, + "type is only valid for ", + sup, + ""); + } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_err( span, @@ -606,9 +749,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> { infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_err( span, - format!("in type `{}`, pointer has a longer lifetime than \ - the data it references", - ty.user_string(self.tcx)).as_slice()); + format!("in type `{}`, reference has a longer lifetime \ + than the data it references", + self.ty_to_string(ty)).as_slice()); note_and_explain_region( self.tcx, "the pointer is valid for ", @@ -620,6 +763,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sup, ""); } + infer::Managed(span) => { + self.tcx.sess.span_err( + span, + format!("cannot put borrowed references into managed memory").as_slice()); + } } } @@ -637,7 +785,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sup_region, "..."); - self.note_region_origin(sup_origin); + self.note_region_origin(&sup_origin); note_and_explain_region( self.tcx, @@ -645,7 +793,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { sub_region, "..."); - self.note_region_origin(sub_origin); + self.note_region_origin(&sub_origin); } fn report_sup_sup_conflict(&self, @@ -662,7 +810,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { region1, "..."); - self.note_region_origin(origin1); + self.note_region_origin(&origin1); note_and_explain_region( self.tcx, @@ -670,7 +818,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> { region2, "..."); - self.note_region_origin(origin2); + self.note_region_origin(&origin2); } fn report_processed_errors(&self, @@ -920,8 +1068,12 @@ impl<'a> Rebuilder<'a> { -> OwnedSlice { ty_param_bounds.map(|tpb| { match tpb { - &ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound, - &ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s), + &ast::RegionTyParamBound(lt) => { + // FIXME -- it's unclear whether I'm supposed to + // substitute lifetime here. I suspect we need to + // be passing down a map. + ast::RegionTyParamBound(lt) + } &ast::UnboxedFnTyParamBound(unboxed_function_type) => { ast::UnboxedFnTyParamBound(unboxed_function_type) } @@ -1291,8 +1443,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { var_description).as_slice()); } - fn note_region_origin(&self, origin: SubregionOrigin) { - match origin { + fn note_region_origin(&self, origin: &SubregionOrigin) { + match *origin { infer::Subtype(ref trace) => { let desc = match trace.origin { infer::Misc(_) => { @@ -1384,8 +1536,16 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { infer::RelateObjectBound(span) => { self.tcx.sess.span_note( span, - "...so that source pointer does not outlive \ - lifetime bound of the object type"); + "...so that it can be closed over into an object"); + } + infer::RelateProcBound(span, var_node_id, _ty) => { + self.tcx.sess.span_err( + span, + format!( + "...so that the variable `{}` can be captured \ + into a proc", + ty::local_var_name_str(self.tcx, + var_node_id)).as_slice()); } infer::CallRcvr(span) => { self.tcx.sess.span_note( @@ -1414,16 +1574,52 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { "...so that reference is valid \ at the time of implicit borrow"); } + infer::ExprTypeIsNotInScope(t, span) => { + self.tcx.sess.span_note( + span, + format!("...so type `{}` of expression is valid during the \ + expression", + self.ty_to_string(t)).as_slice()); + } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_note( span, "...so that variable is valid at time of its declaration"); } - infer::ReferenceOutlivesReferent(_, span) => { + infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_note( span, - "...so that the pointer does not outlive the \ - data it points at"); + format!("...so that the reference type `{}` \ + does not outlive the data it points at", + self.ty_to_string(ty)).as_slice()); + } + infer::Managed(span) => { + self.tcx.sess.span_note( + span, + "...so that the value can be stored in managed memory."); + } + infer::RelateParamBound(span, param_ty, t) => { + self.tcx.sess.span_note( + span, + format!("...so that the parameter `{}`, \ + when instantiated with `{}`, \ + will meet its declared lifetime bounds.", + param_ty.user_string(self.tcx), + self.ty_to_string(t)).as_slice()); + } + infer::RelateDefaultParamBound(span, t) => { + self.tcx.sess.span_note( + span, + format!("...so that type parameter \ + instantiated with `{}`, \ + will meet its declared lifetime bounds.", + self.ty_to_string(t)).as_slice()); + } + infer::RelateRegionParamBound(span) => { + self.tcx.sess.span_note( + span, + format!("...so that the declared lifetime parameter bounds \ + are satisfied").as_slice()); } } } diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index b6628c22ae6..00eaa4d235b 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -96,7 +96,10 @@ impl<'f> Combine for Glb<'f> { } } - fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres { + fn builtin_bounds(&self, + a: ty::BuiltinBounds, + b: ty::BuiltinBounds) + -> cres { // More bounds is a subtype of fewer bounds, so // the GLB (mutual subtype) is the union. Ok(a.union(b)) diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 6a50038afe7..8707efc622b 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -90,7 +90,10 @@ impl<'f> Combine for Lub<'f> { } } - fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres { + fn builtin_bounds(&self, + a: ty::BuiltinBounds, + b: ty::BuiltinBounds) + -> cres { // More bounds is a subtype of fewer bounds, so // the LUB (mutual supertype) is the intersection. Ok(a.intersection(b)) diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 5629a085500..ed96effdd83 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -168,6 +168,22 @@ pub enum SubregionOrigin { // relating `'a` to `'b` RelateObjectBound(Span), + // When closing over a variable in a closure/proc, ensure that the + // type of the variable outlives the lifetime bound. + RelateProcBound(Span, ast::NodeId, ty::t), + + // The given type parameter was instantiated with the given type, + // and that type must outlive some region. + RelateParamBound(Span, ty::ParamTy, ty::t), + + // The given region parameter was instantiated with a region + // that must outlive some other region. + RelateRegionParamBound(Span), + + // A bound placed on type parameters that states that must outlive + // the moment of their instantiation. + RelateDefaultParamBound(Span, ty::t), + // Creating a pointer `b` to contents of another reference Reborrow(Span), @@ -177,6 +193,9 @@ pub enum SubregionOrigin { // (&'a &'b T) where a >= b ReferenceOutlivesReferent(ty::t, Span), + // The type T of an expression E must outlive the lifetime for E. + ExprTypeIsNotInScope(ty::t, Span), + // A `ref b` whose region does not enclose the decl site BindingTypeIsNotValidAtDecl(Span), @@ -194,6 +213,9 @@ pub enum SubregionOrigin { // An auto-borrow that does not enclose the expr where it occurs AutoBorrow(Span), + + // Managed data cannot contain borrowed pointers. + Managed(Span), } /// Reasons to create a region inference variable @@ -336,7 +358,6 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { } pub fn mk_subr(cx: &InferCtxt, - _a_is_expected: bool, origin: SubregionOrigin, a: ty::Region, b: ty::Region) { @@ -346,6 +367,18 @@ pub fn mk_subr(cx: &InferCtxt, cx.region_vars.commit(snapshot); } +pub fn verify_param_bound(cx: &InferCtxt, + origin: SubregionOrigin, + param_ty: ty::ParamTy, + a: ty::Region, + bs: Vec) { + debug!("verify_param_bound({}, {} <: {})", + param_ty.repr(cx.tcx), + a.repr(cx.tcx), + bs.repr(cx.tcx)); + + cx.region_vars.verify_param_bound(origin, param_ty, a, bs); +} pub fn mk_eqty(cx: &InferCtxt, a_is_expected: bool, origin: TypeOrigin, @@ -589,6 +622,13 @@ impl<'a> InferCtxt<'a> { self.rollback_to(snapshot); r } + + pub fn add_given(&self, + sub: ty::FreeRegion, + sup: ty::RegionVid) + { + self.region_vars.add_given(sub, sup); + } } impl<'a> InferCtxt<'a> { @@ -687,14 +727,13 @@ impl<'a> InferCtxt<'a> { } pub fn resolve_type_vars_in_trait_ref_if_possible(&self, - trait_ref: - &ty::TraitRef) + trait_ref: &ty::TraitRef) -> ty::TraitRef { // make up a dummy type just to reuse/abuse the resolve machinery let dummy0 = ty::mk_trait(self.tcx, trait_ref.def_id, trait_ref.substs.clone(), - ty::empty_builtin_bounds()); + ty::region_existential_bound(ty::ReStatic)); let dummy1 = self.resolve_type_vars_if_possible(dummy0); match ty::get(dummy1).sty { ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => { @@ -896,15 +935,21 @@ impl SubregionOrigin { FreeVariable(a, _) => a, IndexSlice(a) => a, RelateObjectBound(a) => a, + RelateProcBound(a, _, _) => a, + RelateParamBound(a, _, _) => a, + RelateRegionParamBound(a) => a, + RelateDefaultParamBound(a, _) => a, Reborrow(a) => a, ReborrowUpvar(a, _) => a, ReferenceOutlivesReferent(_, a) => a, + ExprTypeIsNotInScope(_, a) => a, BindingTypeIsNotValidAtDecl(a) => a, CallRcvr(a) => a, CallArg(a) => a, CallReturn(a) => a, AddrOf(a) => a, AutoBorrow(a) => a, + Managed(a) => a, } } } @@ -933,6 +978,27 @@ impl Repr for SubregionOrigin { RelateObjectBound(a) => { format!("RelateObjectBound({})", a.repr(tcx)) } + RelateProcBound(a, b, c) => { + format!("RelateProcBound({},{},{})", + a.repr(tcx), + b, + c.repr(tcx)) + } + RelateParamBound(a, b, c) => { + format!("RelateParamBound({},{},{})", + a.repr(tcx), + b.repr(tcx), + c.repr(tcx)) + } + RelateRegionParamBound(a) => { + format!("RelateRegionParamBound({})", + a.repr(tcx)) + } + RelateDefaultParamBound(a, b) => { + format!("RelateDefaultParamBound({},{})", + a.repr(tcx), + b.repr(tcx)) + } Reborrow(a) => format!("Reborrow({})", a.repr(tcx)), ReborrowUpvar(a, b) => { format!("ReborrowUpvar({},{:?})", a.repr(tcx), b) @@ -940,6 +1006,11 @@ impl Repr for SubregionOrigin { ReferenceOutlivesReferent(_, a) => { format!("ReferenceOutlivesReferent({})", a.repr(tcx)) } + ExprTypeIsNotInScope(a, b) => { + format!("ExprTypeIsNotInScope({}, {})", + a.repr(tcx), + b.repr(tcx)) + } BindingTypeIsNotValidAtDecl(a) => { format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx)) } @@ -948,6 +1019,7 @@ impl Repr for SubregionOrigin { CallReturn(a) => format!("CallReturn({})", a.repr(tcx)), AddrOf(a) => format!("AddrOf({})", a.repr(tcx)), AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)), + Managed(a) => format!("Managed({})", a.repr(tcx)), } } } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index dc674da38af..7c8d10dd994 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -30,12 +30,32 @@ use syntax::ast; mod doc; +// A constraint that influences the inference process. #[deriving(PartialEq, Eq, Hash)] pub enum Constraint { + // One region variable is subregion of another ConstrainVarSubVar(RegionVid, RegionVid), + + // Concrete region is subregion of region variable ConstrainRegSubVar(Region, RegionVid), + + // Region variable is subregion of concrete region ConstrainVarSubReg(RegionVid, Region), - ConstrainRegSubReg(Region, Region), +} + +// Something we have to verify after region inference is done, but +// which does not directly influence the inference process +pub enum Verify { + // VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor + // `b` are inference variables. + VerifyRegSubReg(SubregionOrigin, Region, Region), + + // VerifyParamBound(T, _, R, RS): The parameter type `T` must + // outlive the region `R`. `T` is known to outlive `RS`. Therefore + // verify that `R <= RS[i]` for some `i`. Inference variables may + // be involved (but this verification step doesn't influence + // inference). + VerifyParamBound(ty::ParamTy, SubregionOrigin, Region, Vec), } #[deriving(PartialEq, Eq, Hash)] @@ -51,6 +71,8 @@ pub enum UndoLogEntry { Mark, AddVar(RegionVid), AddConstraint(Constraint), + AddVerify(uint), + AddGiven(ty::FreeRegion, ty::RegionVid), AddCombination(CombineMapType, TwoRegions) } @@ -66,6 +88,13 @@ pub enum RegionResolutionError { /// `o` requires that `a <= b`, but this does not hold ConcreteFailure(SubregionOrigin, Region, Region), + /// `ParamBoundFailure(p, s, a, bs) + /// + /// The parameter type `p` must be known to outlive the lifetime + /// `a`, but it is only known to outlive `bs` (and none of the + /// regions in `bs` outlive `a`). + ParamBoundFailure(SubregionOrigin, ty::ParamTy, Region, Vec), + /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// /// Could not infer a value for `v` because `sub_r <= v` (due to @@ -125,7 +154,38 @@ pub type CombineMap = HashMap; pub struct RegionVarBindings<'a> { tcx: &'a ty::ctxt, var_origins: RefCell>, + + // 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>, + + // 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>, + + // 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>, + lubs: RefCell, glbs: RefCell, skolemization_count: Cell, @@ -164,6 +224,8 @@ impl<'a> RegionVarBindings<'a> { var_origins: RefCell::new(Vec::new()), values: RefCell::new(None), constraints: RefCell::new(HashMap::new()), + verifys: RefCell::new(Vec::new()), + givens: RefCell::new(HashSet::new()), lubs: RefCell::new(HashMap::new()), glbs: RefCell::new(HashMap::new()), skolemization_count: Cell::new(0), @@ -216,12 +278,19 @@ impl<'a> RegionVarBindings<'a> { Mark | CommitedSnapshot => { } AddVar(vid) => { let mut var_origins = self.var_origins.borrow_mut(); - assert_eq!(var_origins.len(), vid.index + 1); var_origins.pop().unwrap(); + assert_eq!(var_origins.len(), vid.index); } AddConstraint(ref constraint) => { self.constraints.borrow_mut().remove(constraint); } + AddVerify(index) => { + self.verifys.borrow_mut().pop(); + assert_eq!(self.verifys.borrow().len(), index); + } + AddGiven(sub, sup) => { + self.givens.borrow_mut().remove(&(sub, sup)); + } AddCombination(Glb, ref regions) => { self.glbs.borrow_mut().remove(regions); } @@ -289,13 +358,14 @@ impl<'a> RegionVarBindings<'a> { self.values.borrow().is_none() } - pub fn add_constraint(&self, - constraint: Constraint, - origin: SubregionOrigin) { + fn add_constraint(&self, + constraint: Constraint, + origin: SubregionOrigin) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); - debug!("RegionVarBindings: add_constraint({:?})", constraint); + debug!("RegionVarBindings: add_constraint({})", + constraint.repr(self.tcx)); if self.constraints.borrow_mut().insert(constraint, origin) { if self.in_snapshot() { @@ -304,6 +374,38 @@ impl<'a> RegionVarBindings<'a> { } } + fn add_verify(&self, + verify: Verify) { + // cannot add verifys once regions are resolved + assert!(self.values_are_none()); + + debug!("RegionVarBindings: add_verify({})", + verify.repr(self.tcx)); + + let mut verifys = self.verifys.borrow_mut(); + let index = verifys.len(); + verifys.push(verify); + if self.in_snapshot() { + self.undo_log.borrow_mut().push(AddVerify(index)); + } + } + + pub fn add_given(&self, + sub: ty::FreeRegion, + sup: ty::RegionVid) { + // cannot add givens once regions are resolved + assert!(self.values_are_none()); + + let mut givens = self.givens.borrow_mut(); + if givens.insert((sub, sup)) { + debug!("add_given({} <= {})", + sub.repr(self.tcx), + sup); + + self.undo_log.borrow_mut().push(AddGiven(sub, sup)); + } + } + pub fn make_subregion(&self, origin: SubregionOrigin, sub: Region, @@ -320,7 +422,9 @@ impl<'a> RegionVarBindings<'a> { (ReEarlyBound(..), ReEarlyBound(..)) => { // This case is used only to make sure that explicitly-specified // `Self` types match the real self type in implementations. - self.add_constraint(ConstrainRegSubReg(sub, sup), origin); + // + // FIXME(NDM) -- we really shouldn't be comparing bound things + self.add_verify(VerifyRegSubReg(origin, sub, sup)); } (ReEarlyBound(..), _) | (ReLateBound(..), _) | @@ -345,11 +449,19 @@ impl<'a> RegionVarBindings<'a> { self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } _ => { - self.add_constraint(ConstrainRegSubReg(sub, sup), origin); + self.add_verify(VerifyRegSubReg(origin, sub, sup)); } } } + pub fn verify_param_bound(&self, + origin: SubregionOrigin, + param_ty: ty::ParamTy, + sub: Region, + sups: Vec) { + self.add_verify(VerifyParamBound(param_ty, origin, sub, sups)); + } + pub fn lub_regions(&self, origin: SubregionOrigin, a: Region, @@ -358,7 +470,9 @@ impl<'a> RegionVarBindings<'a> { // cannot add constraints once regions are resolved assert!(self.values_are_none()); - debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); + debug!("RegionVarBindings: lub_regions({}, {})", + a.repr(self.tcx), + b.repr(self.tcx)); match (a, b) { (ReStatic, _) | (_, ReStatic) => { ReStatic // nothing lives longer than static @@ -381,7 +495,9 @@ impl<'a> RegionVarBindings<'a> { // cannot add constraints once regions are resolved assert!(self.values_are_none()); - debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); + debug!("RegionVarBindings: glb_regions({}, {})", + a.repr(self.tcx), + b.repr(self.tcx)); match (a, b) { (ReStatic, r) | (r, ReStatic) => { // static lives longer than everything else @@ -397,30 +513,29 @@ impl<'a> RegionVarBindings<'a> { } } + pub fn max_regions(&self, + a: Region, + b: Region) + -> Option + { + match self.glb_concrete_regions(a, b) { + Ok(r) => Some(r), + Err(_) => None + } + } + pub fn resolve_var(&self, rid: RegionVid) -> ty::Region { - let v = match *self.values.borrow() { + match *self.values.borrow() { None => { self.tcx.sess.span_bug( self.var_origins.borrow().get(rid.index).span(), "attempt to resolve region variable before values have \ been computed!") } - Some(ref values) => *values.get(rid.index) - }; - - debug!("RegionVarBindings: resolve_var({:?}={})={:?}", - rid, rid.index, v); - match v { - Value(r) => r, - - NoValue => { - // No constraints, return ty::ReEmpty - ReEmpty - } - - ErrorValue => { - // An error that has previously been reported. - ReStatic + Some(ref values) => { + let r = lookup(values, rid); + debug!("resolve_var({}) = {}", rid, r.repr(self.tcx)); + r } } } @@ -456,7 +571,7 @@ impl<'a> RegionVarBindings<'a> { } relate(self, a, ReInfer(ReVar(c))); relate(self, b, ReInfer(ReVar(c))); - debug!("combine_vars() c={:?}", c); + debug!("combine_vars() c={}", c); ReInfer(ReVar(c)) } @@ -493,40 +608,53 @@ impl<'a> RegionVarBindings<'a> { while result_index < result_set.len() { // nb: can't use uint::range() here because result_set grows let r = *result_set.get(result_index); - debug!("result_index={}, r={:?}", result_index, r); + debug!("result_index={}, r={}", result_index, r); for undo_entry in self.undo_log.borrow().slice_from(mark.length).iter() { - let regs = match undo_entry { - &AddConstraint(ConstrainVarSubVar(ref a, ref b)) => { - Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b)))) + match undo_entry { + &AddConstraint(ConstrainVarSubVar(a, b)) => { + consider_adding_bidirectional_edges( + &mut result_set, r, + ReInfer(ReVar(a)), ReInfer(ReVar(b))); } - &AddConstraint(ConstrainRegSubVar(ref a, ref b)) => { - Some((*a, ReInfer(ReVar(*b)))) + &AddConstraint(ConstrainRegSubVar(a, b)) => { + consider_adding_bidirectional_edges( + &mut result_set, r, + a, ReInfer(ReVar(b))); } - &AddConstraint(ConstrainVarSubReg(ref a, ref b)) => { - Some((ReInfer(ReVar(*a)), *b)) + &AddConstraint(ConstrainVarSubReg(a, b)) => { + consider_adding_bidirectional_edges( + &mut result_set, r, + ReInfer(ReVar(a)), b); } - &AddConstraint(ConstrainRegSubReg(a, b)) => { - Some((a, b)) + &AddGiven(a, b) => { + consider_adding_bidirectional_edges( + &mut result_set, r, + ReFree(a), ReInfer(ReVar(b))); + } + &AddVerify(i) => { + match self.verifys.borrow().get(i) { + &VerifyRegSubReg(_, a, b) => { + consider_adding_bidirectional_edges( + &mut result_set, r, + a, b); + } + &VerifyParamBound(_, _, a, ref bs) => { + for &b in bs.iter() { + consider_adding_bidirectional_edges( + &mut result_set, r, + a, b); + } + } + } } &AddCombination(..) | &Mark | &AddVar(..) | &OpenSnapshot | &CommitedSnapshot => { - None - } - }; - - match regs { - None => {} - Some((r1, r2)) => { - result_set = - consider_adding_edge(result_set, r, r1, r2); - result_set = - consider_adding_edge(result_set, r, r2, r1); } } } @@ -536,17 +664,24 @@ impl<'a> RegionVarBindings<'a> { return result_set; - fn consider_adding_edge(result_set: Vec , - r: Region, - r1: Region, - r2: Region) -> Vec { - let mut result_set = result_set; - if r == r1 { // Clearly, this is potentially inefficient. + fn consider_adding_bidirectional_edges(result_set: &mut Vec, + r: Region, + r1: Region, + r2: Region) { + consider_adding_directed_edge(result_set, r, r1, r2); + consider_adding_directed_edge(result_set, r, r2, r1); + } + + fn consider_adding_directed_edge(result_set: &mut Vec, + r: Region, + r1: Region, + r2: Region) { + if r == r1 { + // Clearly, this is potentially inefficient. if !result_set.iter().any(|x| *x == r2) { result_set.push(r2); } } - return result_set; } } @@ -595,7 +730,7 @@ impl<'a> RegionVarBindings<'a> { self.tcx.sess.span_bug( self.var_origins.borrow().get(v_id.index).span(), format!("lub_concrete_regions invoked with \ - non-concrete regions: {:?}, {:?}", + non-concrete regions: {}, {}", a, b).as_slice()); } @@ -675,7 +810,7 @@ impl<'a> RegionVarBindings<'a> { a: Region, b: Region) -> cres { - debug!("glb_concrete_regions({:?}, {:?})", a, b); + debug!("glb_concrete_regions({}, {})", a, b); match (a, b) { (ReLateBound(..), _) | (_, ReLateBound(..)) | @@ -702,7 +837,7 @@ impl<'a> RegionVarBindings<'a> { self.tcx.sess.span_bug( self.var_origins.borrow().get(v_id.index).span(), format!("glb_concrete_regions invoked with \ - non-concrete regions: {:?}, {:?}", + non-concrete regions: {}, {}", a, b).as_slice()); } @@ -783,7 +918,7 @@ impl<'a> RegionVarBindings<'a> { // scopes or two free regions. So, if one of // these scopes is a subscope of the other, return // it. Otherwise fail. - debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})", + debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})", scope_a, scope_b, region_a, region_b); match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) { Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)), @@ -815,12 +950,16 @@ type RegionGraph = graph::Graph<(), Constraint>; impl<'a> RegionVarBindings<'a> { fn infer_variable_values(&self, errors: &mut Vec) - -> Vec { + -> Vec + { let mut var_data = self.construct_var_data(); self.expansion(var_data.as_mut_slice()); self.contraction(var_data.as_mut_slice()); - self.collect_concrete_region_errors(&mut *errors); - self.extract_values_and_collect_conflicts(var_data.as_slice(), errors) + let values = + self.extract_values_and_collect_conflicts(var_data.as_slice(), + errors); + self.collect_concrete_region_errors(&values, errors); + values } fn construct_var_data(&self) -> Vec { @@ -838,6 +977,12 @@ impl<'a> RegionVarBindings<'a> { fn expansion(&self, var_data: &mut [VarData]) { self.iterate_until_fixed_point("Expansion", |constraint| { + debug!("expansion: constraint={} origin={}", + constraint.repr(self.tcx), + self.constraints.borrow() + .find(constraint) + .unwrap() + .repr(self.tcx)); match *constraint { ConstrainRegSubVar(a_region, b_vid) => { let b_data = &mut var_data[b_vid.index]; @@ -856,10 +1001,6 @@ impl<'a> RegionVarBindings<'a> { // This is a contraction constraint. Ignore it. false } - ConstrainRegSubReg(..) => { - // No region variables involved. Ignore. - false - } } }) } @@ -868,14 +1009,29 @@ impl<'a> RegionVarBindings<'a> { a_region: Region, b_vid: RegionVid, b_data: &mut VarData) - -> bool { - debug!("expand_node({:?}, {:?} == {:?})", - a_region, b_vid, b_data.value); + -> bool + { + debug!("expand_node({}, {} == {})", + a_region.repr(self.tcx), + b_vid, + b_data.value.repr(self.tcx)); + + // Check if this relationship is implied by a given. + match a_region { + ty::ReFree(fr) => { + if self.givens.borrow().contains(&(fr, b_vid)) { + debug!("given"); + return false; + } + } + _ => { } + } b_data.classification = Expanding; match b_data.value { NoValue => { - debug!("Setting initial value of {:?} to {:?}", b_vid, a_region); + debug!("Setting initial value of {} to {}", + b_vid, a_region.repr(self.tcx)); b_data.value = Value(a_region); return true; @@ -887,8 +1043,10 @@ impl<'a> RegionVarBindings<'a> { return false; } - debug!("Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub); + debug!("Expanding value of {} from {} to {}", + b_vid, + cur_region.repr(self.tcx), + lub.repr(self.tcx)); b_data.value = Value(lub); return true; @@ -903,6 +1061,12 @@ impl<'a> RegionVarBindings<'a> { fn contraction(&self, var_data: &mut [VarData]) { self.iterate_until_fixed_point("Contraction", |constraint| { + debug!("contraction: constraint={} origin={}", + constraint.repr(self.tcx), + self.constraints.borrow() + .find(constraint) + .unwrap() + .repr(self.tcx)); match *constraint { ConstrainRegSubVar(..) => { // This is an expansion constraint. Ignore. @@ -921,10 +1085,6 @@ impl<'a> RegionVarBindings<'a> { let a_data = &mut var_data[a_vid.index]; self.contract_node(a_vid, a_data, b_region) } - ConstrainRegSubReg(..) => { - // No region variables involved. Ignore. - false - } } }) } @@ -934,8 +1094,9 @@ impl<'a> RegionVarBindings<'a> { a_data: &mut VarData, b_region: Region) -> bool { - debug!("contract_node({:?} == {:?}/{:?}, {:?})", - a_vid, a_data.value, a_data.classification, b_region); + debug!("contract_node({} == {}/{}, {})", + a_vid, a_data.value.repr(self.tcx), + a_data.classification, b_region.repr(self.tcx)); return match a_data.value { NoValue => { @@ -967,8 +1128,10 @@ impl<'a> RegionVarBindings<'a> { b_region: Region) -> bool { if !this.is_subregion_of(a_region, b_region) { - debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}", - a_vid, a_region, b_region); + debug!("Setting {} to ErrorValue: {} not subregion of {}", + a_vid, + a_region.repr(this.tcx), + b_region.repr(this.tcx)); a_data.value = ErrorValue; } false @@ -985,15 +1148,19 @@ impl<'a> RegionVarBindings<'a> { if glb == a_region { false } else { - debug!("Contracting value of {:?} from {:?} to {:?}", - a_vid, a_region, glb); + debug!("Contracting value of {} from {} to {}", + a_vid, + a_region.repr(this.tcx), + glb.repr(this.tcx)); a_data.value = Value(glb); true } } Err(_) => { - debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}", - a_vid, a_region, b_region); + debug!("Setting {} to ErrorValue: no glb of {}, {}", + a_vid, + a_region.repr(this.tcx), + b_region.repr(this.tcx)); a_data.value = ErrorValue; false } @@ -1001,30 +1168,44 @@ impl<'a> RegionVarBindings<'a> { } } - fn collect_concrete_region_errors( - &self, - errors: &mut Vec) + fn collect_concrete_region_errors(&self, + values: &Vec, + errors: &mut Vec) { - for (constraint, _) in self.constraints.borrow().iter() { - let (sub, sup) = match *constraint { - ConstrainVarSubVar(..) | - ConstrainRegSubVar(..) | - ConstrainVarSubReg(..) => { - continue; - } - ConstrainRegSubReg(sub, sup) => { - (sub, sup) - } - }; + let mut reg_reg_dups = HashSet::new(); + for verify in self.verifys.borrow().iter() { + match *verify { + VerifyRegSubReg(ref origin, sub, sup) => { + if self.is_subregion_of(sub, sup) { + continue; + } - if self.is_subregion_of(sub, sup) { - continue; + if !reg_reg_dups.insert((sub, sup)) { + continue; + } + + debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}", + sub.repr(self.tcx), + sup.repr(self.tcx)); + errors.push(ConcreteFailure((*origin).clone(), sub, sup)); + } + + VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => { + let sub = normalize(values, sub); + if sups.iter() + .map(|&sup| normalize(values, sup)) + .any(|sup| self.is_subregion_of(sub, sup)) + { + continue; + } + + let sups = sups.iter().map(|&sup| normalize(values, sup)) + .collect(); + errors.push( + ParamBoundFailure( + (*origin).clone(), *param_ty, sub, sups)); + } } - - debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}", - sub, sup); - let origin = self.constraints.borrow().get_copy(constraint); - errors.push(ConcreteFailure(origin, sub, sup)); } } @@ -1032,7 +1213,8 @@ impl<'a> RegionVarBindings<'a> { &self, var_data: &[VarData], errors: &mut Vec) - -> Vec { + -> Vec + { debug!("extract_values_and_collect_conflicts()"); // This is the best way that I have found to suppress @@ -1141,10 +1323,6 @@ impl<'a> RegionVarBindings<'a> { dummy_idx, *constraint); } - ConstrainRegSubReg(..) => { - // Relations between two concrete regions do not - // require an edge in the graph. - } } } @@ -1206,16 +1384,10 @@ impl<'a> RegionVarBindings<'a> { self.tcx.sess.span_bug( self.var_origins.borrow().get(node_idx.index).span(), format!("collect_error_for_expanding_node() could not find error \ - for var {:?}, lower_bounds={}, upper_bounds={}", - node_idx, - lower_bounds.iter() - .map(|x| x.region) - .collect::>() - .repr(self.tcx), - upper_bounds.iter() - .map(|x| x.region) - .collect::>() - .repr(self.tcx)).as_slice()); + for var {}, lower_bounds={}, upper_bounds={}", + node_idx, + lower_bounds.repr(self.tcx), + upper_bounds.repr(self.tcx)).as_slice()); } fn collect_error_for_contracting_node( @@ -1257,12 +1429,9 @@ impl<'a> RegionVarBindings<'a> { self.tcx.sess.span_bug( self.var_origins.borrow().get(node_idx.index).span(), format!("collect_error_for_contracting_node() could not find error \ - for var {:?}, upper_bounds={}", - node_idx, - upper_bounds.iter() - .map(|x| x.region) - .collect::>() - .repr(self.tcx)).as_slice()); + for var {}, upper_bounds={}", + node_idx, + upper_bounds.repr(self.tcx)).as_slice()); } fn collect_concrete_regions(&self, @@ -1301,8 +1470,8 @@ impl<'a> RegionVarBindings<'a> { state.dup_found = true; } - debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \ - classification={:?})", + debug!("collect_concrete_regions(orig_node_idx={}, node_idx={}, \ + classification={})", orig_node_idx, node_idx, classification); // figure out the direction from which this node takes its @@ -1323,7 +1492,7 @@ impl<'a> RegionVarBindings<'a> { graph: &RegionGraph, source_vid: RegionVid, dir: Direction) { - debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); + debug!("process_edges(source_vid={}, dir={})", source_vid, dir); let source_node_index = NodeIndex(source_vid.index); graph.each_adjacent_edge(source_node_index, dir, |_, edge| { @@ -1343,8 +1512,6 @@ impl<'a> RegionVarBindings<'a> { origin: this.constraints.borrow().get_copy(&edge.data) }); } - - ConstrainRegSubReg(..) => {} } true }); @@ -1386,9 +1553,53 @@ impl Repr for Constraint { ConstrainVarSubReg(a, b) => { format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx)) } - ConstrainRegSubReg(a, b) => { - format!("ConstrainRegSubReg({}, {})", a.repr(tcx), b.repr(tcx)) + } + } +} + +impl Repr for Verify { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + VerifyRegSubReg(_, ref a, ref b) => { + format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx)) + } + VerifyParamBound(_, ref p, ref a, ref bs) => { + format!("VerifyParamBound({}, {}, {})", + p.repr(tcx), a.repr(tcx), bs.repr(tcx)) } } } } + +fn normalize(values: &Vec, r: ty::Region) -> ty::Region { + match r { + ty::ReInfer(ReVar(rid)) => lookup(values, rid), + _ => r + } +} + +fn lookup(values: &Vec, 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)) + } +} diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index a54afb1102f..a9e8d1e8603 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -102,7 +102,8 @@ impl<'f> Combine for Sub<'f> { }) } - fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres { + fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds) + -> cres { // More bounds is a subtype of fewer bounds. // // e.g., fn:Copy() <: fn(), because the former is a function diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 44afc04d3f0..33bdded5234 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -555,3 +555,12 @@ impl SimplyUnifiable for ast::FloatTy { return ty::terr_float_mismatch(err); } } + +impl Repr for VarValue { + 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) + } + } +} diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index cdb691073cd..530f65855d4 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -30,12 +30,19 @@ pub trait RegionScope { span: Span, count: uint) -> Result , ()>; + + fn default_region_bound(&self, span: Span) -> Option; } -// A scope in which all regions must be explicitly named +// A scope in which all regions must be explicitly named. This is used +// for types that appear in structs and so on. pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { + fn default_region_bound(&self, _span: Span) -> Option { + None + } + fn anon_regions(&self, _span: Span, _count: uint) @@ -44,6 +51,33 @@ impl RegionScope for ExplicitRscope { } } +// A scope in which any omitted region defaults to `default`. This is +// used after the `->` in function signatures, but also for backwards +// compatibility with object types. The latter use may go away. +pub struct SpecificRscope { + default: ty::Region +} + +impl SpecificRscope { + pub fn new(r: ty::Region) -> SpecificRscope { + SpecificRscope { default: r } + } +} + +impl RegionScope for SpecificRscope { + fn default_region_bound(&self, _span: Span) -> Option { + Some(self.default) + } + + fn anon_regions(&self, + _span: Span, + count: uint) + -> Result , ()> + { + Ok(Vec::from_elem(count, self.default)) + } +} + /// A scope in which we generate anonymous, late-bound regions for /// omitted regions. This occurs in function signatures. pub struct BindingRscope { @@ -58,30 +92,26 @@ impl BindingRscope { anon_bindings: Cell::new(0), } } + + fn next_region(&self) -> ty::Region { + let idx = self.anon_bindings.get(); + self.anon_bindings.set(idx + 1); + ty::ReLateBound(self.binder_id, ty::BrAnon(idx)) + } } impl RegionScope for BindingRscope { + fn default_region_bound(&self, _span: Span) -> Option + { + Some(self.next_region()) + } + fn anon_regions(&self, _: Span, count: uint) - -> Result, ()> { - let idx = self.anon_bindings.get(); - self.anon_bindings.set(idx + count); - Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id, - ty::BrAnon(idx + i)))) - } -} - -/// A scope in which we generate one specific region. This occurs after the -/// `->` (i.e. in the return type) of function signatures. -pub struct ImpliedSingleRscope { - pub region: ty::Region, -} - -impl RegionScope for ImpliedSingleRscope { - fn anon_regions(&self, _: Span, count: uint) - -> Result,()> { - Ok(Vec::from_elem(count, self.region.clone())) + -> Result , ()> + { + Ok(Vec::from_fn(count, |_| self.next_region())) } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 9c9942d2628..61ef9df99e8 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -10,6 +10,8 @@ #![allow(non_camel_case_types)] +use std::hash::{Hash, Hasher}; +use std::collections::HashMap; use syntax::ast; use syntax::visit; use syntax::visit::Visitor; @@ -105,3 +107,51 @@ pub fn block_query(b: ast::P, p: |&ast::Expr| -> bool) -> bool { visit::walk_block(&mut v, &*b, ()); return v.flag; } + +// K: Eq + Hash, V, S, H: Hasher +pub fn can_reach,T:Eq+Clone+Hash>( + edges_map: &HashMap,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; +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 5dff183108c..11f16f1ea95 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -23,11 +23,9 @@ use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; -use middle::typeck::infer::region_inference; -use middle::typeck::infer::unify::VarValue as VV; -use middle::typeck::infer::unify; -use middle::typeck::infer; use middle::typeck; +use middle::typeck::check::regionmanip; +use middle::typeck::infer; use std::gc::Gc; use std::rc::Rc; @@ -66,6 +64,22 @@ pub fn note_and_explain_region(cx: &ctxt, } } +fn item_scope_tag(item: &ast::Item) -> &'static str { + /*! + * When a free region is associated with `item`, how should we describe + * the item in the error message. + */ + + match item.node { + ast::ItemImpl(..) => "impl", + ast::ItemStruct(..) => "struct", + ast::ItemEnum(..) => "enum", + ast::ItemTrait(..) => "trait", + ast::ItemFn(..) => "function body", + _ => "item" + } +} + pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) -> (String, Option) { return match region { @@ -87,9 +101,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) Some(ast_map::NodeStmt(stmt)) => { explain_span(cx, "statement", stmt.span) } - Some(ast_map::NodeItem(it)) if (match it.node { - ast::ItemFn(..) => true, _ => false}) => { - explain_span(cx, "function body", it.span) + Some(ast_map::NodeItem(it)) => { + let tag = item_scope_tag(&*it); + explain_span(cx, tag, it.span) } Some(_) | None => { // this really should not happen @@ -112,17 +126,17 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) match cx.map.find(fr.scope_id) { Some(ast_map::NodeBlock(ref blk)) => { - let (msg, opt_span) = explain_span(cx, "block", blk.span); - (format!("{} {}", prefix, msg), opt_span) + let (msg, opt_span) = explain_span(cx, "block", blk.span); + (format!("{} {}", prefix, msg), opt_span) } - Some(ast_map::NodeItem(it)) if match it.node { - ast::ItemImpl(..) => true, _ => false} => { - let (msg, opt_span) = explain_span(cx, "impl", it.span); - (format!("{} {}", prefix, msg), opt_span) + Some(ast_map::NodeItem(it)) => { + let tag = item_scope_tag(&*it); + let (msg, opt_span) = explain_span(cx, tag, it.span); + (format!("{} {}", prefix, msg), opt_span) } Some(_) | None => { - // this really should not happen - (format!("{} node {}", prefix, fr.scope_id), None) + // this really should not happen + (format!("{} node {}", prefix, fr.scope_id), None) } } } @@ -143,7 +157,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) }; fn explain_span(cx: &ctxt, heading: &str, span: Span) - -> (String, Option) { + -> (String, Option) { let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo); (format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()), Some(span)) @@ -273,7 +287,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { _ => { } } - push_sig_to_string(cx, &mut s, '(', ')', sig); + push_sig_to_string(cx, &mut s, '(', ')', sig, ""); s } @@ -296,34 +310,34 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } }; + let bounds_str = cty.bounds.user_string(cx); + match cty.store { ty::UniqTraitStore => { assert_eq!(cty.onceness, ast::Once); s.push_str("proc"); - push_sig_to_string(cx, &mut s, '(', ')', &cty.sig); + push_sig_to_string(cx, &mut s, '(', ')', &cty.sig, + bounds_str.as_slice()); } ty::RegionTraitStore(..) => { match cty.onceness { ast::Many => {} ast::Once => s.push_str("once ") } - push_sig_to_string(cx, &mut s, '|', '|', &cty.sig); + push_sig_to_string(cx, &mut s, '|', '|', &cty.sig, + bounds_str.as_slice()); } } - if !cty.bounds.is_empty() { - s.push_str(":"); - s.push_str(cty.bounds.repr(cx).as_slice()); - } - - s + s.into_owned() } fn push_sig_to_string(cx: &ctxt, s: &mut String, bra: char, ket: char, - sig: &ty::FnSig) { + sig: &ty::FnSig, + bounds: &str) { s.push_char(bra); let strs: Vec = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect(); s.push_str(strs.connect(", ").as_slice()); @@ -332,6 +346,11 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } s.push_char(ket); + if !bounds.is_empty() { + s.push_str(":"); + s.push_str(bounds); + } + if ty::get(sig.output).sty != ty_nil { s.push_str(" -> "); if ty::type_is_bot(sig.output) { @@ -383,18 +402,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } ty_infer(infer_ty) => infer_ty.to_string(), ty_err => "[type error]".to_string(), - ty_param(ParamTy {idx: id, def_id: did, ..}) => { - let ident = match cx.ty_param_defs.borrow().find(&did.node) { - Some(def) => token::get_ident(def.ident).get().to_string(), - // This can only happen when a type mismatch error happens and - // the actual type has more type parameters than the expected one. - None => format!("", id), - }; - if !cx.sess.verbose() { - ident - } else { - format!("{}:{:?}", ident, did) - } + ty_param(ref param_ty) => { + param_ty.repr(cx) } ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let base = ty::item_path_str(cx, did); @@ -408,8 +417,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { let trait_def = ty::lookup_trait_def(cx, did); let ty = parameterized(cx, base.as_slice(), substs, &trait_def.generics); - let bound_sep = if bounds.is_empty() { "" } else { "+" }; - let bound_str = bounds.repr(cx); + let bound_str = bounds.user_string(cx); + let bound_sep = if bound_str.is_empty() { "" } else { "+" }; format!("{}{}{}", ty, bound_sep, @@ -573,6 +582,14 @@ impl Repr for Vec { } } +impl UserString for Vec { + fn user_string(&self, tcx: &ctxt) -> String { + let strs: Vec = + self.iter().map(|t| t.user_string(tcx)).collect(); + strs.connect(", ") + } +} + impl Repr for def::Def { fn repr(&self, _tcx: &ctxt) -> String { format!("{:?}", *self) @@ -581,16 +598,18 @@ impl Repr for def::Def { impl Repr for ty::TypeParameterDef { fn repr(&self, tcx: &ctxt) -> String { - format!("TypeParameterDef({:?}, {})", self.def_id, + format!("TypeParameterDef({}, {})", + self.def_id.repr(tcx), self.bounds.repr(tcx)) } } impl Repr for ty::RegionParameterDef { - fn repr(&self, _tcx: &ctxt) -> String { - format!("RegionParameterDef({}, {:?})", + fn repr(&self, tcx: &ctxt) -> String { + format!("RegionParameterDef(name={}, def_id={}, bounds={})", token::get_name(self.name), - self.def_id) + self.def_id.repr(tcx), + self.bounds.repr(tcx)) } } @@ -638,18 +657,31 @@ impl Repr for subst::RegionSubsts { } } +impl Repr for ty::BuiltinBounds { + fn repr(&self, _tcx: &ctxt) -> String { + let mut res = Vec::new(); + for b in self.iter() { + res.push(match b { + ty::BoundSend => "Send".to_owned(), + ty::BoundSized => "Sized".to_owned(), + ty::BoundCopy => "Copy".to_owned(), + ty::BoundSync => "Sync".to_owned(), + }); + } + res.connect("+") + } +} + +impl Repr for ty::ExistentialBounds { + fn repr(&self, tcx: &ctxt) -> String { + self.user_string(tcx) + } +} + impl Repr for ty::ParamBounds { fn repr(&self, tcx: &ctxt) -> String { let mut res = Vec::new(); - for b in self.builtin_bounds.iter() { - res.push(match b { - ty::BoundStatic => "'static".to_string(), - ty::BoundSend => "Send".to_string(), - ty::BoundSized => "Sized".to_string(), - ty::BoundCopy => "Copy".to_string(), - ty::BoundSync => "Sync".to_string(), - }); - } + res.push(self.builtin_bounds.repr(tcx)); for t in self.trait_bounds.iter() { res.push(t.repr(tcx)); } @@ -663,6 +695,15 @@ impl Repr for ty::TraitRef { } } +impl Repr for ty::TraitDef { + fn repr(&self, tcx: &ctxt) -> String { + format!("TraitDef(generics={}, bounds={}, trait_ref={})", + self.generics.repr(tcx), + self.bounds.repr(tcx), + self.trait_ref.repr(tcx)) + } +} + impl Repr for ast::Expr { fn repr(&self, _tcx: &ctxt) -> String { format!("expr({}: {})", self.id, pprust::expr_to_string(self)) @@ -675,12 +716,24 @@ impl Repr for ast::Path { } } +impl UserString for ast::Path { + fn user_string(&self, _tcx: &ctxt) -> String { + pprust::path_to_string(self) + } +} + impl Repr for ast::Item { fn repr(&self, tcx: &ctxt) -> String { format!("item({})", tcx.map.node_to_string(self.id)) } } +impl Repr for ast::Lifetime { + fn repr(&self, _tcx: &ctxt) -> String { + format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self)) + } +} + impl Repr for ast::Stmt { fn repr(&self, _tcx: &ctxt) -> String { format!("stmt({}: {})", @@ -724,11 +777,7 @@ impl Repr for ty::Region { bound_region.repr(tcx)) } - ty::ReFree(ref fr) => { - format!("ReFree({}, {})", - fr.scope_id, - fr.bound_region.repr(tcx)) - } + ty::ReFree(ref fr) => fr.repr(tcx), ty::ReScope(id) => { format!("ReScope({})", id) @@ -753,6 +802,20 @@ impl Repr for ty::Region { } } +impl UserString for ty::Region { + fn user_string(&self, tcx: &ctxt) -> String { + region_to_string(tcx, "", false, *self) + } +} + +impl Repr for ty::FreeRegion { + fn repr(&self, tcx: &ctxt) -> String { + format!("ReFree({}, {})", + self.scope_id, + self.bound_region.repr(tcx)) + } +} + impl Repr for ast::DefId { fn repr(&self, tcx: &ctxt) -> String { // Unfortunately, there seems to be no way to attempt to print @@ -833,6 +896,12 @@ impl Repr for ast::Name { } } +impl UserString for ast::Name { + fn user_string(&self, _tcx: &ctxt) -> String { + token::get_name(*self).get().to_string() + } +} + impl Repr for ast::Ident { fn repr(&self, _tcx: &ctxt) -> String { token::get_ident(*self).get().to_string() @@ -928,21 +997,14 @@ impl Repr for ty::BuiltinBound { impl UserString for ty::BuiltinBound { fn user_string(&self, _tcx: &ctxt) -> String { match *self { - ty::BoundStatic => "'static".to_string(), - ty::BoundSend => "Send".to_string(), - ty::BoundSized => "Sized".to_string(), - ty::BoundCopy => "Copy".to_string(), - ty::BoundSync => "Sync".to_string(), + ty::BoundSend => "Send".to_owned(), + ty::BoundSized => "Sized".to_owned(), + ty::BoundCopy => "Copy".to_owned(), + ty::BoundSync => "Sync".to_owned(), } } } -impl Repr for ty::BuiltinBounds { - fn repr(&self, tcx: &ctxt) -> String { - self.user_string(tcx) - } -} - impl Repr for Span { fn repr(&self, tcx: &ctxt) -> String { tcx.sess.codemap().span_to_string(*self).to_string() @@ -956,6 +1018,43 @@ impl UserString for Rc { } } +impl UserString for ty::ParamBounds { + fn user_string(&self, tcx: &ctxt) -> String { + let mut result = Vec::new(); + let s = self.builtin_bounds.user_string(tcx); + if !s.is_empty() { + result.push(s); + } + for n in self.trait_bounds.iter() { + result.push(n.user_string(tcx)); + } + result.connect("+") + } +} + +impl UserString for ty::ExistentialBounds { + fn user_string(&self, tcx: &ctxt) -> String { + if self.builtin_bounds.contains_elem(ty::BoundSend) && + self.region_bound == ty::ReStatic + { // Region bound is implied by builtin bounds: + return self.builtin_bounds.repr(tcx); + } + + let mut res = Vec::new(); + + let region_str = self.region_bound.user_string(tcx); + if !region_str.is_empty() { + res.push(region_str); + } + + for bound in self.builtin_bounds.iter() { + res.push(bound.user_string(tcx)); + } + + res.connect("+") + } +} + impl UserString for ty::BuiltinBounds { fn user_string(&self, tcx: &ctxt) -> String { self.iter() @@ -1083,33 +1182,55 @@ impl Repr for infer::Bounds { } } -impl Repr for VV { - fn repr(&self, tcx: &ctxt) -> String { - match *self { - unify::Redirect(ref k) => - format!("Redirect({})", k.repr(tcx)), - unify::Root(ref v, r) => - format!("Root({}, {})", v.repr(tcx), r) - } - } -} - -impl Repr for region_inference::VarValue { - fn repr(&self, tcx: &ctxt) -> String { - match *self { - infer::region_inference::NoValue => - format!("NoValue"), - infer::region_inference::Value(r) => - format!("Value({})", r.repr(tcx)), - infer::region_inference::ErrorValue => - format!("ErrorValue"), - } - } -} - impl Repr for ty::ExplicitSelfCategory { fn repr(&self, _: &ctxt) -> String { explicit_self_category_to_str(self).to_string() } } + +impl Repr for regionmanip::WfConstraint { + fn repr(&self, tcx: &ctxt) -> String { + match *self { + regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => { + format!("RegionSubRegionConstraint({}, {})", + r_a.repr(tcx), + r_b.repr(tcx)) + } + + regionmanip::RegionSubParamConstraint(_, r, p) => { + format!("RegionSubParamConstraint({}, {})", + r.repr(tcx), + p.repr(tcx)) + } + } + } +} + +impl UserString for ParamTy { + fn user_string(&self, tcx: &ctxt) -> String { + let id = self.idx; + let did = self.def_id; + let ident = match tcx.ty_param_defs.borrow().find(&did.node) { + Some(def) => token::get_ident(def.ident).get().to_string(), + + // This can only happen when a type mismatch error happens and + // the actual type has more type parameters than the expected one. + None => format!("", id), + }; + ident + } +} + +impl Repr for ParamTy { + fn repr(&self, tcx: &ctxt) -> String { + self.user_string(tcx) + } +} + +impl Repr for (A,B) { + fn repr(&self, tcx: &ctxt) -> String { + let &(ref a, ref b) = self; + format!("({},{})", a.repr(tcx), b.repr(tcx)) + } +} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 1ac0aee85d4..522941cee8c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -192,7 +192,7 @@ impl AttrHelper for SpecialAttribute { } pub struct AttrBuilder { - attrs: Vec<(uint, Box)> + attrs: Vec<(uint, Box)> } impl AttrBuilder { @@ -203,12 +203,12 @@ impl AttrBuilder { } pub fn arg<'a, T: AttrHelper + 'static>(&'a mut self, idx: uint, a: T) -> &'a mut AttrBuilder { - self.attrs.push((idx, box a as Box)); + self.attrs.push((idx, box a as Box)); self } pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder { - self.attrs.push((ReturnIndex as uint, box a as Box)); + self.attrs.push((ReturnIndex as uint, box a as Box)); self } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 445672fcdc4..ee1b51683c2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -159,18 +159,12 @@ pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait { clean::RequiredMethod(trait_item) } }); - let supertraits = ty::trait_supertraits(tcx, did); - let mut parents = supertraits.iter().map(|i| { - match i.clean() { - clean::TraitBound(ty) => ty, - clean::RegionBound => unreachable!() - } - }); - + let trait_def = ty::lookup_trait_def(tcx, did); + let bounds = trait_def.bounds.clean(); clean::Trait { generics: (&def.generics, subst::TypeSpace).clean(), items: items.collect(), - parents: parents.collect() + bounds: bounds, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dc2c0d1d083..af4df81f996 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -481,15 +481,14 @@ impl Clean for ty::TypeParameterDef { #[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum TyParamBound { - RegionBound, + RegionBound, // FIXME(#16518) -- need to include name of actual region TraitBound(Type) } impl Clean for ast::TyParamBound { fn clean(&self) -> TyParamBound { match *self { - ast::StaticRegionTyParamBound => RegionBound, - ast::OtherRegionTyParamBound(_) => RegionBound, + ast::RegionTyParamBound(_) => RegionBound, ast::UnboxedFnTyParamBound(_) => { // FIXME(pcwalton): Wrong. RegionBound @@ -499,6 +498,16 @@ impl Clean for ast::TyParamBound { } } +impl Clean> for ty::ExistentialBounds { + fn clean(&self) -> Vec { + let mut vec = vec!(RegionBound); + for bb in self.builtin_bounds.iter() { + vec.push(bb.clean()); + } + vec + } +} + fn external_path(name: &str, substs: &subst::Substs) -> Path { let lifetimes = substs.regions().get_slice(subst::TypeSpace) .iter() @@ -525,7 +534,6 @@ impl Clean for ty::BuiltinBound { }; let empty = subst::Substs::empty(); let (did, path) = match *self { - ty::BoundStatic => return RegionBound, ty::BoundSend => (tcx.lang_items.send_trait().unwrap(), external_path("Send", &empty)), @@ -810,10 +818,7 @@ impl Clean for ast::ClosureTy { decl: self.decl.clean(), onceness: self.onceness, fn_style: self.fn_style, - bounds: match self.bounds { - Some(ref x) => x.clean(), - None => Vec::new() - }, + bounds: self.bounds.clean() } } } @@ -909,7 +914,7 @@ impl Clean for ast::RetStyle { pub struct Trait { pub items: Vec, pub generics: Generics, - pub parents: Vec, + pub bounds: Vec, } impl Clean for doctree::Trait { @@ -924,7 +929,7 @@ impl Clean for doctree::Trait { inner: TraitItem(Trait { items: self.items.clean(), generics: self.generics.clean(), - parents: self.parents.clean(), + bounds: self.bounds.clean(), }), } } @@ -1060,7 +1065,7 @@ pub enum Type { Self(ast::DefId), /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. Primitive(Primitive), - Closure(Box, Option), + Closure(Box), Proc(Box), /// extern "ABI" fn BareFunction(Box), @@ -1208,7 +1213,7 @@ impl Clean for ast::Ty { tpbs.clean().map(|x| x), id) } - TyClosure(ref c, region) => Closure(box c.clean(), region.clean()), + TyClosure(ref c) => Closure(box c.clean()), TyProc(ref c) => Proc(box c.clean()), TyBareFn(ref barefn) => BareFunction(box barefn.clean()), TyParen(ref ty) => ty.clean(), @@ -1273,11 +1278,11 @@ impl Clean for ty::t { decl: (ast_util::local_def(0), &fty.sig).clean(), onceness: fty.onceness, fn_style: fty.fn_style, - bounds: fty.bounds.iter().map(|i| i.clean()).collect(), + bounds: fty.bounds.clean(), }; match fty.store { ty::UniqTraitStore => Proc(decl), - ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()), + ty::RegionTraitStore(..) => Closure(decl), } } ty::ty_struct(did, ref substs) | diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index da45321e7fd..4d2cf852b8a 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -156,7 +156,7 @@ pub struct Trait { pub name: Ident, pub items: Vec, //should be TraitItem pub generics: ast::Generics, - pub parents: Vec, + pub bounds: Vec, pub attrs: Vec, pub id: ast::NodeId, pub whence: Span, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 37349388588..e526286ef46 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -355,7 +355,7 @@ impl fmt::Show for clean::Type { } clean::Self(..) => f.write("Self".as_bytes()), clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()), - clean::Closure(ref decl, ref region) => { + clean::Closure(ref decl) => { write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}", style = FnStyleSpace(decl.fn_style), lifetimes = if decl.lifetimes.len() == 0 { @@ -370,13 +370,6 @@ impl fmt::Show for clean::Type { }, bounds = { let mut ret = String::new(); - match *region { - Some(ref lt) => { - ret.push_str(format!(": {}", - *lt).as_slice()); - } - None => {} - } for bound in decl.bounds.iter() { match *bound { clean::RegionBound => {} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6415ee85f57..8342b6bd675 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1610,12 +1610,12 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item, fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { - let mut parents = String::new(); - if t.parents.len() > 0 { - parents.push_str(": "); - for (i, p) in t.parents.iter().enumerate() { - if i > 0 { parents.push_str(" + "); } - parents.push_str(format!("{}", *p).as_slice()); + let mut bounds = String::new(); + if t.bounds.len() > 0 { + bounds.push_str(": "); + for (i, p) in t.bounds.iter().enumerate() { + if i > 0 { bounds.push_str(" + "); } + bounds.push_str(format!("{}", *p).as_slice()); } } @@ -1624,7 +1624,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, VisSpace(it.visibility), it.name.get_ref().as_slice(), t.generics, - parents)); + bounds)); let required = t.items.iter() .filter(|m| { match **m { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b67b3c394d6..1706ebfbcf4 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -317,12 +317,12 @@ impl<'a> RustdocVisitor<'a> { }; om.statics.push(s); }, - ast::ItemTrait(ref gen, _, ref tr, ref items) => { + ast::ItemTrait(ref gen, _, ref b, ref items) => { let t = Trait { name: item.ident, items: items.iter().map(|x| (*x).clone()).collect(), generics: gen.clone(), - parents: tr.iter().map(|x| (*x).clone()).collect(), + bounds: b.iter().map(|x| (*x).clone()).collect(), id: item.id, attrs: item.attrs.iter().map(|x| *x).collect(), whence: item.span, diff --git a/src/librustrt/exclusive.rs b/src/librustrt/exclusive.rs index 179d050f598..28514bec5b4 100644 --- a/src/librustrt/exclusive.rs +++ b/src/librustrt/exclusive.rs @@ -26,7 +26,8 @@ pub struct Exclusive { data: UnsafeCell, } -/// An RAII guard returned via `lock` +/// stage0 only +#[cfg(stage0)] pub struct ExclusiveGuard<'a, T> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref @@ -34,6 +35,15 @@ pub struct ExclusiveGuard<'a, T> { _guard: mutex::LockGuard<'a>, } +/// An RAII guard returned via `lock` +#[cfg(not(stage0))] +pub struct ExclusiveGuard<'a, T:'a> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _data: &'a mut T, + _guard: mutex::LockGuard<'a>, +} + impl Exclusive { /// Creates a new `Exclusive` which will protect the data provided. pub fn new(user_data: T) -> Exclusive { diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index 70ce85ee649..5ca46a728c3 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -19,6 +19,7 @@ #![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)] #![feature(linkage, lang_items, unsafe_destructor, default_type_params)] #![feature(import_shadowing)] +#![feature(issue_5723_bootstrap)] #![no_std] #![experimental] @@ -98,7 +99,7 @@ pub trait Runtime { fn can_block(&self) -> bool; // FIXME: This is a serious code smell and this should not exist at all. - fn wrap(self: Box) -> Box; + fn wrap(self: Box) -> Box; } /// The default error code of the rust runtime if the main task fails instead diff --git a/src/librustrt/local_data.rs b/src/librustrt/local_data.rs index 6a0b599179c..fedea3c31e0 100644 --- a/src/librustrt/local_data.rs +++ b/src/librustrt/local_data.rs @@ -144,6 +144,16 @@ unsafe fn get_local_map<'a>() -> Option<&'a mut Map> { /// /// The task-local data can be accessed through this value, and when this /// structure is dropped it will return the borrow on the data. +#[cfg(not(stage0))] +pub struct Ref { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _inner: &'static TLDValueBox, + _marker: marker::NoSend +} + +/// stage0 only +#[cfg(stage0)] pub struct Ref { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs index 261d544a241..1afd88edbc2 100644 --- a/src/librustrt/rtio.rs +++ b/src/librustrt/rtio.rs @@ -120,7 +120,7 @@ pub struct ProcessConfig<'a> { } pub struct LocalIo<'a> { - factory: &'a mut IoFactory, + factory: &'a mut IoFactory+'a, } #[unsafe_destructor] @@ -174,7 +174,7 @@ impl<'a> LocalIo<'a> { } } - pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> { + pub fn new<'a>(io: &'a mut IoFactory+'a) -> LocalIo<'a> { LocalIo { factory: io } } diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index acd53535e3b..e39071864a7 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -103,7 +103,7 @@ pub struct Task { pub name: Option, state: TaskState, - imp: Option>, + imp: Option>, } // Once a task has entered the `Armed` state it must be destroyed via `drop`, @@ -353,14 +353,14 @@ impl Task { /// Inserts a runtime object into this task, transferring ownership to the /// task. It is illegal to replace a previous runtime object in this task /// with this argument. - pub fn put_runtime(&mut self, ops: Box) { + pub fn put_runtime(&mut self, ops: Box) { assert!(self.imp.is_none()); self.imp = Some(ops); } /// Removes the runtime from this task, transferring ownership to the /// caller. - pub fn take_runtime(&mut self) -> Box { + pub fn take_runtime(&mut self) -> Box { assert!(self.imp.is_some()); self.imp.take().unwrap() } @@ -390,7 +390,7 @@ impl Task { Ok(t) => Some(t), Err(t) => { let data = mem::transmute::<_, raw::TraitObject>(t).data; - let obj: Box = + let obj: Box = mem::transmute(raw::TraitObject { vtable: vtable, data: data, diff --git a/src/librustuv/access.rs b/src/librustuv/access.rs index 290293cf086..0fa89ce989a 100644 --- a/src/librustuv/access.rs +++ b/src/librustuv/access.rs @@ -26,11 +26,18 @@ pub struct Access { inner: Arc>>, } +#[cfg(stage0)] pub struct Guard<'a, T> { access: &'a mut Access, missile: Option, } +#[cfg(not(stage0))] +pub struct Guard<'a, T:'static> { + access: &'a mut Access, + missile: Option, +} + struct Inner { queue: Vec<(BlockedTask, uint)>, held: bool, diff --git a/src/librustuv/timeout.rs b/src/librustuv/timeout.rs index 32d73952416..d2482ee6b60 100644 --- a/src/librustuv/timeout.rs +++ b/src/librustuv/timeout.rs @@ -28,12 +28,20 @@ pub struct AccessTimeout { pub access: access::Access, } +#[cfg(stage0)] pub struct Guard<'a, T> { state: &'a mut TimeoutState, pub access: access::Guard<'a, T>, pub can_timeout: bool, } +#[cfg(not(stage0))] +pub struct Guard<'a, T:'static> { + state: &'a mut TimeoutState, + pub access: access::Guard<'a, T>, + pub can_timeout: bool, +} + #[deriving(PartialEq)] enum TimeoutState { NoTimeout, diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index cfc915c7d0a..d70b6b4d57b 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -382,7 +382,7 @@ fn fmt_number_or_null(v: f64) -> String { /// A structure for implementing serialization to JSON. pub struct Encoder<'a> { - writer: &'a mut io::Writer, + writer: &'a mut io::Writer+'a, } impl<'a> Encoder<'a> { @@ -594,7 +594,7 @@ impl<'a> ::Encoder for Encoder<'a> { /// Another encoder for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettyEncoder<'a> { - writer: &'a mut io::Writer, + writer: &'a mut io::Writer+'a, curr_indent: uint, indent: uint, } diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 5c35ad85233..44ea56f4c73 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -24,6 +24,7 @@ Core encoding and decoding interfaces. html_root_url = "http://doc.rust-lang.org/master/", html_playground_url = "http://play.rust-lang.org/")] #![feature(macro_rules, managed_boxes, default_type_params, phase)] +#![feature(issue_5723_bootstrap)] // test harness access #[cfg(test)] diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index b8f8bd41a2d..714712d9eba 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -409,20 +409,38 @@ mod table { assert_eq!(size_of::(), size_of::()) } - /// Iterator over shared references to entries in a table. + /// Note: stage0-specific version that lacks bound. + #[cfg(stage0)] pub struct Entries<'a, K, V> { table: &'a RawTable, idx: uint, elems_seen: uint, } - /// Iterator over mutable references to entries in a table. + /// Iterator over shared references to entries in a table. + #[cfg(not(stage0))] + pub struct Entries<'a, K:'a, V:'a> { + table: &'a RawTable, + idx: uint, + elems_seen: uint, + } + + /// Note: stage0-specific version that lacks bound. + #[cfg(stage0)] pub struct MutEntries<'a, K, V> { table: &'a mut RawTable, idx: uint, elems_seen: uint, } + /// Iterator over mutable references to entries in a table. + #[cfg(not(stage0))] + pub struct MutEntries<'a, K:'a, V:'a> { + table: &'a mut RawTable, + idx: uint, + elems_seen: uint, + } + /// Iterator over the entries in a table, consuming the table. pub struct MoveEntries { table: RawTable, diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index 12caa715865..ffbcdd87bfe 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -37,10 +37,29 @@ use ptr::RawPtr; /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. +#[cfg(stage0)] pub struct Bytes<'r, T> { reader: &'r mut T, } +/// An iterator that reads a single byte on each iteration, +/// until `.read_byte()` returns `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Bytes` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +#[cfg(not(stage0))] +pub struct Bytes<'r, T:'r> { + reader: &'r mut T, +} + impl<'r, R: Reader> Bytes<'r, R> { /// Constructs a new byte iterator from the given Reader instance. pub fn new(r: &'r mut R) -> Bytes<'r, R> { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index dc6478df360..38aa58f1c6a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -945,11 +945,11 @@ pub trait Reader { } } -impl Reader for Box { +impl Reader for Box { fn read(&mut self, buf: &mut [u8]) -> IoResult { 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 { self.read(buf) } } @@ -976,6 +976,13 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) - }) } +/// Note: stage0-specific version that lacks bound. +#[cfg(stage0)] +pub struct RefReader<'a, R> { + /// The underlying reader which this is referencing + inner: &'a mut R +} + /// A `RefReader` is a struct implementing `Reader` which contains a reference /// to another reader. This is often useful when composing streams. /// @@ -1000,7 +1007,8 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) - /// /// # } /// ``` -pub struct RefReader<'a, R> { +#[cfg(not(stage0))] +pub struct RefReader<'a, R:'a> { /// The underlying reader which this is referencing inner: &'a mut R } @@ -1058,12 +1066,21 @@ pub trait Writer { /// /// This function will return any I/O error reported while formatting. fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> { - // Create a shim which translates a Writer to a FormatWriter and saves - // off I/O errors. instead of discarding them + // Note: stage0-specific version that lacks bound. + #[cfg(stage0)] struct Adaptor<'a, T> { inner: &'a mut T, error: IoResult<()>, } + + // Create a shim which translates a Writer to a FormatWriter and saves + // off I/O errors. instead of discarding them + #[cfg(not(stage0))] + struct Adaptor<'a, T:'a> { + inner: &'a mut T, + error: IoResult<()>, + } + impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> { fn write(&mut self, bytes: &[u8]) -> fmt::Result { match self.inner.write(bytes) { @@ -1278,7 +1295,7 @@ pub trait Writer { } } -impl Writer for Box { +impl Writer for Box { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } @@ -1286,7 +1303,7 @@ impl Writer for Box { fn flush(&mut self) -> IoResult<()> { self.flush() } } -impl<'a> Writer for &'a mut Writer { +impl<'a> Writer for &'a mut Writer+'a { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } @@ -1318,11 +1335,42 @@ impl<'a> Writer for &'a mut Writer { /// println!("input processed: {}", output.unwrap()); /// # } /// ``` +#[cfg(stage0)] pub struct RefWriter<'a, W> { /// The underlying writer which this is referencing inner: &'a mut W } +/// A `RefWriter` is a struct implementing `Writer` which contains a reference +/// to another writer. This is often useful when composing streams. +/// +/// # Example +/// +/// ``` +/// # fn main() {} +/// # fn process_input(r: R) {} +/// # fn foo () { +/// use std::io::util::TeeReader; +/// use std::io::{stdin, MemWriter}; +/// +/// let mut output = MemWriter::new(); +/// +/// { +/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a +/// // handle to it in the outer scope +/// let mut tee = TeeReader::new(stdin(), output.by_ref()); +/// process_input(tee); +/// } +/// +/// println!("input processed: {}", output.unwrap()); +/// # } +/// ``` +#[cfg(not(stage0))] +pub struct RefWriter<'a, W:'a> { + /// The underlying writer which this is referencing + inner: &'a mut W +} + impl<'a, W: Writer> Writer for RefWriter<'a, W> { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) } @@ -1351,10 +1399,29 @@ impl Stream for T {} /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. +#[cfg(stage0)] pub struct Lines<'r, T> { buffer: &'r mut T, } +/// An iterator that reads a line on each iteration, +/// until `.read_line()` encounters `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Lines` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +#[cfg(not(stage0))] +pub struct Lines<'r, T:'r> { + buffer: &'r mut T, +} + impl<'r, T: Buffer> Iterator> for Lines<'r, T> { fn next(&mut self) -> Option> { match self.buffer.read_line() { @@ -1378,10 +1445,29 @@ impl<'r, T: Buffer> Iterator> for Lines<'r, T> { /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. +#[cfg(stage0)] pub struct Chars<'r, T> { buffer: &'r mut T } +/// An iterator that reads a utf8-encoded character on each iteration, +/// until `.read_char()` encounters `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Chars` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +#[cfg(not(stage0))] +pub struct Chars<'r, T:'r> { + buffer: &'r mut T +} + impl<'r, T: Buffer> Iterator> for Chars<'r, T> { fn next(&mut self) -> Option> { match self.buffer.read_char() { @@ -1611,6 +1697,12 @@ pub trait Acceptor { } } +/// Note: stage0-specific version that lacks bound on A. +#[cfg(stage0)] +pub struct IncomingConnections<'a, A> { + inc: &'a mut A, +} + /// An infinite iterator over incoming connection attempts. /// Calling `next` will block the task until a connection is attempted. /// @@ -1618,7 +1710,8 @@ pub trait Acceptor { /// `Some`. The `Some` contains the `IoResult` representing whether the /// connection attempt was successful. A successful connection will be wrapped /// in `Ok`. A failed connection is represented as an `Err`. -pub struct IncomingConnections<'a, A> { +#[cfg(not(stage0))] +pub struct IncomingConnections<'a, A:'a> { inc: &'a mut A, } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 1fe0ba780a6..7fba0bc85a6 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -126,12 +126,12 @@ impl Buffer for NullReader { /// The `Writer`s are delegated to in order. If any `Writer` returns an error, /// that error is returned immediately and remaining `Writer`s are not called. pub struct MultiWriter { - writers: Vec> + writers: Vec> } impl MultiWriter { /// Creates a new `MultiWriter` - pub fn new(writers: Vec>) -> MultiWriter { + pub fn new(writers: Vec>) -> MultiWriter { MultiWriter { writers: writers } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d35b644b643..8c1ed7cfa8f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -108,6 +108,7 @@ #![feature(macro_rules, globs, managed_boxes, linkage)] #![feature(default_type_params, phase, lang_items, unsafe_destructor)] #![feature(import_shadowing)] +#![feature(issue_5723_bootstrap)] // Don't link to std. We are std. #![no_std] diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index 50441cb534d..6a10be84a62 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -825,12 +825,20 @@ pub trait GenericPathUnsafe { unsafe fn push_unchecked(&mut self, path: T); } -/// Helper struct for printing paths with format!() +/// Note: stage0-specific version that lacks bound. +#[cfg(stage0)] pub struct Display<'a, P> { path: &'a P, filename: bool } +/// Helper struct for printing paths with format!() +#[cfg(not(stage0))] +pub struct Display<'a, P:'a> { + path: &'a P, + filename: bool +} + impl<'a, P: GenericPath> fmt::Show for Display<'a, P> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.as_maybe_owned().as_slice().fmt(f) diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 42384892e69..58b3179a297 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -291,7 +291,7 @@ mod imp { struct Context<'a> { idx: int, - writer: &'a mut Writer, + writer: &'a mut Writer+'a, last_error: Option, } diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs index 16bcdd9bbb6..16f6eea6144 100644 --- a/src/libsync/comm/mod.rs +++ b/src/libsync/comm/mod.rs @@ -386,6 +386,14 @@ pub struct Receiver { /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. #[unstable] +#[cfg(not(stage0))] +pub struct Messages<'a, T:'a> { + rx: &'a Receiver +} + +/// Stage0 only +#[cfg(stage0)] +#[unstable] pub struct Messages<'a, T> { rx: &'a Receiver } diff --git a/src/libsync/comm/select.rs b/src/libsync/comm/select.rs index 737a4bfe299..dc9891dd1ee 100644 --- a/src/libsync/comm/select.rs +++ b/src/libsync/comm/select.rs @@ -76,6 +76,24 @@ pub struct Select { /// A handle to a receiver which is currently a member of a `Select` set of /// receivers. This handle is used to keep the receiver in the set as well as /// interact with the underlying receiver. +#[cfg(not(stage0))] +pub struct Handle<'rx, T:'rx> { + /// The ID of this handle, used to compare against the return value of + /// `Select::wait()` + id: uint, + selector: &'rx Select, + next: *mut Handle<'static, ()>, + prev: *mut Handle<'static, ()>, + added: bool, + packet: &'rx Packet+'rx, + + // due to our fun transmutes, we be sure to place this at the end. (nothing + // previous relies on T) + rx: &'rx Receiver, +} + +/// Stage0 only +#[cfg(stage0)] pub struct Handle<'rx, T> { /// The ID of this handle, used to compare against the return value of /// `Select::wait()` @@ -84,7 +102,7 @@ pub struct Handle<'rx, T> { next: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>, added: bool, - packet: &'rx Packet, + packet: &'rx Packet+'rx, // due to our fun transmutes, we be sure to place this at the end. (nothing // previous relies on T) diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs index bed90743503..c2744751ee5 100644 --- a/src/libsync/lib.rs +++ b/src/libsync/lib.rs @@ -29,6 +29,7 @@ #![feature(phase, globs, macro_rules, unsafe_destructor)] #![feature(import_shadowing)] +#![feature(issue_5723_bootstrap)] #![deny(missing_doc)] #![no_std] diff --git a/src/libsync/lock.rs b/src/libsync/lock.rs index b07d06ca18e..e1cae6c62d5 100644 --- a/src/libsync/lock.rs +++ b/src/libsync/lock.rs @@ -180,6 +180,18 @@ pub struct Mutex { /// An guard which is created by locking a mutex. Through this guard the /// underlying data can be accessed. +#[cfg(not(stage0))] +pub struct MutexGuard<'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, + /// Inner condition variable connected to the locked mutex that this guard + /// was created from. This can be used for atomic-unlock-and-deschedule. + pub cond: Condvar<'a>, +} + +/// stage0 only +#[cfg(stage0)] pub struct MutexGuard<'a, T> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref @@ -280,6 +292,18 @@ pub struct RWLock { /// A guard which is created by locking an rwlock in write mode. Through this /// guard the underlying data can be accessed. +#[cfg(not(stage0))] +pub struct RWLockWriteGuard<'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, + /// Inner condition variable that can be used to sleep on the write mode of + /// this rwlock. + pub cond: Condvar<'a>, +} + +/// stage0 only +#[cfg(stage0)] pub struct RWLockWriteGuard<'a, T> { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref @@ -291,6 +315,16 @@ pub struct RWLockWriteGuard<'a, T> { /// A guard which is created by locking an rwlock in read mode. Through this /// guard the underlying data can be accessed. +#[cfg(not(stage0))] +pub struct RWLockReadGuard<'a, T:'a> { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _data: &'a T, + _guard: raw::RWLockReadGuard<'a>, +} + +/// Stage0 only +#[cfg(stage0)] pub struct RWLockReadGuard<'a, T> { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref diff --git a/src/libsync/raw.rs b/src/libsync/raw.rs index c42d567fc18..98934d87474 100644 --- a/src/libsync/raw.rs +++ b/src/libsync/raw.rs @@ -103,10 +103,17 @@ struct SemInner { } #[must_use] +#[cfg(stage0)] struct SemGuard<'a, Q> { sem: &'a Sem, } +#[must_use] +#[cfg(not(stage0))] +struct SemGuard<'a, Q:'a> { + sem: &'a Sem, +} + impl Sem { fn new(count: int, q: Q) -> Sem { assert!(count >= 0, diff --git a/src/libsync/spsc_queue.rs b/src/libsync/spsc_queue.rs index 578e518cb8f..32b77be78a4 100644 --- a/src/libsync/spsc_queue.rs +++ b/src/libsync/spsc_queue.rs @@ -315,27 +315,6 @@ mod test { assert_eq!(consumer.pop(), None); } - // This behaviour is blocked by the type system if using the safe constructor - #[test] - fn pop_peeked_unchecked() { - let q = unsafe { Queue::new(0) }; - q.push(vec![1i]); - q.push(vec![2]); - let peeked = q.peek().unwrap(); - - assert_eq!(*peeked, vec![1]); - assert_eq!(q.pop(), Some(vec![1])); - - assert_eq!(*peeked, vec![1]); - q.push(vec![7]); - - // Note: This should actually expect 1, but this test is to highlight - // the unsafety allowed by the unchecked usage. A Rust user would not - // expect their peeked value to mutate like this without the type system - // complaining. - assert_eq!(*peeked, vec![7]); - } - #[test] fn peek() { let (mut consumer, mut producer) = queue(0); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7d5787092a5..d574a02fded 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -224,16 +224,17 @@ pub static DUMMY_NODE_ID: NodeId = -1; #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamBound { TraitTyParamBound(TraitRef), - StaticRegionTyParamBound, UnboxedFnTyParamBound(UnboxedFnTy), - OtherRegionTyParamBound(Span) // FIXME -- just here until work for #5723 lands + RegionTyParamBound(Lifetime) } +pub type TyParamBounds = OwnedSlice; + #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct TyParam { pub ident: Ident, pub id: NodeId, - pub bounds: OwnedSlice, + pub bounds: TyParamBounds, pub unbound: Option, pub default: Option>, pub span: Span @@ -892,11 +893,7 @@ pub struct ClosureTy { pub fn_style: FnStyle, pub onceness: Onceness, pub decl: P, - /// Optional optvec distinguishes between "fn()" and "fn:()" so we can - /// implement issue #7264. None means "fn()", which means infer a default - /// bound based on pointer sigil during typeck. Some(Empty) means "fn:()", - /// which means use no bounds (e.g., not even Owned on a ~fn()). - pub bounds: Option>, + pub bounds: TyParamBounds, } #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)] @@ -923,12 +920,12 @@ pub enum Ty_ { TyFixedLengthVec(P, Gc), TyPtr(MutTy), TyRptr(Option, MutTy), - TyClosure(Gc, Option), + TyClosure(Gc), TyProc(Gc), TyBareFn(Gc), TyUnboxedFn(Gc), TyTup(Vec> ), - TyPath(Path, Option>, NodeId), // for #7264; see above + TyPath(Path, Option, NodeId), // for #7264; see above /// No-op; kept solely so that we can pretty-print faithfully TyParen(P), TyTypeof(Gc), @@ -1281,7 +1278,7 @@ pub enum Item_ { ItemTrait(Generics, Option, // (optional) default bound not required for Self. // Currently, only Sized makes sense here. - Vec , + TyParamBounds, Vec), ItemImpl(Generics, Option, // (optional) trait this impl implements diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 5fccf6cc3f0..993c5ce676a 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -68,10 +68,15 @@ impl<'a> Iterator for LinkedPath<'a> { } } -// HACK(eddyb) move this into libstd (value wrapper for slice::Items). +#[cfg(stage0)] #[deriving(Clone)] pub struct Values<'a, T>(pub slice::Items<'a, T>); +// HACK(eddyb) move this into libstd (value wrapper for slice::Items). +#[cfg(not(stage0))] +#[deriving(Clone)] +pub struct Values<'a, T:'a>(pub slice::Items<'a, T>); + impl<'a, T: Copy> Iterator for Values<'a, T> { fn next(&mut self) -> Option { let &Values(ref mut items) = self; @@ -478,6 +483,7 @@ impl Map { } } +#[cfg(stage0)] pub struct NodesMatchingSuffix<'a, S> { map: &'a Map, item_name: &'a S, @@ -485,6 +491,14 @@ pub struct NodesMatchingSuffix<'a, S> { idx: NodeId, } +#[cfg(not(stage0))] +pub struct NodesMatchingSuffix<'a, S:'a> { + map: &'a Map, + item_name: &'a S, + in_which: &'a [S], + idx: NodeId, +} + impl<'a,S:Str> NodesMatchingSuffix<'a,S> { /// Returns true only if some suffix of the module path for parent /// matches `self.in_which`. @@ -676,11 +690,7 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { None => {} } } - ItemTrait(_, _, ref traits, ref methods) => { - for t in traits.iter() { - self.insert(t.ref_id, EntryItem(self.parent, i)); - } - + ItemTrait(_, _, _, ref methods) => { for tm in methods.iter() { match *tm { RequiredMethod(ref m) => { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 1a4b41404be..cc586a3affa 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -349,12 +349,20 @@ pub trait IdVisitingOperation { /// A visitor that applies its operation to all of the node IDs /// in a visitable thing. +#[cfg(stage0)] pub struct IdVisitor<'a, O> { pub operation: &'a O, pub pass_through_items: bool, pub visited_outermost: bool, } +#[cfg(not(stage0))] +pub struct IdVisitor<'a, O:'a> { + pub operation: &'a O, + pub pass_through_items: bool, + pub visited_outermost: bool, +} + impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { fn visit_generics_helper(&self, generics: &Generics) { for type_parameter in generics.ty_params.iter() { diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 209296989fa..25a6a4c01bd 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -45,8 +45,10 @@ fn with_used_diagnostics(f: |&mut HashMap| -> T) -> T { } } -pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span, - token_tree: &[TokenTree]) -> Box { +pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt, + span: Span, + token_tree: &[TokenTree]) + -> Box { let code = match token_tree { [ast::TTTok(_, token::IDENT(code, _))] => code, _ => unreachable!() @@ -75,8 +77,10 @@ pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span, MacExpr::new(quote_expr!(ecx, ())) } -pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span, - token_tree: &[TokenTree]) -> Box { +pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, + span: Span, + token_tree: &[TokenTree]) + -> Box { let (code, description) = match token_tree { [ast::TTTok(_, token::IDENT(ref code, _))] => { (code, None) @@ -101,8 +105,10 @@ pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span, MacItem::new(quote_item!(ecx, mod $sym {}).unwrap()) } -pub fn expand_build_diagnostic_array(ecx: &mut ExtCtxt, span: Span, - token_tree: &[TokenTree]) -> Box { +pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, + span: Span, + token_tree: &[TokenTree]) + -> Box { let name = match token_tree { [ast::TTTok(_, token::IDENT(ref name, _))] => name, _ => unreachable!() diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 180f2409b8a..8028d51a7b5 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -45,8 +45,8 @@ impl State { static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; -pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { let mut p = cx.new_parser_from_tts(tts); let mut asm = InternedString::new(""); let mut asm_str_style = None; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 01d3920a254..b3b66a6a604 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -52,23 +52,23 @@ pub struct BasicMacroExpander { /// Represents a thing that maps token trees to Macro Results pub trait TTMacroExpander { - fn expand(&self, - ecx: &mut ExtCtxt, - span: Span, - token_tree: &[ast::TokenTree]) - -> Box; + fn expand<'cx>(&self, + ecx: &'cx mut ExtCtxt, + span: Span, + token_tree: &[ast::TokenTree]) + -> Box; } pub type MacroExpanderFn = - fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree]) - -> Box; + fn<'cx>(ecx: &'cx mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree]) + -> Box; impl TTMacroExpander for BasicMacroExpander { - fn expand(&self, - ecx: &mut ExtCtxt, - span: Span, - token_tree: &[ast::TokenTree]) - -> Box { + fn expand<'cx>(&self, + ecx: &'cx mut ExtCtxt, + span: Span, + token_tree: &[ast::TokenTree]) + -> Box { (self.expander)(ecx, span, token_tree) } } @@ -79,27 +79,27 @@ pub struct BasicIdentMacroExpander { } pub trait IdentMacroExpander { - fn expand(&self, - cx: &mut ExtCtxt, - sp: Span, - ident: ast::Ident, - token_tree: Vec ) - -> Box; + fn expand<'cx>(&self, + cx: &'cx mut ExtCtxt, + sp: Span, + ident: ast::Ident, + token_tree: Vec ) + -> Box; } impl IdentMacroExpander for BasicIdentMacroExpander { - fn expand(&self, - cx: &mut ExtCtxt, - sp: Span, - ident: ast::Ident, - token_tree: Vec ) - -> Box { + fn expand<'cx>(&self, + cx: &'cx mut ExtCtxt, + sp: Span, + ident: ast::Ident, + token_tree: Vec ) + -> Box { (self.expander)(cx, sp, ident, token_tree) } } pub type IdentMacroExpanderFn = - fn(&mut ExtCtxt, Span, ast::Ident, Vec) -> Box; + fn<'cx>(&'cx mut ExtCtxt, Span, ast::Ident, Vec) -> Box; /// The result of a macro expansion. The return values of the various /// methods are spliced into the AST at the callsite of the macro (or @@ -146,8 +146,8 @@ pub struct MacExpr { e: Gc, } impl MacExpr { - pub fn new(e: Gc) -> Box { - box MacExpr { e: e } as Box + pub fn new(e: Gc) -> Box { + box MacExpr { e: e } as Box } } impl MacResult for MacExpr { @@ -160,8 +160,8 @@ pub struct MacPat { p: Gc, } impl MacPat { - pub fn new(p: Gc) -> Box { - box MacPat { p: p } as Box + pub fn new(p: Gc) -> Box { + box MacPat { p: p } as Box } } impl MacResult for MacPat { @@ -174,8 +174,8 @@ pub struct MacItem { i: Gc } impl MacItem { - pub fn new(i: Gc) -> Box { - box MacItem { i: i } as Box + pub fn new(i: Gc) -> Box { + box MacItem { i: i } as Box } } impl MacResult for MacItem { @@ -203,8 +203,8 @@ impl DummyResult { /// /// Use this as a return value after hitting any errors and /// calling `span_err`. - pub fn any(sp: Span) -> Box { - box DummyResult { expr_only: false, span: sp } as Box + pub fn any(sp: Span) -> Box { + box DummyResult { expr_only: false, span: sp } as Box } /// Create a default MacResult that can only be an expression. @@ -212,8 +212,8 @@ impl DummyResult { /// Use this for macros that must expand to an expression, so even /// if an error is encountered internally, the user will receive /// an error that they also used it in the wrong place. - pub fn expr(sp: Span) -> Box { - box DummyResult { expr_only: true, span: sp } as Box + pub fn expr(sp: Span) -> Box { + box DummyResult { expr_only: true, span: sp } as Box } /// A plain dummy expression. diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index 6ea55096348..18367511495 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -17,8 +17,10 @@ use ext::base; use ext::build::AstBuilder; -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { cx.span_warn(sp, "`bytes!` is deprecated, use `b\"foo\"` literals instead"); cx.parse_sess.span_diagnostic.span_note(sp, "see http://doc.rust-lang.org/rust.html#byte-and-byte-string-literals \ diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index c2930662bc4..0c3a951c982 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -26,8 +26,10 @@ use parse::token::InternedString; use parse::token; -pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { let mut p = cx.new_parser_from_tts(tts); let mut cfgs = Vec::new(); // parse `cfg!(meta_item, meta_item(x,y), meta_item="foo", ...)` diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs index dd1153bf666..ea7a4d061c0 100644 --- a/src/libsyntax/ext/concat.rs +++ b/src/libsyntax/ext/concat.rs @@ -19,7 +19,7 @@ use std::string::String; pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let es = match base::get_exprs_from_tts(cx, sp, tts) { Some(e) => e, None => return base::DummyResult::expr(sp) diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 7cf901bbd5e..0ac26a3a904 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -18,8 +18,8 @@ use parse::token::{str_to_ident}; use std::gc::GC; -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { let mut res_str = String::new(); for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 4b185419b40..50bdc296aad 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -407,9 +407,15 @@ impl<'a> TraitDef<'a> { cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) }).collect(); + // require the current trait bounds.push(cx.typarambound(trait_path.clone())); + // also add in any bounds from the declaration + for declared_bound in ty_param.bounds.iter() { + bounds.push((*declared_bound).clone()); + } + cx.typaram(self.span, ty_param.ident, OwnedSlice::from_vec(bounds), diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index b24cfb85794..aae92ae85fc 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -23,8 +23,8 @@ use parse::token; use std::os; -pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { None => return DummyResult::expr(sp), Some(v) => v @@ -59,8 +59,8 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) MacExpr::new(e) } -pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { +pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { let exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.len() == 0 => { cx.span_err(sp, "env! takes 1 or 2 arguments"); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d918b28d4dc..9dbea1c9ac2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -31,6 +31,10 @@ use util::small_vector::SmallVector; use std::gc::{Gc, GC}; +enum Either { + Left(L), + Right(R) +} fn expand_expr(e: Gc, fld: &mut MacroExpander) -> Gc { match e.node { @@ -102,7 +106,8 @@ fn expand_mac_invoc(mac: &ast::Mac, span: &codemap::Span, parse_thunk: |Box|->Option, mark_thunk: |T,Mrk|->T, fld: &mut MacroExpander) - -> Option { + -> Option +{ match (*mac).node { // it would almost certainly be cleaner to pass the whole // macro invocation in, rather than pulling it apart and @@ -149,10 +154,13 @@ fn expand_mac_invoc(mac: &ast::Mac, span: &codemap::Span, // the macro. let mac_span = original_span(fld.cx); - let expanded = expandfun.expand(fld.cx, - mac_span.call_site, - marked_before.as_slice()); - let parsed = match parse_thunk(expanded) { + let opt_parsed = { + let expanded = expandfun.expand(fld.cx, + mac_span.call_site, + marked_before.as_slice()); + parse_thunk(expanded) + }; + let parsed = match opt_parsed { Some(e) => e, None => { fld.cx.span_err( @@ -358,7 +366,8 @@ fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool { // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. fn expand_item_mac(it: Gc, fld: &mut MacroExpander) - -> SmallVector> { + -> SmallVector> +{ let (pth, tts) = match it.node { ItemMac(codemap::Spanned { node: MacInvocTT(ref pth, ref tts, _), @@ -372,86 +381,93 @@ fn expand_item_mac(it: Gc, fld: &mut MacroExpander) let extname = pth.segments.get(0).identifier; let extnamestr = token::get_ident(extname); let fm = fresh_mark(); - let expanded = match fld.cx.syntax_env.find(&extname.name) { - None => { - fld.cx.span_err(pth.span, - format!("macro undefined: '{}!'", - extnamestr).as_slice()); - // let compilation continue - return SmallVector::zero(); - } - - Some(rc) => match *rc { - NormalTT(ref expander, span) => { - if it.ident.name != parse::token::special_idents::invalid.name { - fld.cx - .span_err(pth.span, - format!("macro {}! expects no ident argument, \ - given '{}'", - extnamestr, - token::get_ident(it.ident)).as_slice()); - return SmallVector::zero(); - } - fld.cx.bt_push(ExpnInfo { - call_site: it.span, - callee: NameAndSpan { - name: extnamestr.get().to_string(), - format: MacroBang, - span: span - } - }); - // mark before expansion: - let marked_before = mark_tts(tts.as_slice(), fm); - expander.expand(fld.cx, it.span, marked_before.as_slice()) - } - IdentTT(ref expander, span) => { - if it.ident.name == parse::token::special_idents::invalid.name { - fld.cx.span_err(pth.span, - format!("macro {}! expects an ident argument", - extnamestr.get()).as_slice()); - return SmallVector::zero(); - } - fld.cx.bt_push(ExpnInfo { - call_site: it.span, - callee: NameAndSpan { - name: extnamestr.get().to_string(), - format: MacroBang, - span: span - } - }); - // mark before expansion: - let marked_tts = mark_tts(tts.as_slice(), fm); - expander.expand(fld.cx, it.span, it.ident, marked_tts) - } - LetSyntaxTT(ref expander, span) => { - if it.ident.name == parse::token::special_idents::invalid.name { - fld.cx.span_err(pth.span, - format!("macro {}! expects an ident argument", - extnamestr.get()).as_slice()); - return SmallVector::zero(); - } - fld.cx.bt_push(ExpnInfo { - call_site: it.span, - callee: NameAndSpan { - name: extnamestr.get().to_string(), - format: MacroBang, - span: span - } - }); - // DON'T mark before expansion: - expander.expand(fld.cx, it.span, it.ident, tts) - } - _ => { - fld.cx.span_err(it.span, - format!("{}! is not legal in item position", - extnamestr.get()).as_slice()); + let def_or_items = { + let expanded = match fld.cx.syntax_env.find(&extname.name) { + None => { + fld.cx.span_err(pth.span, + format!("macro undefined: '{}!'", + extnamestr).as_slice()); + // let compilation continue return SmallVector::zero(); } + + Some(rc) => match *rc { + NormalTT(ref expander, span) => { + if it.ident.name != parse::token::special_idents::invalid.name { + fld.cx + .span_err(pth.span, + format!("macro {}! expects no ident argument, \ + given '{}'", + extnamestr, + token::get_ident(it.ident)).as_slice()); + return SmallVector::zero(); + } + fld.cx.bt_push(ExpnInfo { + call_site: it.span, + callee: NameAndSpan { + name: extnamestr.get().to_string(), + format: MacroBang, + span: span + } + }); + // mark before expansion: + let marked_before = mark_tts(tts.as_slice(), fm); + expander.expand(fld.cx, it.span, marked_before.as_slice()) + } + IdentTT(ref expander, span) => { + if it.ident.name == parse::token::special_idents::invalid.name { + fld.cx.span_err(pth.span, + format!("macro {}! expects an ident argument", + extnamestr.get()).as_slice()); + return SmallVector::zero(); + } + fld.cx.bt_push(ExpnInfo { + call_site: it.span, + callee: NameAndSpan { + name: extnamestr.get().to_string(), + format: MacroBang, + span: span + } + }); + // mark before expansion: + let marked_tts = mark_tts(tts.as_slice(), fm); + expander.expand(fld.cx, it.span, it.ident, marked_tts) + } + LetSyntaxTT(ref expander, span) => { + if it.ident.name == parse::token::special_idents::invalid.name { + fld.cx.span_err(pth.span, + format!("macro {}! expects an ident argument", + extnamestr.get()).as_slice()); + return SmallVector::zero(); + } + fld.cx.bt_push(ExpnInfo { + call_site: it.span, + callee: NameAndSpan { + name: extnamestr.get().to_string(), + format: MacroBang, + span: span + } + }); + // DON'T mark before expansion: + expander.expand(fld.cx, it.span, it.ident, tts) + } + _ => { + fld.cx.span_err(it.span, + format!("{}! is not legal in item position", + extnamestr.get()).as_slice()); + return SmallVector::zero(); + } + } + }; + + match expanded.make_def() { + Some(def) => Left(def), + None => Right(expanded.make_items()) } }; - let items = match expanded.make_def() { - Some(MacroDef { name, ext }) => { + let items = match def_or_items { + Left(MacroDef { name, ext }) => { // hidden invariant: this should only be possible as the // result of expanding a LetSyntaxTT, and thus doesn't // need to be marked. Not that it could be marked anyway. @@ -462,23 +478,20 @@ fn expand_item_mac(it: Gc, fld: &mut MacroExpander) } SmallVector::zero() } - None => { - match expanded.make_items() { - Some(items) => { - items.move_iter() - .map(|i| mark_item(i, fm)) - .flat_map(|i| fld.fold_item(i).move_iter()) - .collect() - } - None => { - fld.cx.span_err(pth.span, - format!("non-item macro in item position: {}", - extnamestr.get()).as_slice()); - return SmallVector::zero(); - } - } + Right(Some(items)) => { + items.move_iter() + .map(|i| mark_item(i, fm)) + .flat_map(|i| fld.fold_item(i).move_iter()) + .collect() + } + Right(None) => { + fld.cx.span_err(pth.span, + format!("non-item macro in item position: {}", + extnamestr.get()).as_slice()); + return SmallVector::zero(); } }; + fld.cx.bt_pop(); return items; } @@ -901,7 +914,7 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: &ast::FnDecl, block: Gc { +pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, } diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 4185458bfbe..5352cfaf749 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -19,7 +19,7 @@ use ext::build::AstBuilder; pub fn expand_syntax_ext(ecx: &mut base::ExtCtxt, sp: Span, _tts: &[ast::TokenTree]) - -> Box { + -> Box { ecx.span_err(sp, "`fmt!` is deprecated, use `format!` instead"); ecx.parse_sess.span_diagnostic.span_note(sp, "see http://doc.rust-lang.org/std/fmt/ \ diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 124e9e95942..0994abaadc7 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -33,7 +33,7 @@ enum Position { Named(String), } -struct Context<'a, 'b> { +struct Context<'a, 'b:'a> { ecx: &'a mut ExtCtxt<'b>, fmtsp: Span, @@ -668,8 +668,9 @@ impl<'a, 'b> Context<'a, 'b> { } } -pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> Box { +pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, + tts: &[ast::TokenTree]) + -> Box { match parse_args(ecx, sp, false, tts) { (invocation, Some((efmt, args, order, names))) => { @@ -680,8 +681,8 @@ pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span, } } -pub fn expand_format_args_method(ecx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> Box { +pub fn expand_format_args_method<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, + tts: &[ast::TokenTree]) -> Box { match parse_args(ecx, sp, true, tts) { (invocation, Some((efmt, args, order, names))) => { diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 1f4d087abd0..8df5746e412 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -15,10 +15,10 @@ use print; use std::rc::Rc; -pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, - sp: codemap::Span, - tt: &[ast::TokenTree]) - -> Box { +pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, + sp: codemap::Span, + tt: &[ast::TokenTree]) + -> Box { cx.print_backtrace(); println!("{}", print::pprust::tt_to_string(&ast::TTDelim( diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index d7d6c20b475..0c41db7ecd6 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -410,35 +410,36 @@ pub mod rt { } -pub fn expand_quote_tokens(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) - -> Box { +pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { let (cx_expr, expr) = expand_tts(cx, sp, tts); let expanded = expand_wrapper(cx, sp, cx_expr, expr); base::MacExpr::new(expanded) } -pub fn expand_quote_expr(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) -> Box { +pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts); base::MacExpr::new(expanded) } -pub fn expand_quote_item(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) - -> Box { +pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes", vec!(), tts); base::MacExpr::new(expanded) } -pub fn expand_quote_pat(cx: &mut ExtCtxt, - sp: Span, - tts: &[ast::TokenTree]) - -> Box { +pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { let expanded = expand_parse_call(cx, sp, "parse_pat", vec!(), tts); base::MacExpr::new(expanded) } @@ -446,7 +447,7 @@ pub fn expand_quote_pat(cx: &mut ExtCtxt, pub fn expand_quote_arm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts); base::MacExpr::new(expanded) } @@ -454,7 +455,7 @@ pub fn expand_quote_arm(cx: &mut ExtCtxt, pub fn expand_quote_ty(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let e_param_colons = cx.expr_lit(sp, ast::LitBool(false)); let expanded = expand_parse_call(cx, sp, "parse_ty", vec!(e_param_colons), tts); @@ -464,7 +465,7 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt, pub fn expand_quote_method(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let e_param_colons = cx.expr_none(sp); let expanded = expand_parse_call(cx, sp, "parse_method", vec!(e_param_colons), tts); @@ -474,7 +475,7 @@ pub fn expand_quote_method(cx: &mut ExtCtxt, pub fn expand_quote_stmt(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let e_attrs = cx.expr_vec_ng(sp); let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(e_attrs), tts); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 703adcbd335..5cc0ec4a122 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -29,7 +29,7 @@ use std::rc::Rc; /// line!(): expands to the current line number pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { base::check_zero_tts(cx, sp, tts, "line!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); @@ -40,7 +40,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) /* col!(): expands to the current column number */ pub fn expand_col(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { base::check_zero_tts(cx, sp, tts, "col!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); @@ -52,7 +52,7 @@ pub fn expand_col(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) /// The filemap (`loc.file`) contains a bunch more information we could spit /// out if we wanted. pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { base::check_zero_tts(cx, sp, tts, "file!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); @@ -62,14 +62,14 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let s = pprust::tts_to_string(tts); base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(s.as_slice()))) } pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { base::check_zero_tts(cx, sp, tts, "module_path!"); let string = cx.mod_path() .iter() @@ -85,7 +85,7 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) /// This is generally a bad idea because it's going to behave /// unhygienically. pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Some(f) => f, None => return DummyResult::expr(sp), @@ -105,7 +105,7 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // include_str! : read the given file, insert it as a literal string expr pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Some(f) => f, None => return DummyResult::expr(sp) @@ -141,7 +141,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> Box { + -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") { Some(f) => f, None => return DummyResult::expr(sp) diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 77324632664..1f50eb933bb 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -18,7 +18,7 @@ use parse::token::{keywords, is_keyword}; pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[ast::TokenTree]) - -> Box { + -> Box { match tt { [ast::TTTok(_, ref tok)] if is_keyword(keywords::True, tok) => { cx.set_trace_macros(true); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1eb37abb781..d8f0eb32ad7 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -14,7 +14,6 @@ use ast; use codemap::{Span, Spanned, DUMMY_SP}; use ext::base::{ExtCtxt, MacResult, MacroDef}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::base; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_or_else}; @@ -113,11 +112,11 @@ struct MacroRulesMacroExpander { } impl TTMacroExpander for MacroRulesMacroExpander { - fn expand(&self, - cx: &mut ExtCtxt, - sp: Span, - arg: &[ast::TokenTree]) - -> Box { + fn expand<'cx>(&self, + cx: &'cx mut ExtCtxt, + sp: Span, + arg: &[ast::TokenTree]) + -> Box { generic_extension(cx, sp, self.name, @@ -137,13 +136,13 @@ impl MacResult for MacroRulesDefiner { } /// Given `lhses` and `rhses`, this is the new macro we create -fn generic_extension(cx: &ExtCtxt, - sp: Span, - name: Ident, - arg: &[ast::TokenTree], - lhses: &[Rc], - rhses: &[Rc]) - -> Box { +fn generic_extension<'cx>(cx: &'cx ExtCtxt, + sp: Span, + name: Ident, + arg: &[ast::TokenTree], + lhses: &[Rc], + rhses: &[Rc]) + -> Box { if cx.trace_macros() { println!("{}! {} {} {}", token::get_ident(name), @@ -195,7 +194,7 @@ fn generic_extension(cx: &ExtCtxt, // Weird, but useful for X-macros. return box ParserAnyMacro { parser: RefCell::new(p), - } as Box + } as Box } Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; @@ -213,11 +212,11 @@ fn generic_extension(cx: &ExtCtxt, /// This procedure performs the expansion of the /// macro_rules! macro. It parses the RHS and adds /// an extension to the current context. -pub fn add_new_extension(cx: &mut ExtCtxt, - sp: Span, - name: Ident, - arg: Vec ) - -> Box { +pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + name: Ident, + arg: Vec ) + -> Box { // these spans won't matter, anyways fn ms(m: Matcher_) -> Matcher { Spanned { @@ -274,5 +273,5 @@ pub fn add_new_extension(cx: &mut ExtCtxt, name: token::get_ident(name).to_string(), ext: NormalTT(exp, Some(sp)) })) - } as Box + } as Box } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4a0787aeb9e..be1c0d96711 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -227,15 +227,20 @@ pub trait Folder { noop_fold_variant_arg(va, self) } - fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound { - noop_fold_ty_param_bound(tpb, self) - } - fn fold_opt_bounds(&mut self, b: &Option>) -> Option> { noop_fold_opt_bounds(b, self) } + fn fold_bounds(&mut self, b: &OwnedSlice) + -> OwnedSlice { + noop_fold_bounds(b, self) + } + + fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound { + noop_fold_ty_param_bound(tpb, self) + } + fn fold_mt(&mut self, mt: &MutTy) -> MutTy { noop_fold_mt(mt, self) } @@ -349,20 +354,20 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyRptr(ref region, ref mt) => { TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) } - TyClosure(ref f, ref region) => { + TyClosure(ref f) => { TyClosure(box(GC) ClosureTy { fn_style: f.fn_style, onceness: f.onceness, - bounds: fld.fold_opt_bounds(&f.bounds), + bounds: fld.fold_bounds(&f.bounds), decl: fld.fold_fn_decl(&*f.decl), lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()), - }, fld.fold_opt_lifetime(region)) + }) } TyProc(ref f) => { TyProc(box(GC) ClosureTy { fn_style: f.fn_style, onceness: f.onceness, - bounds: fld.fold_opt_bounds(&f.bounds), + bounds: fld.fold_bounds(&f.bounds), decl: fld.fold_fn_decl(&*f.decl), lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()), }) @@ -648,14 +653,13 @@ pub fn noop_fold_ty_param_bound(tpb: &TyParamBound, fld: &mut T) -> TyParamBound { match *tpb { TraitTyParamBound(ref ty) => TraitTyParamBound(fld.fold_trait_ref(ty)), - StaticRegionTyParamBound => StaticRegionTyParamBound, + RegionTyParamBound(ref lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), UnboxedFnTyParamBound(ref unboxed_function_type) => { UnboxedFnTyParamBound(UnboxedFnTy { decl: fld.fold_fn_decl(&*unboxed_function_type.decl), kind: unboxed_function_type.kind, }) } - OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s) } } @@ -664,7 +668,7 @@ pub fn noop_fold_ty_param(tp: &TyParam, fld: &mut T) -> TyParam { TyParam { ident: tp.ident, id: id, - bounds: tp.bounds.map(|x| fld.fold_ty_param_bound(x)), + bounds: fld.fold_bounds(&tp.bounds), unbound: tp.unbound.as_ref().map(|x| fld.fold_ty_param_bound(x)), default: tp.default.map(|x| fld.fold_ty(x)), span: tp.span @@ -792,11 +796,12 @@ pub fn noop_fold_mt(mt: &MutTy, folder: &mut T) -> MutTy { pub fn noop_fold_opt_bounds(b: &Option>, folder: &mut T) -> Option> { - b.as_ref().map(|bounds| { - bounds.map(|bound| { - folder.fold_ty_param_bound(bound) - }) - }) + b.as_ref().map(|bounds| folder.fold_bounds(bounds)) +} + +fn noop_fold_bounds(bounds: &TyParamBounds, folder: &mut T) + -> TyParamBounds { + bounds.map(|bound| folder.fold_ty_param_bound(bound)) } pub fn noop_fold_variant_arg(va: &VariantArg, folder: &mut T) -> VariantArg { @@ -889,7 +894,8 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ }).collect() ) } - ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { + ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => { + let bounds = folder.fold_bounds(bounds); let methods = methods.iter().flat_map(|method| { let r = match *method { RequiredMethod(ref m) => { @@ -911,7 +917,7 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ }).collect(); ItemTrait(folder.fold_generics(generics), unbound.clone(), - traits.iter().map(|p| folder.fold_trait_ref(p)).collect(), + bounds, methods) } ItemMac(ref m) => ItemMac(folder.fold_mac(m)), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 291c876082f..9bbd6b2a36e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -25,6 +25,7 @@ #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)] #![feature(quote, struct_variant, unsafe_destructor, import_shadowing)] +#![feature(issue_5723_bootstrap)] #![allow(deprecated)] // NOTE(stage0, pcwalton): Remove after snapshot. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 816700681cf..37bda15ac2c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -12,7 +12,7 @@ use abi; use ast::{BareFnTy, ClosureTy}; -use ast::{StaticRegionTyParamBound, OtherRegionTyParamBound, TraitTyParamBound}; +use ast::{RegionTyParamBound, TraitTyParamBound}; use ast::{ProvidedMethod, Public, FnStyle}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, Block}; @@ -70,7 +70,7 @@ use parse; use parse::attr::ParserAttr; use parse::classify; use parse::common::{SeqSep, seq_sep_none}; -use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; +use parse::common::{seq_sep_trailing_allowed}; use parse::lexer::Reader; use parse::lexer::TokenAndSpan; use parse::obsolete::*; @@ -120,7 +120,7 @@ pub enum PathParsingMode { /// A path paired with optional type bounds. pub struct PathAndBounds { pub path: ast::Path, - pub bounds: Option>, + pub bounds: Option, } enum ItemOrViewItem { @@ -309,7 +309,7 @@ pub struct Parser<'a> { pub tokens_consumed: uint, pub restriction: restriction, pub quote_depth: uint, // not (yet) related to the quasiquoter - pub reader: Box, + pub reader: Box, pub interner: Rc, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice @@ -346,8 +346,11 @@ fn real_token(rdr: &mut Reader) -> TokenAndSpan { } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig, - mut rdr: Box) -> Parser<'a> { + pub fn new(sess: &'a ParseSess, + cfg: ast::CrateConfig, + mut rdr: Box) + -> Parser<'a> + { let tok0 = real_token(rdr); let span = tok0.sp; let placeholder = TokenAndSpan { @@ -1073,14 +1076,7 @@ impl<'a> Parser<'a> { }; let (inputs, variadic) = self.parse_fn_args(false, false); - let bounds = { - if self.eat(&token::COLON) { - let (_, bounds) = self.parse_ty_param_bounds(false); - Some(bounds) - } else { - None - } - }; + let bounds = self.parse_colon_then_ty_param_bounds(); let (ret_style, ret_ty) = self.parse_ret_ty(); let decl = P(FnDecl { inputs: inputs, @@ -1168,14 +1164,7 @@ impl<'a> Parser<'a> { (optional_unboxed_closure_kind, inputs) }; - let (region, bounds) = { - if self.eat(&token::COLON) { - let (region, bounds) = self.parse_ty_param_bounds(true); - (region, Some(bounds)) - } else { - (None, None) - } - }; + let bounds = self.parse_colon_then_ty_param_bounds(); let (return_style, output) = self.parse_ret_ty(); let decl = P(FnDecl { @@ -1199,7 +1188,7 @@ impl<'a> Parser<'a> { bounds: bounds, decl: decl, lifetimes: lifetime_defs, - }, region) + }) } } } @@ -1687,7 +1676,7 @@ impl<'a> Parser<'a> { Some(INTERPOLATED(token::NtPath(box path))) => { return PathAndBounds { path: path, - bounds: None, + bounds: None } } _ => {} @@ -1744,25 +1733,31 @@ impl<'a> Parser<'a> { } } - // Next, parse a plus and bounded type parameters, if applicable. - let bounds = if mode == LifetimeAndTypesAndBounds { - let bounds = { - if self.eat(&token::BINOP(token::PLUS)) { - let (_, bounds) = self.parse_ty_param_bounds(false); - if bounds.len() == 0 { - let last_span = self.last_span; - self.span_err(last_span, - "at least one type parameter bound \ - must be specified after the `+`"); - } - Some(bounds) - } else { - None + // Next, parse a plus and bounded type parameters, if + // applicable. We need to remember whether the separate was + // present for later, because in some contexts it's a parse + // error. + let opt_bounds = { + if mode == LifetimeAndTypesAndBounds && + self.eat(&token::BINOP(token::PLUS)) + { + let bounds = self.parse_ty_param_bounds(); + + // For some reason that I do not fully understand, we + // do not permit an empty list in the case where it is + // introduced by a `+`, but we do for `:` and other + // separators. -nmatsakis + if bounds.len() == 0 { + let last_span = self.last_span; + self.span_err(last_span, + "at least one type parameter bound \ + must be specified"); } - }; - bounds - } else { - None + + Some(bounds) + } else { + None + } }; // Assemble the span. @@ -1775,7 +1770,7 @@ impl<'a> Parser<'a> { global: is_global, segments: segments, }, - bounds: bounds, + bounds: opt_bounds, } } @@ -3604,45 +3599,34 @@ impl<'a> Parser<'a> { } } - /// matches optbounds = ( ( : ( boundseq )? )? ) - /// where boundseq = ( bound + boundseq ) | bound - /// and bound = 'static | ty - /// Returns "None" if there's no colon (e.g. "T"); - /// Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:") - /// Returns "Some(stuff)" otherwise (e.g. "T:stuff"). - /// NB: The None/Some distinction is important for issue #7264. - /// - /// Note that the `allow_any_lifetime` argument is a hack for now while the - /// AST doesn't support arbitrary lifetimes in bounds on type parameters. In - /// the future, this flag should be removed, and the return value of this - /// function should be Option<~[TyParamBound]> - fn parse_ty_param_bounds(&mut self, allow_any_lifetime: bool) - -> (Option, - OwnedSlice) { - let mut ret_lifetime = None; + // Parses a sequence of bounds if a `:` is found, + // otherwise returns empty list. + fn parse_colon_then_ty_param_bounds(&mut self) + -> OwnedSlice + { + if !self.eat(&token::COLON) { + OwnedSlice::empty() + } else { + self.parse_ty_param_bounds() + } + } + + // matches bounds = ( boundseq )? + // where boundseq = ( bound + boundseq ) | bound + // and bound = 'region | ty + // NB: The None/Some distinction is important for issue #7264. + fn parse_ty_param_bounds(&mut self) + -> OwnedSlice + { let mut result = vec!(); loop { match self.token { token::LIFETIME(lifetime) => { - let lifetime_interned_string = token::get_ident(lifetime); - if lifetime_interned_string.equiv(&("'static")) { - result.push(StaticRegionTyParamBound); - if allow_any_lifetime && ret_lifetime.is_none() { - ret_lifetime = Some(ast::Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.span, - name: lifetime.name - }); - } - } else if allow_any_lifetime && ret_lifetime.is_none() { - ret_lifetime = Some(ast::Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.span, - name: lifetime.name - }); - } else { - result.push(OtherRegionTyParamBound(self.span)); - } + result.push(RegionTyParamBound(ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: self.span, + name: lifetime.name + })); self.bump(); } token::MOD_SEP | token::IDENT(..) => { @@ -3662,7 +3646,7 @@ impl<'a> Parser<'a> { } } - return (ret_lifetime, OwnedSlice::from_vec(result)); + return OwnedSlice::from_vec(result); } fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { @@ -3699,16 +3683,7 @@ impl<'a> Parser<'a> { ident = self.parse_ident(); } - let opt_bounds = { - if self.eat(&token::COLON) { - let (_, bounds) = self.parse_ty_param_bounds(false); - Some(bounds) - } else { - None - } - }; - // For typarams we don't care about the difference b/w "" and "". - let bounds = opt_bounds.unwrap_or_default(); + let bounds = self.parse_colon_then_ty_param_bounds(); let default = if self.token == token::EQ { self.bump(); @@ -3797,7 +3772,7 @@ impl<'a> Parser<'a> { }; self.expect(&token::COLON); - let (_, bounds) = self.parse_ty_param_bounds(false); + let bounds = self.parse_ty_param_bounds(); let hi = self.span.hi; let span = mk_sp(lo, hi); @@ -4273,19 +4248,13 @@ impl<'a> Parser<'a> { let mut tps = self.parse_generics(); let sized = self.parse_for_sized(); - // Parse traits, if necessary. - let traits; - if self.token == token::COLON { - self.bump(); - traits = self.parse_trait_ref_list(&token::LBRACE); - } else { - traits = Vec::new(); - } + // Parse supertrait bounds. + let bounds = self.parse_colon_then_ty_param_bounds(); self.parse_where_clause(&mut tps); let meths = self.parse_trait_methods(); - (ident, ItemTrait(tps, sized, traits, meths), None) + (ident, ItemTrait(tps, sized, bounds, meths), None) } fn parse_impl_items(&mut self) -> (Vec, Vec) { @@ -4319,12 +4288,10 @@ impl<'a> Parser<'a> { // New-style trait. Reinterpret the type as a trait. let opt_trait_ref = match ty.node { TyPath(ref path, None, node_id) => { - Some(TraitRef { - path: /* bad */ (*path).clone(), - ref_id: node_id - }) + Some(TraitRef { path: (*path).clone(), + ref_id: node_id }) } - TyPath(..) => { + TyPath(_, Some(_), _) => { self.span_err(ty.span, "bounded traits are only valid in type position"); None @@ -4359,15 +4326,6 @@ impl<'a> Parser<'a> { } } - /// Parse B + C + D - fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec { - self.parse_seq_to_before_end( - ket, - seq_sep_trailing_disallowed(token::BINOP(token::PLUS)), - |p| p.parse_trait_ref() - ) - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo { let class_name = self.parse_ident(); diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index f28e6829b00..70da4e11961 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -155,7 +155,7 @@ pub struct PrintStackElem { static SIZE_INFINITY: int = 0xffff; -pub fn mk_printer(out: Box, linewidth: uint) -> Printer { +pub fn mk_printer(out: Box, linewidth: uint) -> Printer { // Yes 3, it makes the ring buffers big enough to never // fall behind. let n: uint = 3 * linewidth; @@ -260,7 +260,7 @@ pub fn mk_printer(out: Box, linewidth: uint) -> Printer { /// the method called 'pretty_print', and the 'PRINT' process is the method /// called 'print'. pub struct Printer { - pub out: Box, + pub out: Box, buf_len: uint, /// Width of lines we're constrained to margin: int, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 41f95fa75f5..da265d81250 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -10,8 +10,8 @@ use abi; use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind}; -use ast::{FnUnboxedClosureKind, MethodImplItem, P, OtherRegionTyParamBound}; -use ast::{StaticRegionTyParamBound, TraitTyParamBound, UnboxedClosureKind}; +use ast::{FnUnboxedClosureKind, MethodImplItem, P}; +use ast::{RegionTyParamBound, TraitTyParamBound, UnboxedClosureKind}; use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod}; use ast; use ast_util; @@ -60,16 +60,16 @@ pub struct State<'a> { literals: Option >, cur_cmnt_and_lit: CurrentCommentAndLiteral, boxes: Vec, - ann: &'a PpAnn, + ann: &'a PpAnn+'a, encode_idents_with_hygiene: bool, } -pub fn rust_printer(writer: Box) -> State<'static> { +pub fn rust_printer(writer: Box) -> State<'static> { static NO_ANN: NoAnn = NoAnn; rust_printer_annotated(writer, &NO_ANN) } -pub fn rust_printer_annotated<'a>(writer: Box, +pub fn rust_printer_annotated<'a>(writer: Box, ann: &'a PpAnn) -> State<'a> { State { s: pp::mk_printer(writer, default_columns), @@ -98,7 +98,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, krate: &ast::Crate, filename: String, input: &mut io::Reader, - out: Box, + out: Box, ann: &'a PpAnn, is_expanded: bool) -> IoResult<()> { let mut s = State::new_from_input(cm, @@ -118,7 +118,7 @@ impl<'a> State<'a> { span_diagnostic: &diagnostic::SpanHandler, filename: String, input: &mut io::Reader, - out: Box, + out: Box, ann: &'a PpAnn, is_expanded: bool) -> State<'a> { let (cmnts, lits) = comments::gather_comments_and_literals( @@ -138,7 +138,7 @@ impl<'a> State<'a> { } pub fn new(cm: &'a CodeMap, - out: Box, + out: Box, ann: &'a PpAnn, comments: Option>, literals: Option>) -> State<'a> { @@ -594,17 +594,16 @@ impl<'a> State<'a> { }; try!(self.print_ty_fn(Some(f.abi), None, - &None, f.fn_style, ast::Many, &*f.decl, None, - &None, + &OwnedSlice::empty(), Some(&generics), None, None)); } - ast::TyClosure(f, ref region) => { + ast::TyClosure(f) => { let generics = ast::Generics { lifetimes: f.lifetimes.clone(), ty_params: OwnedSlice::empty(), @@ -615,7 +614,6 @@ impl<'a> State<'a> { }; try!(self.print_ty_fn(None, Some('&'), - region, f.fn_style, f.onceness, &*f.decl, @@ -636,7 +634,6 @@ impl<'a> State<'a> { }; try!(self.print_ty_fn(None, Some('~'), - &None, f.fn_style, f.onceness, &*f.decl, @@ -649,12 +646,11 @@ impl<'a> State<'a> { ast::TyUnboxedFn(f) => { try!(self.print_ty_fn(None, None, - &None, ast::NormalFn, ast::Many, &*f.decl, None, - &None, + &OwnedSlice::empty(), None, None, Some(f.kind))); @@ -837,7 +833,7 @@ impl<'a> State<'a> { } try!(self.bclose(item.span)); } - ast::ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { + ast::ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => { try!(self.head(visibility_qualified(item.vis, "trait").as_slice())); try!(self.print_ident(item.ident)); @@ -851,16 +847,7 @@ impl<'a> State<'a> { } _ => {} } - if traits.len() != 0u { - try!(word(&mut self.s, ":")); - for (i, trait_) in traits.iter().enumerate() { - try!(self.nbsp()); - if i != 0 { - try!(self.word_space("+")); - } - try!(self.print_path(&trait_.path, false)); - } - } + try!(self.print_bounds(":", bounds)); try!(self.print_where_clause(generics)); try!(word(&mut self.s, " ")); try!(self.bopen()); @@ -1073,12 +1060,11 @@ impl<'a> State<'a> { try!(self.print_outer_attributes(m.attrs.as_slice())); try!(self.print_ty_fn(None, None, - &None, m.fn_style, ast::Many, &*m.decl, Some(m.ident), - &None, + &OwnedSlice::empty(), Some(&m.generics), Some(m.explicit_self.node), None)); @@ -1808,7 +1794,7 @@ impl<'a> State<'a> { match *opt_bounds { None => Ok(()), - Some(ref bounds) => self.print_bounds(&None, bounds, true, true), + Some(ref bounds) => self.print_bounds("+", bounds) } } @@ -2132,30 +2118,12 @@ impl<'a> State<'a> { } pub fn print_bounds(&mut self, - region: &Option, - bounds: &OwnedSlice, - print_colon_anyway: bool, - print_plus_before_bounds: bool) + prefix: &str, + bounds: &OwnedSlice) -> IoResult<()> { - let separator = if print_plus_before_bounds { - "+" - } else { - ":" - }; - if !bounds.is_empty() || region.is_some() { - try!(word(&mut self.s, separator)); + if !bounds.is_empty() { + try!(word(&mut self.s, prefix)); let mut first = true; - match *region { - Some(ref lt) => { - let token = token::get_name(lt.name); - if token.get() != "'static" { - try!(self.nbsp()); - first = false; - try!(self.print_lifetime(lt)); - } - } - None => {} - } for bound in bounds.iter() { try!(self.nbsp()); if first { @@ -2165,27 +2133,27 @@ impl<'a> State<'a> { } try!(match *bound { - TraitTyParamBound(ref tref) => self.print_trait_ref(tref), - StaticRegionTyParamBound => word(&mut self.s, "'static"), + TraitTyParamBound(ref tref) => { + self.print_trait_ref(tref) + } + RegionTyParamBound(ref lt) => { + self.print_lifetime(lt) + } UnboxedFnTyParamBound(ref unboxed_function_type) => { self.print_ty_fn(None, None, - &None, ast::NormalFn, ast::Many, &*unboxed_function_type.decl, None, - &None, + &OwnedSlice::empty(), None, None, Some(unboxed_function_type.kind)) } - OtherRegionTyParamBound(_) => Ok(()) }) } Ok(()) - } else if print_colon_anyway { - word(&mut self.s, separator) } else { Ok(()) } @@ -2212,23 +2180,29 @@ impl<'a> State<'a> { Ok(()) } - fn print_type_parameters(&mut self, - lifetimes: &[ast::LifetimeDef], - ty_params: &[ast::TyParam]) - -> IoResult<()> { - let total = lifetimes.len() + ty_params.len(); + pub fn print_generics(&mut self, + generics: &ast::Generics) + -> IoResult<()> + { + let total = generics.lifetimes.len() + generics.ty_params.len(); + if total == 0 { + return Ok(()); + } + + try!(word(&mut self.s, "<")); + let mut ints = Vec::new(); for i in range(0u, total) { ints.push(i); } - self.commasep(Inconsistent, ints.as_slice(), |s, &idx| { - if idx < lifetimes.len() { - let lifetime = &lifetimes[idx]; + try!(self.commasep(Inconsistent, ints.as_slice(), |s, &idx| { + if idx < generics.lifetimes.len() { + let lifetime = generics.lifetimes.get(idx); s.print_lifetime_def(lifetime) } else { - let idx = idx - lifetimes.len(); - let param = &ty_params[idx]; + let idx = idx - generics.lifetimes.len(); + let param = generics.ty_params.get(idx); match param.unbound { Some(TraitTyParamBound(ref tref)) => { try!(s.print_trait_ref(tref)); @@ -2237,10 +2211,7 @@ impl<'a> State<'a> { _ => {} } try!(s.print_ident(param.ident)); - try!(s.print_bounds(&None, - ¶m.bounds, - false, - false)); + try!(s.print_bounds(":", ¶m.bounds)); match param.default { Some(ref default) => { try!(space(&mut s.s)); @@ -2250,19 +2221,10 @@ impl<'a> State<'a> { _ => Ok(()) } } - }) - } + })); - pub fn print_generics(&mut self, generics: &ast::Generics) - -> IoResult<()> { - if generics.lifetimes.len() + generics.ty_params.len() > 0 { - try!(word(&mut self.s, "<")); - try!(self.print_type_parameters(generics.lifetimes.as_slice(), - generics.ty_params.as_slice())); - word(&mut self.s, ">") - } else { - Ok(()) - } + try!(word(&mut self.s, ">")); + Ok(()) } pub fn print_where_clause(&mut self, generics: &ast::Generics) @@ -2283,7 +2245,7 @@ impl<'a> State<'a> { } try!(self.print_ident(predicate.ident)); - try!(self.print_bounds(&None, &predicate.bounds, false, false)); + try!(self.print_bounds(":", &predicate.bounds)); } Ok(()) @@ -2421,12 +2383,11 @@ impl<'a> State<'a> { pub fn print_ty_fn(&mut self, opt_abi: Option, opt_sigil: Option, - opt_region: &Option, fn_style: ast::FnStyle, onceness: ast::Onceness, decl: &ast::FnDecl, id: Option, - opt_bounds: &Option>, + bounds: &OwnedSlice, generics: Option<&ast::Generics>, opt_explicit_self: Option, opt_unboxed_closure_kind: @@ -2495,9 +2456,7 @@ impl<'a> State<'a> { try!(self.pclose()); } - opt_bounds.as_ref().map(|bounds| { - self.print_bounds(opt_region, bounds, true, false) - }); + try!(self.print_bounds(":", bounds)); try!(self.maybe_print_comment(decl.output.span.lo)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 6c6f59f0df6..7a35d82b0e4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -298,13 +298,9 @@ pub fn walk_item>(visitor: &mut V, item: &Item, env: E) item.id, env.clone()) } - ItemTrait(ref generics, _, ref trait_paths, ref methods) => { + ItemTrait(ref generics, _, ref bounds, ref methods) => { visitor.visit_generics(generics, env.clone()); - for trait_path in trait_paths.iter() { - visitor.visit_path(&trait_path.path, - trait_path.ref_id, - env.clone()) - } + walk_ty_param_bounds(visitor, bounds, env.clone()); for method in methods.iter() { visitor.visit_trait_item(method, env.clone()) } @@ -375,18 +371,13 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { visitor.visit_ty(&*tuple_element_type, env.clone()) } } - TyClosure(ref function_declaration, ref region) => { + TyClosure(ref function_declaration) => { for argument in function_declaration.decl.inputs.iter() { visitor.visit_ty(&*argument.ty, env.clone()) } visitor.visit_ty(&*function_declaration.decl.output, env.clone()); - for bounds in function_declaration.bounds.iter() { - walk_ty_param_bounds(visitor, bounds, env.clone()) - } - visitor.visit_opt_lifetime_ref( - typ.span, - region, - env.clone()); + walk_ty_param_bounds(visitor, &function_declaration.bounds, + env.clone()); walk_lifetime_decls(visitor, &function_declaration.lifetimes, env.clone()); } @@ -395,9 +386,8 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { visitor.visit_ty(&*argument.ty, env.clone()) } visitor.visit_ty(&*function_declaration.decl.output, env.clone()); - for bounds in function_declaration.bounds.iter() { - walk_ty_param_bounds(visitor, bounds, env.clone()) - } + walk_ty_param_bounds(visitor, &function_declaration.bounds, + env.clone()); walk_lifetime_decls(visitor, &function_declaration.lifetimes, env.clone()); } @@ -415,10 +405,13 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } visitor.visit_ty(&*function_declaration.decl.output, env.clone()); } - TyPath(ref path, ref bounds, id) => { + TyPath(ref path, ref opt_bounds, id) => { visitor.visit_path(path, id, env.clone()); - for bounds in bounds.iter() { - walk_ty_param_bounds(visitor, bounds, env.clone()) + match *opt_bounds { + Some(ref bounds) => { + walk_ty_param_bounds(visitor, bounds, env.clone()); + } + None => { } } } TyFixedLengthVec(ref ty, ref expression) => { @@ -532,7 +525,6 @@ pub fn walk_ty_param_bounds>(visitor: &mut V, TraitTyParamBound(ref typ) => { walk_trait_ref_helper(visitor, typ, env.clone()) } - StaticRegionTyParamBound => {} UnboxedFnTyParamBound(ref function_declaration) => { for argument in function_declaration.decl.inputs.iter() { visitor.visit_ty(&*argument.ty, env.clone()) @@ -540,7 +532,9 @@ pub fn walk_ty_param_bounds>(visitor: &mut V, visitor.visit_ty(&*function_declaration.decl.output, env.clone()); } - OtherRegionTyParamBound(..) => {} + RegionTyParamBound(ref lifetime) => { + visitor.visit_lifetime_ref(lifetime, env.clone()); + } } } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index f4b162f0dd8..4790e3833b7 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -135,10 +135,10 @@ pub trait TDynBenchFn { pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), - StaticMetricFn(proc(&mut MetricMap)), + StaticMetricFn(proc(&mut MetricMap):'static), DynTestFn(proc():Send), - DynMetricFn(proc(&mut MetricMap)), - DynBenchFn(Box) + DynMetricFn(proc(&mut MetricMap):'static), + DynBenchFn(Box) } impl TestFn { diff --git a/src/test/auxiliary/issue-2380.rs b/src/test/auxiliary/issue-2380.rs index c617c1b2d03..1cba738c564 100644 --- a/src/test/auxiliary/issue-2380.rs +++ b/src/test/auxiliary/issue-2380.rs @@ -14,8 +14,8 @@ pub trait i { } -pub fn f() -> Box> { +pub fn f() -> Box+'static> { impl i for () { } - box() () as Box> + box() () as Box+'static> } diff --git a/src/test/auxiliary/issue-7178.rs b/src/test/auxiliary/issue-7178.rs index fe3842ef174..18b464bd924 100644 --- a/src/test/auxiliary/issue-7178.rs +++ b/src/test/auxiliary/issue-7178.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub struct Foo<'a, A>(&'a A); +pub struct Foo<'a, A:'a>(&'a A); impl<'a, A> Foo<'a, A> { pub fn new(a: &'a A) -> Foo<'a, A> { diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index b6283206676..0a9cfb5884f 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -40,7 +40,7 @@ pub fn plugin_registrar(reg: &mut Registry) { } fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { + -> Box { if !tts.is_empty() { cx.span_fatal(sp, "make_a_1 takes no arguments"); } @@ -49,7 +49,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) // See Issue #15750 fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) - -> Box { + -> Box { // Parse an expression and emit it unchanged. let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), Vec::from_slice(tts)); @@ -65,7 +65,7 @@ fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: Gc, it: Gc) } } -fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { +fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { use syntax::ext::quote::rt::*; if !tts.is_empty() { diff --git a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs new file mode 100644 index 00000000000..a7429ca534b --- /dev/null +++ b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs @@ -0,0 +1,33 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that method bounds declared on traits/impls in a cross-crate +// scenario work. This is the libary portion of the test. + +pub enum MaybeOwned<'a> { + Owned(int), + Borrowed(&'a int) +} + +struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a int +} + +// I encountered a bug at some point with encoding the IntoMaybeOwned +// trait, so I'll use that as the template for this test. +pub trait IntoMaybeOwned<'a> { + fn into_maybe_owned(self) -> MaybeOwned<'a>; + fn bigger_region<'b:'a>(self, b: Inv<'b>); +} + +impl<'a> IntoMaybeOwned<'a> for Inv<'a> { + fn into_maybe_owned(self) -> MaybeOwned<'a> { fail!() } + fn bigger_region<'b:'a>(self, b: Inv<'b>) { fail!() } +} diff --git a/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs b/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs index b5d13d15493..7a4339aa9f0 100644 --- a/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs +++ b/src/test/auxiliary/syntax-extension-with-dll-deps-2.rs @@ -29,7 +29,7 @@ pub fn plugin_registrar(reg: &mut Registry) { } fn expand_foo(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { + -> Box { let answer = other::the_answer(); MacExpr::new(quote_expr!(cx, $answer)) } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index adec9d31afe..03f98686324 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -77,7 +77,7 @@ struct AminoAcid { p: f32, } -struct RepeatFasta<'a, W> { +struct RepeatFasta<'a, W:'a> { alu: &'static str, out: &'a mut W } @@ -126,7 +126,7 @@ fn make_lookup(a: &[AminoAcid]) -> [AminoAcid, ..LOOKUP_SIZE] { lookup } -struct RandomFasta<'a, W> { +struct RandomFasta<'a, W:'a> { seed: u32, lookup: [AminoAcid, ..LOOKUP_SIZE], out: &'a mut W, diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index 9be111f55ae..c46c44abcd4 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -69,11 +69,11 @@ impl<'a, T> Iterator for Iterate<'a, T> { } // a linked list using borrowed next. -enum List<'a, T> { +enum List<'a, T:'a> { Nil, Cons(T, &'a List<'a, T>) } -struct ListIterator<'a, T> { +struct ListIterator<'a, T:'a> { cur: &'a List<'a, T> } impl<'a, T> List<'a, T> { diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index db6db02ded5..b63ecc6b66f 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo() { +fn foo() { 1u.bar::(); //~ ERROR: does not fulfill `Send` } diff --git a/src/test/compile-fail/borrowck-call-sendfn.rs b/src/test/compile-fail/borrowck-call-sendfn.rs index 57c0deb178d..eb2ea6b3de4 100644 --- a/src/test/compile-fail/borrowck-call-sendfn.rs +++ b/src/test/compile-fail/borrowck-call-sendfn.rs @@ -9,7 +9,7 @@ // except according to those terms. struct Foo { - f: proc() + f: proc():'static } fn call(x: Foo) { diff --git a/src/test/compile-fail/borrowck-object-lifetime.rs b/src/test/compile-fail/borrowck-object-lifetime.rs index c55a5a30538..bbb58e21198 100644 --- a/src/test/compile-fail/borrowck-object-lifetime.rs +++ b/src/test/compile-fail/borrowck-object-lifetime.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,17 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that borrows that occur due to calls to object methods +// properly "claim" the object path. trait Foo { fn borrowed(&self) -> &(); + fn mut_borrowed(&mut self) -> &(); } -fn borrowed_receiver(x: &Foo) -> &() { - x.borrowed() +fn borrowed_receiver(x: &Foo) { + let _y = x.borrowed(); + let _z = x.borrowed(); } -fn owned_receiver(x: Box) -> &'static () { - x.borrowed() //~ ERROR `*x` does not live long enough +fn mut_borrowed_receiver(x: &mut Foo) { + let _y = x.borrowed(); + let _z = x.mut_borrowed(); //~ ERROR cannot borrow } fn mut_owned_receiver(mut x: Box) { diff --git a/src/test/compile-fail/box-static-bound.rs b/src/test/compile-fail/box-static-bound.rs index 5ef52ab6645..29ee79b0079 100644 --- a/src/test/compile-fail/box-static-bound.rs +++ b/src/test/compile-fail/box-static-bound.rs @@ -12,7 +12,7 @@ use std::gc::{Gc, GC}; fn f(x: T) -> Gc { - box(GC) x //~ ERROR value may contain references + box(GC) x //~ ERROR the parameter type `T` may not live long enough } fn g(x: T) -> Gc { diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs index 67222bdafbf..726413981a5 100644 --- a/src/test/compile-fail/builtin-superkinds-self-type.rs +++ b/src/test/compile-fail/builtin-superkinds-self-type.rs @@ -11,7 +11,7 @@ // Tests (negatively) the ability for the Self type in default methods // to use capabilities granted by builtin kinds as supertraits. -trait Foo : Sync { +trait Foo : Sync+'static { fn foo(self, mut chan: Sender) { chan.send(self); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs index 951354d964d..1ff9dc9dac4 100644 --- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -13,7 +13,7 @@ struct X { } fn foo(blk: ||:'static) -> X { - return X { field: blk }; //~ ERROR expected bounds `'static+Send` + return X { field: blk }; //~ ERROR expected bounds `Send` } fn main() { diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs index 9176412cd79..c0b463535d4 100644 --- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -12,8 +12,8 @@ fn bar(blk: ||:'static) { } fn foo(x: &()) { - bar(|| { //~ ERROR cannot infer an appropriate lifetime - let _ = x; + bar(|| { + let _ = x; //~ ERROR captured variable `x` does not outlive }) } diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index d69a56b76b0..5bd9f20dd83 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -9,13 +9,13 @@ // except according to those terms. -fn take_any(_: ||:) { +fn take_any(_: ||) { } fn take_const_owned(_: ||:Sync+Send) { } -fn give_any(f: ||:) { +fn give_any(f: ||) { take_any(f); } diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index bf501ecfb70..af4c12c754b 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -14,7 +14,6 @@ type Foo = Vec; impl Drop for Foo { //~^ ERROR cannot provide an extension implementation -//~^^ ERROR multiple applicable methods fn drop(&mut self) { println!("kaboom"); } diff --git a/src/test/compile-fail/isuue-12470.rs b/src/test/compile-fail/issue-12470.rs similarity index 98% rename from src/test/compile-fail/isuue-12470.rs rename to src/test/compile-fail/issue-12470.rs index bf13b7ebbdb..aa7e3cd3739 100644 --- a/src/test/compile-fail/isuue-12470.rs +++ b/src/test/compile-fail/issue-12470.rs @@ -24,7 +24,7 @@ impl X for B { } struct A<'a> { - p: &'a X + p: &'a X+'a } fn make_a<'a>(p: &'a X) -> A<'a> { diff --git a/src/test/compile-fail/issue-14285.rs b/src/test/compile-fail/issue-14285.rs index d5e608ecae3..624ddf0c8bb 100644 --- a/src/test/compile-fail/issue-14285.rs +++ b/src/test/compile-fail/issue-14285.rs @@ -14,7 +14,7 @@ struct A; impl Foo for A {} -struct B<'a>(&'a Foo); +struct B<'a>(&'a Foo+'a); fn foo<'a>(a: &Foo) -> B<'a> { B(a) //~ ERROR cannot infer an appropriate lifetime diff --git a/src/test/compile-fail/issue-3154.rs b/src/test/compile-fail/issue-3154.rs index 141bf2b4279..5f55c550aeb 100644 --- a/src/test/compile-fail/issue-3154.rs +++ b/src/test/compile-fail/issue-3154.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct thing<'a, Q> { +struct thing<'a, Q:'a> { x: &'a Q } diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index ab9f7a84530..71f91050256 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -11,12 +11,12 @@ // aux-build:issue_3907.rs extern crate issue_3907; -type Foo = issue_3907::Foo; +type Foo = issue_3907::Foo+'static; struct S { name: int } -fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type `issue_3907::Foo` +fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type fn main() {} diff --git a/src/test/compile-fail/issue-3953.rs b/src/test/compile-fail/issue-3953.rs index 4484a004251..ab2018af999 100644 --- a/src/test/compile-fail/issue-3953.rs +++ b/src/test/compile-fail/issue-3953.rs @@ -12,15 +12,9 @@ use std::cmp::PartialEq; -trait Hahaha: PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + //~ ERROR duplicate supertrait - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + PartialEq + - PartialEq {} +trait Hahaha: PartialEq + PartialEq { + //~^ ERROR trait `PartialEq` already appears in the list of bounds +} struct Lol(int); diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index 199bc3f5c29..bff167fa391 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -12,12 +12,12 @@ trait MyTrait { } pub enum TraitWrapper { - A(Box), + A(Box), } fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { - A(box ref map) => map, //~ ERROR type `Box` cannot be dereferenced + A(box ref map) => map, //~ ERROR cannot be dereferenced } } diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index 689b8f7c613..0251a06c5bd 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -9,8 +9,8 @@ // except according to those terms. trait I {} -type K = I; +type K = I+'static; -fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type `I` +fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type fn main() {} diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs index ec9ec9565c4..18af9736ed9 100644 --- a/src/test/compile-fail/issue-5216.rs +++ b/src/test/compile-fail/issue-5216.rs @@ -9,12 +9,12 @@ // except according to those terms. fn f() { } -struct S(||); //~ ERROR missing lifetime specifier +struct S(||); //~ ERROR explicit lifetime bound required pub static C: S = S(f); fn g() { } -type T = ||; //~ ERROR missing lifetime specifier +type T = ||; //~ ERROR explicit lifetime bound required pub static D: T = g; fn main() {} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 14136d96c2d..f3bbb8051b7 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -11,14 +11,14 @@ trait A {} struct Struct { - r: A + r: A+'static } -fn new_struct(r: A) -> Struct { - //~^ ERROR variable `r` has dynamically sized type `A` +fn new_struct(r: A+'static) -> Struct { + //~^ ERROR variable `r` has dynamically sized type Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct } trait Curve {} -enum E {X(Curve)} +enum E {X(Curve+'static)} fn main() {} diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 48e1bdd671a..4cc03ee3dcd 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -28,7 +28,7 @@ fn f(val: T) { fn main() { let t: S<&int> = S; let a = &t as &Gettable<&int>; - //~^ ERROR instantiating a type parameter with an incompatible type `&int` + //~^ ERROR instantiating a type parameter with an incompatible type let t: Box> = box S; let a = t as Box>; //~^ ERROR instantiating a type parameter with an incompatible type diff --git a/src/test/compile-fail/proc-bounds.rs b/src/test/compile-fail/kindck-proc-bounds.rs similarity index 83% rename from src/test/compile-fail/proc-bounds.rs rename to src/test/compile-fail/kindck-proc-bounds.rs index e8c6a3ba191..57c8cc3da8a 100644 --- a/src/test/compile-fail/proc-bounds.rs +++ b/src/test/compile-fail/kindck-proc-bounds.rs @@ -10,16 +10,13 @@ fn is_send() {} fn is_freeze() {} -fn is_static() {} -fn main() { +fn foo<'a>() { is_send::(); //~^ ERROR: instantiating a type parameter with an incompatible type is_freeze::(); //~^ ERROR: instantiating a type parameter with an incompatible type - - is_static::(); - //~^ ERROR: instantiating a type parameter with an incompatible type } +fn main() { } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs new file mode 100644 index 00000000000..99519263923 --- /dev/null +++ b/src/test/compile-fail/kindck-send-object.rs @@ -0,0 +1,44 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test which of the builtin types are considered sendable. The tests +// in this file all test the "kind" violates detected during kindck. +// See all `regions-bounded-by-send.rs` + +fn assert_send() { } +trait Dummy { } +trait Message : Send { } + +// careful with object types, who knows what they close over... + +fn object_ref_with_static_bound_not_ok() { + assert_send::<&'static Dummy+'static>(); //~ ERROR does not fulfill +} + +fn box_object_with_no_bound_not_ok<'a>() { + assert_send::>(); //~ ERROR does not fulfill +} + +fn proc_with_no_bound_not_ok<'a>() { + assert_send::(); //~ ERROR does not fulfill +} + +fn closure_with_no_bound_not_ok<'a>() { + assert_send::<||:'static>(); //~ ERROR does not fulfill +} + +fn object_with_send_bound_ok() { + assert_send::<&'static Dummy+Send>(); + assert_send::>(); + assert_send::; + assert_send::<||:Send>; +} + +fn main() { } diff --git a/src/test/compile-fail/kindck-send.rs b/src/test/compile-fail/kindck-send.rs deleted file mode 100644 index 424c7a4e430..00000000000 --- a/src/test/compile-fail/kindck-send.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test which of the builtin types are considered sendable. - - -fn assert_send() { } -trait Dummy { } - -fn test<'a,T,U:Send>(_: &'a int) { - // lifetime pointers with 'static lifetime are ok - assert_send::<&'static int>(); - assert_send::<&'static str>(); - assert_send::<&'static [int]>(); - - // whether or not they are mutable - assert_send::<&'static mut int>(); - - // otherwise lifetime pointers are not ok - assert_send::<&'a int>(); //~ ERROR does not fulfill `Send` - assert_send::<&'a str>(); //~ ERROR does not fulfill `Send` - assert_send::<&'a [int]>(); //~ ERROR does not fulfill `Send` - - // boxes are ok - assert_send::>(); - assert_send::(); - assert_send:: >(); - - // but not if they own a bad thing - assert_send::>(); //~ ERROR does not fulfill `Send` - - // careful with object types, who knows what they close over... - assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send` - assert_send::<&'a Dummy>(); //~ ERROR does not fulfill `Send` - assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill `Send` - assert_send::>(); //~ ERROR does not fulfill `Send` - - // ...unless they are properly bounded - assert_send::<&'static Dummy+Send>(); - assert_send::>(); - - // but closure and object types can have lifetime bounds which make - // them not ok (FIXME #5121) - // assert_send::(); // ERROR does not fulfill `Send` - // assert_send::>(); // ERROR does not fulfill `Send` - - // unsafe ptrs are ok unless they point at unsendable things - assert_send::<*const int>(); - assert_send::<*const &'a int>(); //~ ERROR does not fulfill `Send` -} - -fn main() { -} diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs new file mode 100644 index 00000000000..21bd676a225 --- /dev/null +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } +fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { +//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) + (x.bar, &x.baz, &x.baz) + //~^ ERROR: cannot infer + //~^^ ERROR: cannot infer + //~^^^ ERROR: cannot infer +} + +fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { +//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) + (x.bar, &x.baz, &x.baz) + //~^ ERROR: cannot infer + //~^^ ERROR: cannot infer + //~^^^ ERROR: cannot infer +} + +fn main() { } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index 481fb3dee73..b7da4d73489 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -33,21 +33,6 @@ fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) { //~^ ERROR: cannot infer } -struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } -fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer - //~^ ERROR: cannot infer - //~^^ ERROR: cannot infer -} - -fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer - //~^ ERROR: cannot infer - //~^^ ERROR: cannot infer -} - struct Cat<'x, T> { cat: &'x int, t: T } struct Dog<'y> { dog: &'y int } diff --git a/src/test/compile-fail/moves-sru-moved-field.rs b/src/test/compile-fail/moves-sru-moved-field.rs index 8b02740497d..74e5e6b1202 100644 --- a/src/test/compile-fail/moves-sru-moved-field.rs +++ b/src/test/compile-fail/moves-sru-moved-field.rs @@ -9,7 +9,7 @@ // except according to those terms. -type Noncopyable = proc(); +type Noncopyable = proc():'static; struct Foo { copied: int, diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs new file mode 100644 index 00000000000..40cff3e466b --- /dev/null +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -0,0 +1,44 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test related to when a region bound is required to be specified. + +trait IsStatic : 'static { } +trait IsSend : Send { } +trait Is<'a> : 'a { } +trait Is2<'a> : 'a { } +trait SomeTrait { } + +// Bounds on object types: + +struct Foo<'a,'b,'c> { + // All of these are ok, because we can derive exactly one bound: + a: Box, + b: Box>, + c: Box>, + d: Box, + e: Box+Send>, // we can derive two bounds, but one is 'static, so ok + f: Box, //~ ERROR explicit lifetime bound required + g: Box, + + z: Box+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted +} + +fn test< + 'a, + 'b, + A:IsStatic, + B:Is<'a>+Is2<'b>, //~ ERROR ambiguous lifetime bound + C:'b+Is<'a>+Is2<'b>, + D:Is<'a>+Is2<'static>, + E:'a+'b //~ ERROR only a single explicit lifetime bound is permitted +>() { } + +fn main() { } diff --git a/src/test/compile-fail/region-object-lifetime-1.rs b/src/test/compile-fail/region-object-lifetime-1.rs new file mode 100644 index 00000000000..01daeb628ef --- /dev/null +++ b/src/test/compile-fail/region-object-lifetime-1.rs @@ -0,0 +1,49 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Various tests related to testing how region inference works +// with respect to the object receivers. + +trait Foo { + fn borrowed<'a>(&'a self) -> &'a (); +} + +// Here the receiver and return value all have the same lifetime, +// so no error results. +fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () { + x.borrowed() +} + +// Borrowed receiver but two distinct lifetimes, we get an error. +fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () { + x.borrowed() //~ ERROR cannot infer +} + +// Borrowed receiver with two distinct lifetimes, but we know that +// 'b:'a, hence &'a () is permitted. +fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a Foo+'b) -> &'a () { + x.borrowed() +} + +// Here we have two distinct lifetimes, but we try to return a pointer +// with the longer lifetime when (from the signature) we only know +// that it lives as long as the shorter lifetime. Therefore, error. +fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a Foo+'b) -> &'b () { + x.borrowed() //~ ERROR cannot infer +} + +// Here, the object is bounded by an anonymous lifetime and returned +// as `&'static`, so you get an error. +fn owned_receiver(x: Box) -> &'static () { + x.borrowed() //~ ERROR cannot infer +} + +fn main() {} + diff --git a/src/test/compile-fail/regionck-closure-lifetimes.rs b/src/test/compile-fail/regionck-closure-lifetimes.rs index 846e03d57c3..bb895a318ff 100644 --- a/src/test/compile-fail/regionck-closure-lifetimes.rs +++ b/src/test/compile-fail/regionck-closure-lifetimes.rs @@ -15,7 +15,7 @@ fn env<'a>(blk: |p: ||: 'a|) { let mut state = 0i; let statep = &mut state; - blk(|| *statep = 1i); //~ ERROR cannot infer + blk(|| *statep = 1i); //~ ERROR captured variable `statep` does not outlive } fn no_env_no_for<'a>(blk: |p: |||: 'a) { diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs index 1c590db11e3..7520a4c125a 100644 --- a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs +++ b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs @@ -16,9 +16,8 @@ fn main() { let mut f; { let c = 1; - let c_ref = &c; + let c_ref = &c; //~ ERROR `c` does not live long enough f = |&mut: a: int, b: int| { a + b + *c_ref }; - //~^ ERROR cannot infer an appropriate lifetime } } diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs new file mode 100644 index 00000000000..0c9f5004f57 --- /dev/null +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -0,0 +1,57 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +#![no_std] + +struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a int +} + +pub trait Foo<'a> { + fn no_bound<'b>(self, b: Inv<'b>); + fn has_bound<'b:'a>(self, b: Inv<'b>); + fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + fn wrong_bound2<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); +} + + +impl<'a> Foo<'a> for &'a int { + fn no_bound<'b:'a>(self, b: Inv<'b>) { + //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match + } + + fn has_bound<'b>(self, b: Inv<'b>) { + //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match + } + + fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + //~^ ERROR method `wrong_bound1` has an incompatible type for trait + // + // Note: This is a terrible error message. It is caused + // because, in the trait, 'b is early bound, and in the impl, + // 'c is early bound, so -- after substitution -- the + // lifetimes themselves look isomorphic. We fail because the + // lifetimes that appear in the types are in the wrong + // order. This should really be fixed by keeping more + // information about the lifetime declarations in the trait so + // that we can compare better to the impl, even in cross-crate + // cases. + } + + fn wrong_bound2<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) { + //~^ ERROR distinct set of bounds from its counterpart + } +} + +fn main() { } diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs new file mode 100644 index 00000000000..3c7ffbc8d1f --- /dev/null +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -0,0 +1,91 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test which of the builtin types are considered sendable. The tests +// in this file all test region bound and lifetime violations that are +// detected during type check. + +fn assert_send() { } +trait Dummy { } + +// lifetime pointers with 'static lifetime are ok + +fn static_lifime_ok<'a,T,U:Send>(_: &'a int) { + assert_send::<&'static int>(); + assert_send::<&'static str>(); + assert_send::<&'static [int]>(); + + // whether or not they are mutable + assert_send::<&'static mut int>(); +} + +// otherwise lifetime pointers are not ok + +fn param_not_ok<'a>(x: &'a int) { + assert_send::<&'a int>(); //~ ERROR does not fulfill +} + +fn param_not_ok1<'a>(_: &'a int) { + assert_send::<&'a str>(); //~ ERROR does not fulfill +} + +fn param_not_ok2<'a>(_: &'a int) { + assert_send::<&'a [int]>(); //~ ERROR does not fulfill +} + +// boxes are ok + +fn box_ok() { + assert_send::>(); + assert_send::(); + assert_send::>(); +} + +// but not if they own a bad thing + +fn box_with_region_not_ok<'a>() { + assert_send::>(); //~ ERROR does not fulfill +} + +// objects with insufficient bounds no ok + +fn object_with_random_bound_not_ok<'a>() { + assert_send::<&'a Dummy+'a>(); //~ ERROR does not fulfill +} + +fn object_with_send_bound_not_ok<'a>() { + assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill +} + +fn proc_with_lifetime_not_ok<'a>() { + assert_send::(); //~ ERROR does not fulfill +} + +fn closure_with_lifetime_not_ok<'a>() { + assert_send::<||:'a>(); //~ ERROR does not fulfill +} + +// unsafe pointers are ok unless they point at unsendable things + +fn unsafe_ok1<'a>(_: &'a int) { + assert_send::<*const int>(); + assert_send::<*mut int>(); +} + +fn unsafe_ok2<'a>(_: &'a int) { + assert_send::<*const &'a int>(); //~ ERROR does not fulfill +} + +fn unsafe_ok3<'a>(_: &'a int) { + assert_send::<*mut &'a int>(); //~ ERROR does not fulfill +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs new file mode 100644 index 00000000000..04a94b75215 --- /dev/null +++ b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs @@ -0,0 +1,73 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test which of the builtin types are considered sendable. The tests +// in this file all test region bound and lifetime violations that are +// detected during type check. + +trait Dummy : 'static { } +fn assert_send() { } + +// lifetime pointers with 'static lifetime are ok + +fn static_lifime_ok<'a,T,U:Send>(_: &'a int) { + assert_send::<&'static int>(); + assert_send::<&'static str>(); + assert_send::<&'static [int]>(); + + // whether or not they are mutable + assert_send::<&'static mut int>(); +} + +// otherwise lifetime pointers are not ok + +fn param_not_ok<'a>(x: &'a int) { + assert_send::<&'a int>(); //~ ERROR does not fulfill +} + +fn param_not_ok1<'a>(_: &'a int) { + assert_send::<&'a str>(); //~ ERROR does not fulfill +} + +fn param_not_ok2<'a>(_: &'a int) { + assert_send::<&'a [int]>(); //~ ERROR does not fulfill +} + +// boxes are ok + +fn box_ok() { + assert_send::>(); + assert_send::(); + assert_send::>(); +} + +// but not if they own a bad thing + +fn box_with_region_not_ok<'a>() { + assert_send::>(); //~ ERROR does not fulfill +} + +// unsafe pointers are ok unless they point at unsendable things + +fn unsafe_ok1<'a>(_: &'a int) { + assert_send::<*const int>(); + assert_send::<*mut int>(); +} + +fn unsafe_ok2<'a>(_: &'a int) { + assert_send::<*const &'a int>(); //~ ERROR does not fulfill +} + +fn unsafe_ok3<'a>(_: &'a int) { + assert_send::<*mut &'a int>(); //~ ERROR does not fulfill +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs new file mode 100644 index 00000000000..ab97bad5bc2 --- /dev/null +++ b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs @@ -0,0 +1,33 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:regions-bounded-method-type-parameters-cross-crate-lib.rs + +// Check explicit region bounds on methods in the cross crate case. + +extern crate lib = "regions-bounded-method-type-parameters-cross-crate-lib"; + +use lib::Inv; +use lib::MaybeOwned; +use lib::IntoMaybeOwned; + +fn call_into_maybe_owned<'a,F:IntoMaybeOwned<'a>>(f: F) { + // Exercise a code path I found to be buggy. We were not encoding + // the region parameters from the receiver correctly on trait + // methods. + f.into_maybe_owned(); +} + +fn call_bigger_region<'a, 'b>(a: Inv<'a>, b: Inv<'b>) { + // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. + a.bigger_region(b) //~ ERROR cannot infer +} + +fn main() { } diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs new file mode 100644 index 00000000000..e628eb3285a --- /dev/null +++ b/src/test/compile-fail/regions-bounded-method-type-parameters-trait-bound.rs @@ -0,0 +1,44 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] +#![feature(lang_items)] + +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +#[lang="sized"] +trait Sized { } + +struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a int +} + +trait Foo<'x> { + fn method<'y:'x>(self, y: Inv<'y>); +} + +fn caller1<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'a, and hence 'a:'a holds. + f.method(a); +} + +fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. + f.method(b); //~ ERROR cannot infer +} + +fn caller3<'a,'b:'a,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { + // Here the value provided for 'y is 'b, and hence 'b:'a holds. + f.method(b); +} + +fn main() { } diff --git a/src/test/compile-fail/proc-static-bound.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs similarity index 54% rename from src/test/compile-fail/proc-static-bound.rs rename to src/test/compile-fail/regions-bounded-method-type-parameters.rs index f11ddc0151f..ba1993686d5 100644 --- a/src/test/compile-fail/proc-static-bound.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs @@ -8,19 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - let mut x = Some(1); - let mut p: proc(&mut Option) = proc(_) {}; - match x { - Some(ref y) => { - p = proc(z: &mut Option) { - *z = None; - let _ = y; - //~^ ERROR cannot capture variable of type `&int`, which does not fulfill `'static` - }; - } - None => {} - } - p(&mut x); +#![no_std] + +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +struct Foo; + +impl Foo { + fn some_method(self) { } } +fn caller<'a>(x: &int) { + Foo.some_method::<&'a int>(); + //~^ ERROR does not fulfill the required lifetime +} + +fn main() { } diff --git a/src/test/compile-fail/owned-ptr-static-bound.rs b/src/test/compile-fail/regions-close-object-into-object.rs similarity index 58% rename from src/test/compile-fail/owned-ptr-static-bound.rs rename to src/test/compile-fail/regions-close-object-into-object.rs index dc6e8b1d6be..a45c8e1db54 100644 --- a/src/test/compile-fail/owned-ptr-static-bound.rs +++ b/src/test/compile-fail/regions-close-object-into-object.rs @@ -10,21 +10,25 @@ trait A {} -struct B<'a, T>(&'a A); +struct B<'a, T>(&'a A+'a); trait X {} impl<'a, T> X for B<'a, T> {} -fn f<'a, T, U>(v: Box>) -> Box { - box B(v) as Box //~ ERROR value may contain references; add `'static` bound to `T` +fn f<'a, T, U>(v: Box+'static>) -> Box { + box B(v) as Box } -fn g<'a, T, U>(v: Box>) -> Box { - box B(v) as Box //~ ERROR value may contain references; add `'static` bound to `U` +fn g<'a, T: 'static>(v: Box>) -> Box { + box B(v) as Box //~ ERROR cannot infer } -fn h<'a, T: 'static>(v: Box>) -> Box { - box B(v) as Box // ok +fn h<'a, T, U>(v: Box+'static>) -> Box { + box B(v) as Box +} + +fn i<'a, T, U>(v: Box>) -> Box { + box B(v) as Box //~ ERROR cannot infer } fn main() {} diff --git a/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs similarity index 72% rename from src/test/compile-fail/regions-bound-lists-feature-gate-2.rs rename to src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs index 0f79716f370..037514f45c7 100644 --- a/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs +++ b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - trait Foo { } -fn foo<'a, 'b:'a>() { //~ ERROR region bounds require `issue_5723_bootstrap` -} +impl<'a> Foo for &'a int { } -pub fn main() { } +fn main() { + let blah; + { + let ss: &int = &1; //~ ERROR borrowed value does not live long enough + blah = box ss as Box; + } +} diff --git a/src/test/compile-fail/regions-close-over-type-parameter-1.rs b/src/test/compile-fail/regions-close-over-type-parameter-1.rs new file mode 100644 index 00000000000..5465f199f40 --- /dev/null +++ b/src/test/compile-fail/regions-close-over-type-parameter-1.rs @@ -0,0 +1,31 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for what happens when a type parameter `A` is closed over into +// an object. This should yield errors unless `A` (and the object) +// both have suitable bounds. + +trait SomeTrait { fn get(&self) -> int; } + +fn make_object1(v: A) -> Box { + box v as Box + //~^ ERROR the parameter type `A` may not live long enough +} + +fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { + box v as Box +} + +fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { + box v as Box + //~^ ERROR the parameter type `A` may not live long enough +} + +fn main() { } diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/regions-close-over-type-parameter-2.rs similarity index 61% rename from src/test/compile-fail/kindck-owned-trait-contains.rs rename to src/test/compile-fail/regions-close-over-type-parameter-2.rs index 50704a1afbf..0ee349aaebf 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-2.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,25 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test for what happens when a type parameter `A` is closed over into +// an object. This should yield errors unless `A` (and the object) +// both have suitable bounds. -trait Repeat { fn get(&self) -> A; } +trait Foo { fn get(&self); } -impl Repeat for A { - fn get(&self) -> A { self.clone() } +impl Foo for A { + fn get(&self) { } } -fn repeater(v: A) -> Box> { - box v as Box> // No +fn repeater3<'a,A:'a>(v: A) -> Box { + box v as Box } fn main() { // Error results because the type of is inferred to be // ~Repeat<&'blk int> where blk is the lifetime of the block below. - let y = { + let _ = { let tmp0 = 3i; let tmp1 = &tmp0; //~ ERROR `tmp0` does not live long enough - repeater(tmp1) + repeater3(tmp1) }; - assert!(3 == *(y.get())); } diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs index 25016c104ad..5da281d93dd 100644 --- a/src/test/compile-fail/regions-early-bound-error.rs +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -15,7 +15,7 @@ trait GetRef<'a, T> { fn get(&self) -> &'a T; } -struct Box<'a, T> { +struct Box<'a, T:'a> { t: &'a T } diff --git a/src/test/compile-fail/regions-enum-not-wf.rs b/src/test/compile-fail/regions-enum-not-wf.rs new file mode 100644 index 00000000000..6395ee62f16 --- /dev/null +++ b/src/test/compile-fail/regions-enum-not-wf.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Various examples of structs whose fields are not well-formed. + +#![no_std] +#![allow(dead_code)] + +enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough + Ref1Variant1(&'a T) +} + +enum Ref2<'a, T> { //~ ERROR the parameter type `T` may not live long enough + Ref2Variant1, + Ref2Variant2(int, &'a T), +} + +enum RefOk<'a, T:'a> { + RefOkVariant1(&'a T) +} + +enum RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough + RefIndirectVariant1(int, RefOk<'a,T>) +} + +enum RefDouble<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data + RefDoubleVariant1(&'a &'b T) +} + +fn main() { } diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs index d2551ec4fed..d752bc97cac 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs @@ -16,5 +16,6 @@ fn with_int(f: |x: &int|) { fn main() { let mut x = None; //~^ ERROR lifetime of variable does not enclose its declaration + //~^^ ERROR type of expression contains references that are not valid during the expression with_int(|y| x = Some(y)); } diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index 980a4aed34f..adef1f901fd 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -8,17 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait deref { +#![no_std] + +#![allow(dead_code)] + +trait Deref { fn get(self) -> int; } -impl<'a> deref for &'a int { +impl<'a> Deref for &'a int { fn get(self) -> int { *self } } -fn with(f: |x: &int| -> R) -> int { +fn with(f: |x: &int| -> R) -> int { f(&3).get() } diff --git a/src/test/compile-fail/regions-free-region-ordering-callee.rs b/src/test/compile-fail/regions-free-region-ordering-callee.rs index 9762e5c4690..26cf3be429b 100644 --- a/src/test/compile-fail/regions-free-region-ordering-callee.rs +++ b/src/test/compile-fail/regions-free-region-ordering-callee.rs @@ -31,6 +31,12 @@ fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint { } fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: |&'a &'b uint|) { + // Do not infer ordering from closure argument types. + let z: Option<&'a &'b uint> = None; + //~^ ERROR reference has a longer lifetime than the data it references +} + +fn ordering5<'a, 'b>(a: &'a uint, b: &'b uint, x: Option<&'a &'b uint>) { let z: Option<&'a &'b uint> = None; } diff --git a/src/test/compile-fail/regions-free-region-ordering-caller.rs b/src/test/compile-fail/regions-free-region-ordering-caller.rs index 2f8caabb7f8..55c0cf3bb26 100644 --- a/src/test/compile-fail/regions-free-region-ordering-caller.rs +++ b/src/test/compile-fail/regions-free-region-ordering-caller.rs @@ -16,18 +16,18 @@ struct Paramd<'a> { x: &'a uint } fn call2<'a, 'b>(a: &'a uint, b: &'b uint) { let z: Option<&'b &'a uint> = None; - //~^ ERROR pointer has a longer lifetime than the data it references + //~^ ERROR reference has a longer lifetime than the data it references } fn call3<'a, 'b>(a: &'a uint, b: &'b uint) { let y: Paramd<'a> = Paramd { x: a }; let z: Option<&'b Paramd<'a>> = None; - //~^ ERROR pointer has a longer lifetime than the data it references + //~^ ERROR reference has a longer lifetime than the data it references } fn call4<'a, 'b>(a: &'a uint, b: &'b uint) { - let z: Option<|&'a &'b uint|> = None; - //~^ ERROR pointer has a longer lifetime than the data it references + let z: Option<&'a &'b uint> = None; + //~^ ERROR reference has a longer lifetime than the data it references } diff --git a/src/test/compile-fail/regions-free-region-ordering-incorrect.rs b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs index 6f6b6761735..9cb61c24922 100644 --- a/src/test/compile-fail/regions-free-region-ordering-incorrect.rs +++ b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs @@ -15,7 +15,7 @@ // // This test began its life as a test for issue #4325. -struct Node<'b, T> { +struct Node<'b, T:'b> { val: T, next: Option<&'b Node<'b, T>> } diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs index cef3b525997..76bbe71cf75 100644 --- a/src/test/compile-fail/regions-freevar.rs +++ b/src/test/compile-fail/regions-freevar.rs @@ -12,7 +12,7 @@ fn wants_static_fn(_x: ||: 'static) {} fn main() { let i = 3i; - wants_static_fn(|| { //~ ERROR cannot infer - println!("i={}", i); + wants_static_fn(|| { + println!("i={}", i); //~ ERROR captured variable `i` does not outlive }) } diff --git a/src/test/compile-fail/regions-infer-bound-from-trait-self.rs b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs new file mode 100644 index 00000000000..25fd20b6ec5 --- /dev/null +++ b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs @@ -0,0 +1,61 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we can derive lifetime bounds on `Self` from trait +// inheritance. + +trait Static : 'static { } + +trait Is<'a> : 'a { } + +struct Inv<'a> { + x: Option<&'a mut &'a int> +} + +fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } + +// In these case, `Self` inherits `'static`. + +trait InheritsFromStatic : 'static { + fn foo1<'a>(self, x: Inv<'a>) { + check_bound(x, self) + } +} +trait InheritsFromStaticIndirectly : Static { + fn foo1<'a>(self, x: Inv<'a>) { + check_bound(x, self) + } +} + + +// In these case, `Self` inherits `'a`. + +trait InheritsFromIs<'a> : 'a { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + } +} + +trait InheritsFromIsIndirectly<'a> : Is<'a> { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + } +} + +// In this case, `Self` inherits nothing. + +trait InheritsFromNothing<'a> { + fn foo(self, x: Inv<'a>) { + check_bound(x, self) + //~^ ERROR parameter type `Self` may not live long enough + } +} + +fn main() { } diff --git a/src/test/compile-fail/regions-infer-bound-from-trait.rs b/src/test/compile-fail/regions-infer-bound-from-trait.rs new file mode 100644 index 00000000000..d1111377f1e --- /dev/null +++ b/src/test/compile-fail/regions-infer-bound-from-trait.rs @@ -0,0 +1,50 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we can derive lifetime bounds on type parameters +// from trait inheritance. + +trait Static : 'static { } + +trait Is<'a> : 'a { } + +struct Inv<'a> { + x: Option<&'a mut &'a int> +} + +fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } + +// In all of these cases, we can derive a bound for A that is longer +// than 'a based on the trait bound of A: + +fn foo1<'a,A:Static>(x: Inv<'a>, a: A) { + check_bound(x, a) +} + +fn foo2<'a,A:Static>(x: Inv<'static>, a: A) { + check_bound(x, a) +} + +fn foo3<'a,A:Is<'a>>(x: Inv<'a>, a: A) { + check_bound(x, a) +} + +// In these cases, there is no trait bound, so we cannot derive any +// bound for A and we get an error: + +fn bar1<'a,A>(x: Inv<'a>, a: A) { + check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +} + +fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { + check_bound(x, a) //~ ERROR parameter type `A` may not live long enough +} + +fn main() { } diff --git a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs index a743ff81b30..0fa4969b54c 100644 --- a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs +++ b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs @@ -11,7 +11,7 @@ // check that the &int here does not cause us to think that `foo` // contains region pointers -struct foo(proc(x: &int)); +struct foo(proc(x: &int):'static); fn take_foo(x: foo<'static>) {} //~ ERROR wrong number of lifetime parameters diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs new file mode 100644 index 00000000000..a52d2f9f9a0 --- /dev/null +++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs @@ -0,0 +1,41 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![no_std] + +fn a<'a, 'b:'a>(x: &mut &'a int, y: &mut &'b int) { + // Note: this is legal because of the `'b:'a` declaration. + *x = *y; +} + +fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) { + // Illegal now because there is no `'b:'a` declaration. + *x = *y; //~ ERROR mismatched types +} + +fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) { + // Here we try to call `foo` but do not know that `'a` and `'b` are + // related as required. + a(x, y); //~ ERROR cannot infer +} + +fn d() { + // 'a and 'b are early bound in the function `a` because they appear + // inconstraints: + let _: fn(&mut &int, &mut &int) = a; //~ ERROR mismatched types +} + +fn e() { + // 'a and 'b are late bound in the function `b` because there are + // no constraints: + let _: fn(&mut &int, &mut &int) = b; +} + +fn main() { } diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs new file mode 100644 index 00000000000..e32ef275256 --- /dev/null +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -0,0 +1,26 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn borrowed_proc<'a>(x: &'a int) -> proc():'a -> int { + // This is legal, because the region bound on `proc` + // states that it captures `x`. + proc() { + *x + } +} + +fn static_proc<'a>(x: &'a int) -> proc():'static -> int { + // This is illegal, because the region bound on `proc` is 'static. + proc() { //~ ERROR captured variable `x` outlives the `proc()` + *x + } +} + +fn main() { } diff --git a/src/test/compile-fail/regions-bound-lists-feature-gate.rs b/src/test/compile-fail/regions-proc-bounds.rs similarity index 73% rename from src/test/compile-fail/regions-bound-lists-feature-gate.rs rename to src/test/compile-fail/regions-proc-bounds.rs index de3b2faef86..db71bc4e15c 100644 --- a/src/test/compile-fail/regions-bound-lists-feature-gate.rs +++ b/src/test/compile-fail/regions-proc-bounds.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +fn is_static() {} -trait Foo { } +fn foo<'a>() { + is_static::(); + //~^ ERROR does not fulfill the required lifetime -fn foo<'a>(x: Box) { //~ ERROR only the 'static lifetime is accepted here -} - -fn bar<'a, T:'a>() { //~ ERROR only the 'static lifetime is accepted here + is_static::(); } fn main() { } diff --git a/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs b/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs index d3e0740a0fe..50ea8b1f2ed 100644 --- a/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs +++ b/src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs @@ -11,7 +11,7 @@ // Issue #8624. Test for reborrowing with 3 levels, not just two. fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut int) -> &'b mut int { - &mut ***p //~ ERROR cannot infer an appropriate lifetime + &mut ***p //~ ERROR lifetime of `p` is too short to guarantee its contents } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index df46b2aaac0..aac81a2af6b 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -18,8 +18,9 @@ fn with(f: <'a>|x: &'a int| -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) - //~^ ERROR lifetime of return value does not outlive the function call - //~^^ ERROR cannot infer + //~^ ERROR cannot infer + //~^^ ERROR not valid during the expression + //~^^^ ERROR not valid at this point } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index 507a48fb741..dd9421ee2ef 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -21,8 +21,9 @@ fn with(f: |x: &int| -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) - //~^ ERROR lifetime of return value does not outlive the function call - //~^^ ERROR cannot infer + //~^ ERROR cannot infer + //~^^ ERROR not valid during the expression + //~^^^ ERROR not valid at this point } fn main() { diff --git a/src/test/compile-fail/regions-struct-not-wf.rs b/src/test/compile-fail/regions-struct-not-wf.rs new file mode 100644 index 00000000000..3de137a9efb --- /dev/null +++ b/src/test/compile-fail/regions-struct-not-wf.rs @@ -0,0 +1,32 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Various examples of structs whose fields are not well-formed. + +#![no_std] +#![allow(dead_code)] + +struct Ref<'a, T> { //~ ERROR the parameter type `T` may not live long enough + field: &'a T +} + +struct RefOk<'a, T:'a> { + field: &'a T +} + +struct RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough + field: RefOk<'a, T> +} + +struct DoubleRef<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data it references + field: &'a &'b T +} + +fn main() { } diff --git a/src/test/compile-fail/regions-trait-variance.rs b/src/test/compile-fail/regions-trait-variance.rs index 53cfd4e0324..3ceb4e3fef6 100644 --- a/src/test/compile-fail/regions-trait-variance.rs +++ b/src/test/compile-fail/regions-trait-variance.rs @@ -31,7 +31,7 @@ impl Drop for B { } struct A<'r> { - p: &'r X + p: &'r X+'r } fn make_a(p:&X) -> A { diff --git a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs index 5cc3f1bdc37..7dcdc9875e3 100644 --- a/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs +++ b/src/test/compile-fail/regions-variance-covariant-use-contravariant.rs @@ -31,7 +31,7 @@ fn use_<'short,'long>(c: Covariant<'long>, // contravariant with respect to its parameter 'a. let _: Covariant<'short> = c; //~ ERROR mismatched types - //~^ ERROR cannot infer an appropriate lifetime + //~^ ERROR cannot infer an appropriate lifetime } fn main() {} diff --git a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs index 0790c3f956a..d09e6babe09 100644 --- a/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs +++ b/src/test/compile-fail/regions-variance-invariant-use-contravariant.rs @@ -15,7 +15,7 @@ // variance inference works in the first place. struct Invariant<'a> { - f: &'static mut &'a int + f: &'a mut &'a int } fn use_<'short,'long>(c: Invariant<'long>, diff --git a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs index 9cdd05f8ebe..861668ad50d 100644 --- a/src/test/compile-fail/regions-variance-invariant-use-covariant.rs +++ b/src/test/compile-fail/regions-variance-invariant-use-covariant.rs @@ -15,7 +15,7 @@ // variance inference works in the first place. struct Invariant<'a> { - f: &'static mut &'a int + f: &'a mut &'a int } fn use_<'b>(c: Invariant<'b>) { diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs index 3bf547e3aff..bf7c3b261fd 100644 --- a/src/test/compile-fail/selftype-traittype.rs +++ b/src/test/compile-fail/selftype-traittype.rs @@ -13,7 +13,7 @@ trait add { fn plus(&self, x: Self) -> Self; } -fn do_add(x: Box, y: Box) -> Box { +fn do_add(x: Box, y: Box) -> Box { x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object } diff --git a/src/test/compile-fail/static-region-bound.rs b/src/test/compile-fail/static-region-bound.rs index c36610fc79e..2cb1f462e1d 100644 --- a/src/test/compile-fail/static-region-bound.rs +++ b/src/test/compile-fail/static-region-bound.rs @@ -16,6 +16,6 @@ fn f(_: T) {} fn main() { let x = box(GC) 3i; f(x); - let x = &3i; - f(x); //~ ERROR instantiating a type parameter with an incompatible type + let x = &3i; //~ ERROR borrowed value does not live long enough + f(x); } diff --git a/src/test/compile-fail/trailing-plus-in-bounds.rs b/src/test/compile-fail/trailing-plus-in-bounds.rs index e8f9ed4d2cf..b189acb685a 100644 --- a/src/test/compile-fail/trailing-plus-in-bounds.rs +++ b/src/test/compile-fail/trailing-plus-in-bounds.rs @@ -11,7 +11,7 @@ use std::fmt::Show; fn main() { - let x: Box = box 3 as Box; + let x: Box = box 3i as Box; //~^ ERROR at least one type parameter bound must be specified //~^^ ERROR at least one type parameter bound must be specified } diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs index c3d608b48f3..7ed8db4fcd2 100644 --- a/src/test/compile-fail/trait-bounds-sugar.rs +++ b/src/test/compile-fail/trait-bounds-sugar.rs @@ -16,15 +16,16 @@ trait Foo {} fn a(_x: Box) { } -fn b(_x: &'static Foo) { // should be same as &'static Foo+'static +fn b(_x: &'static Foo+'static) { } fn c(x: Box) { - a(x); //~ ERROR expected bounds `Send` + a(x); //~ ERROR mismatched types } fn d(x: &'static Foo+Sync) { - b(x); //~ ERROR expected bounds `'static` + b(x); //~ ERROR cannot infer + //~^ ERROR mismatched types } fn main() {} diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs index 0f9cfab7b8a..9694c1d9f98 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs @@ -11,7 +11,7 @@ // This test checks that the `_` type placeholder does not react // badly if put as a lifetime parameter. -struct Foo<'a, T> { +struct Foo<'a, T:'a> { r: &'a T } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs index e9671b353b9..365b786cc1a 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs @@ -11,7 +11,7 @@ // This test checks that the `_` type placeholder does not react // badly if put as a lifetime parameter. -struct Foo<'a, T> { +struct Foo<'a, T:'a> { r: &'a T } diff --git a/src/test/compile-fail/unconstrained-ref.rs b/src/test/compile-fail/unconstrained-ref.rs index a4125f94cd2..87647cdb546 100644 --- a/src/test/compile-fail/unconstrained-ref.rs +++ b/src/test/compile-fail/unconstrained-ref.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct S<'a, T> { +struct S<'a, T:'a> { o: &'a Option } diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs index e377c9d5f41..a66c1d85009 100644 --- a/src/test/compile-fail/unsized4.rs +++ b/src/test/compile-fail/unsized4.rs @@ -12,7 +12,7 @@ trait T {} fn f() { -//~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type +//~^ERROR incompatible bounds on type parameter `Y`, bound `T` does not allow unsized type } pub fn main() { diff --git a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs index 043f3a233a6..3f2f43b0c9b 100644 --- a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs +++ b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs @@ -23,10 +23,10 @@ impl fmt::Show for Number { } struct List { - list: Vec> } + list: Vec> } impl List { - fn push(&mut self, n: Box) { + fn push(&mut self, n: Box) { self.list.push(n); } } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index da4f9846187..fa38482b21c 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b> { //~ ERROR regions=[[-, o];[];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] x: &'a mut &'b int, } @@ -64,7 +64,7 @@ struct Test7<'a> { //~ ERROR regions=[[*];[];[]] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index 0d20f652496..c049fbc0fed 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -13,29 +13,29 @@ // Try enums too. #[rustc_variance] -enum Base<'a, 'b, 'c, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), } #[rustc_variance] -struct Derived1<'w, 'x, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b, 'c> { //~ ERROR regions=[[o, o, *];[];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]] f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c> { //~ ERROR regions=[[+, -, o];[];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/pretty/closure-reform-pretty.rs b/src/test/pretty/closure-reform-pretty.rs index 92fa8124d68..eb20a09477d 100644 --- a/src/test/pretty/closure-reform-pretty.rs +++ b/src/test/pretty/closure-reform-pretty.rs @@ -17,7 +17,7 @@ fn call_it(f: proc(String) -> String) { } fn call_this(f: |&str|: Send) { } -fn call_that(f: <'a>|&'a int, &'a int|: -> int) { } +fn call_that(f: <'a>|&'a int, &'a int| -> int) { } fn call_extern(f: fn() -> int) { } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index ddf79d1d750..86e394e5408 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -48,8 +48,8 @@ pub fn bar() { as core::fmt::rt::Piece<'static>)] as [core::fmt::rt::Piece<'static>, .. 1]); let __args_vec = - (&([] as [core::fmt::Argument<'static>, .. 0]) as - &'static [core::fmt::Argument<'static>, .. 0]); + (&([] as [core::fmt::Argument<'_>, .. 0]) as + &[core::fmt::Argument<'_>, .. 0]); let __args = (unsafe { ((::std::fmt::Arguments::new as @@ -58,9 +58,9 @@ pub fn bar() { [core::fmt::rt::Piece<'static>, .. 1]), (__args_vec as - &'static [core::fmt::Argument<'static>, .. 0])) - as core::fmt::Arguments<'static>) - } as core::fmt::Arguments<'static>); + &[core::fmt::Argument<'_>, .. 0])) + as core::fmt::Arguments<'_>) + } as core::fmt::Arguments<'_>); @@ -72,9 +72,9 @@ pub fn bar() { ((::std::fmt::format as fn(&core::fmt::Arguments<'_>) -> collections::string::String)((&(__args as - core::fmt::Arguments<'static>) + core::fmt::Arguments<'_>) as - &core::fmt::Arguments<'static>)) + &core::fmt::Arguments<'_>)) as collections::string::String) } } as collections::string::String); diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs index 7c05e6d6065..f575fb32924 100644 --- a/src/test/pretty/path-type-bounds.rs +++ b/src/test/pretty/path-type-bounds.rs @@ -14,7 +14,7 @@ trait Tr { } impl Tr for int { } -fn foo(x: Box) -> Box { x } +fn foo<'a>(x: Box) -> Box { x } fn main() { let x: Box; diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot index a5239a6cc66..c5455ab90dc 100644 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot @@ -2,8 +2,10 @@ digraph block { N0[label="entry"]; N1[label="exit"]; N2[label="expr 1i"]; - N3[label="block { 1i; }"]; + N3[label="stmt 1i;"]; + N4[label="block { 1i; }"]; N0 -> N2; N2 -> N3; - N3 -> N1; + N3 -> N4; + N4 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot index ada3f091808..230dcbaeb98 100644 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot @@ -2,8 +2,10 @@ digraph block { N0[label="entry"]; N1[label="exit"]; N2[label="local _x"]; - N3[label="block { let _x: int; }"]; + N3[label="stmt let _x: int;"]; + N4[label="block { let _x: int; }"]; N0 -> N2; N2 -> N3; - N3 -> N1; + N3 -> N4; + N4 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot index 43462862f6e..e60d349ad14 100644 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot @@ -4,10 +4,12 @@ digraph block { N2[label="expr 3i"]; N3[label="expr 33i"]; N4[label="expr 3i + 33i"]; - N5[label="block { 3i + 33i; }"]; + N5[label="stmt 3i + 33i;"]; + N6[label="block { 3i + 33i; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; - N5 -> N1; + N5 -> N6; + N6 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot index 26c858a0828..82cdcb39fbf 100644 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot @@ -3,9 +3,11 @@ digraph block { N1[label="exit"]; N2[label="expr 4i"]; N3[label="local _x"]; - N4[label="block { let _x = 4i; }"]; + N4[label="stmt let _x = 4i;"]; + N5[label="block { let _x = 4i; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot index 850d04f430f..8a27d536ffc 100644 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot @@ -7,7 +7,8 @@ digraph block { N5[label="local _x"]; N6[label="local _y"]; N7[label="pat (_x, _y)"]; - N8[label="block { let (_x, _y) = (5i, 55i); }"]; + N8[label="stmt let (_x, _y) = (5i, 55i);"]; + N9[label="block { let (_x, _y) = (5i, 55i); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -15,5 +16,6 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N1; + N8 -> N9; + N9 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot index b431476f84a..54e9d89d3fb 100644 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot @@ -5,11 +5,13 @@ digraph block { N3[label="expr S6{val: 6,}"]; N4[label="local _x"]; N5[label="pat S6 { val: _x }"]; - N6[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; + N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; + N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N1; + N6 -> N7; + N7 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index 2b7088fbc33..4c6383324e5 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -15,7 +15,8 @@ digraph block { N13[label="expr x"]; N14[label="expr y"]; N15[label="expr x + y"]; - N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"]; + N16[label="stmt match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, };"]; + N17[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -31,5 +32,6 @@ digraph block { N14 -> N15; N15 -> N7; N7 -> N16; - N16 -> N1; + N16 -> N17; + N17 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot index f43beb025e3..27a240ed182 100644 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot @@ -3,16 +3,19 @@ digraph block { N1[label="exit"]; N2[label="expr 8i"]; N3[label="local x"]; - N4[label="local _y"]; - N5[label="expr x"]; - N6[label="expr 88i"]; - N7[label="expr x > 88i"]; - N8[label="expr 888i"]; - N9[label="expr _y"]; - N10[label="expr _y = 888i"]; - N11[label="block { _y = 888i; }"]; - N12[label="expr if x > 88i { _y = 888i; }"]; - N13[label="block { let x = 8i; let _y; if x > 88i { _y = 888i; } }"]; + N4[label="stmt let x = 8i;"]; + N5[label="local _y"]; + N6[label="stmt let _y;"]; + N7[label="expr x"]; + N8[label="expr 88i"]; + N9[label="expr x > 88i"]; + N10[label="expr 888i"]; + N11[label="expr _y"]; + N12[label="expr _y = 888i"]; + N13[label="stmt _y = 888i;"]; + N14[label="block { _y = 888i; }"]; + N15[label="expr if x > 88i { _y = 888i; }"]; + N16[label="block { let x = 8i; let _y; if x > 88i { _y = 888i; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,8 +26,11 @@ digraph block { N8 -> N9; N9 -> N10; N10 -> N11; - N7 -> N12; N11 -> N12; N12 -> N13; - N13 -> N1; + N13 -> N14; + N9 -> N15; + N14 -> N15; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot index a3576b9c36b..d2c58c6d59a 100644 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot @@ -3,23 +3,27 @@ digraph block { N1[label="exit"]; N2[label="expr 91i"]; N3[label="local x"]; - N4[label="local _y"]; - N5[label="expr x"]; - N6[label="expr 92i"]; - N7[label="expr x > 92i"]; - N8[label="expr 93i"]; - N9[label="expr _y"]; - N10[label="expr _y = 93i"]; - N11[label="block { _y = 93i; }"]; - N12[label="expr 94i"]; - N13[label="expr 95i"]; - N14[label="expr 94i + 95i"]; - N15[label="expr _y"]; - N16[label="expr _y = 94i + 95i"]; - N17[label="block { _y = 94i + 95i; }"]; - N18[label="expr { _y = 94i + 95i; }"]; - N19[label="expr if x > 92i { _y = 93i; } else { _y = 94i + 95i; }"]; - N20[label="block { let x = 91i; let _y; if x > 92i { _y = 93i; } else { _y = 94i + 95i; } }"]; + N4[label="stmt let x = 91i;"]; + N5[label="local _y"]; + N6[label="stmt let _y;"]; + N7[label="expr x"]; + N8[label="expr 92i"]; + N9[label="expr x > 92i"]; + N10[label="expr 93i"]; + N11[label="expr _y"]; + N12[label="expr _y = 93i"]; + N13[label="stmt _y = 93i;"]; + N14[label="block { _y = 93i; }"]; + N15[label="expr 94i"]; + N16[label="expr 95i"]; + N17[label="expr 94i + 95i"]; + N18[label="expr _y"]; + N19[label="expr _y = 94i + 95i"]; + N20[label="stmt _y = 94i + 95i;"]; + N21[label="block { _y = 94i + 95i; }"]; + N22[label="expr { _y = 94i + 95i; }"]; + N23[label="expr if x > 92i { _y = 93i; } else { _y = 94i + 95i; }"]; + N24[label="block { let x = 91i; let _y; if x > 92i { _y = 93i; } else { _y = 94i + 95i; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,15 +34,19 @@ digraph block { N8 -> N9; N9 -> N10; N10 -> N11; - N7 -> N12; + N11 -> N12; N12 -> N13; N13 -> N14; - N14 -> N15; + N9 -> N15; N15 -> N16; N16 -> N17; N17 -> N18; - N11 -> N19; N18 -> N19; N19 -> N20; - N20 -> N1; + N20 -> N21; + N21 -> N22; + N14 -> N23; + N22 -> N23; + N23 -> N24; + N24 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot index 69b5bd6f58c..421a79fd136 100644 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot @@ -3,16 +3,18 @@ digraph block { N1[label="exit"]; N2[label="expr 10i"]; N3[label="local mut x"]; - N4[label="(dummy_node)"]; - N5[label="expr x"]; - N6[label="expr 0i"]; - N7[label="expr x > 0i"]; - N8[label="expr while x > 0i { x -= 1i; }"]; - N9[label="expr 1i"]; - N10[label="expr x"]; - N11[label="expr x -= 1i"]; - N12[label="block { x -= 1i; }"]; - N13[label="block { let mut x = 10i; while x > 0i { x -= 1i; } }"]; + N4[label="stmt let mut x = 10i;"]; + N5[label="(dummy_node)"]; + N6[label="expr x"]; + N7[label="expr 0i"]; + N8[label="expr x > 0i"]; + N9[label="expr while x > 0i { x -= 1i; }"]; + N10[label="expr 1i"]; + N11[label="expr x"]; + N12[label="expr x -= 1i"]; + N13[label="stmt x -= 1i;"]; + N14[label="block { x -= 1i; }"]; + N15[label="block { let mut x = 10i; while x > 0i { x -= 1i; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -20,11 +22,13 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N7 -> N9; - N9 -> N10; + N8 -> N9; + N8 -> N10; N10 -> N11; N11 -> N12; - N12 -> N4; - N8 -> N13; - N13 -> N1; + N12 -> N13; + N13 -> N14; + N14 -> N5; + N9 -> N15; + N15 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot index 44024cf76f3..b928058fed9 100644 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot @@ -3,23 +3,31 @@ digraph block { N1[label="exit"]; N2[label="expr 11i"]; N3[label="local mut _x"]; - N4[label="(dummy_node)"]; - N5[label="expr loop { _x -= 1i; }"]; - N6[label="expr 1i"]; - N7[label="expr _x"]; - N8[label="expr _x -= 1i"]; - N9[label="block { _x -= 1i; }"]; - N10[label="expr \"unreachable\""]; - N11[label="block { let mut _x = 11i; loop { _x -= 1i; } \"unreachable\"; }"]; + N4[label="stmt let mut _x = 11i;"]; + N5[label="(dummy_node)"]; + N6[label="expr loop { _x -= 1i; }"]; + N7[label="expr 1i"]; + N8[label="expr _x"]; + N9[label="expr _x -= 1i"]; + N10[label="stmt _x -= 1i;"]; + N11[label="block { _x -= 1i; }"]; + N12[label="stmt loop { _x -= 1i; }"]; + N13[label="expr \"unreachable\""]; + N14[label="stmt \"unreachable\";"]; + N15[label="block { let mut _x = 11i; loop { _x -= 1i; } \"unreachable\"; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N6; - N6 -> N7; + N4 -> N5; + N5 -> N7; N7 -> N8; N8 -> N9; - N9 -> N4; - N5 -> N10; + N9 -> N10; N10 -> N11; - N11 -> N1; + N11 -> N5; + N6 -> N12; + N12 -> N13; + N13 -> N14; + N14 -> N15; + N15 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot index ad257c19741..d89a37308de 100644 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -3,38 +3,46 @@ digraph block { N1[label="exit"]; N2[label="expr 12i"]; N3[label="local mut x"]; - N4[label="(dummy_node)"]; - N5[label="expr loop { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; - N6[label="expr 1i"]; - N7[label="expr x"]; - N8[label="expr x -= 1i"]; - N9[label="expr x"]; - N10[label="expr 2i"]; - N11[label="expr x == 2i"]; - N12[label="expr break"]; - N13[label="(dummy_node)"]; - N14[label="expr \"unreachable\""]; - N15[label="block { break ; \"unreachable\"; }"]; - N16[label="expr if x == 2i { break ; \"unreachable\"; }"]; - N17[label="block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; - N18[label="block { let mut x = 12i; loop { x -= 1i; if x == 2i { break ; \"unreachable\"; } } }"]; + N4[label="stmt let mut x = 12i;"]; + N5[label="(dummy_node)"]; + N6[label="expr loop { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; + N7[label="expr 1i"]; + N8[label="expr x"]; + N9[label="expr x -= 1i"]; + N10[label="stmt x -= 1i;"]; + N11[label="expr x"]; + N12[label="expr 2i"]; + N13[label="expr x == 2i"]; + N14[label="expr break"]; + N15[label="(dummy_node)"]; + N16[label="stmt break ;"]; + N17[label="expr \"unreachable\""]; + N18[label="stmt \"unreachable\";"]; + N19[label="block { break ; \"unreachable\"; }"]; + N20[label="expr if x == 2i { break ; \"unreachable\"; }"]; + N21[label="block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; + N22[label="block { let mut x = 12i; loop { x -= 1i; if x == 2i { break ; \"unreachable\"; } } }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N6; - N6 -> N7; + N4 -> N5; + N5 -> N7; N7 -> N8; N8 -> N9; N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N5[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; + N12 -> N13; N13 -> N14; - N14 -> N15; - N11 -> N16; + N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; N15 -> N16; N16 -> N17; - N17 -> N4; - N5 -> N18; - N18 -> N1; + N17 -> N18; + N18 -> N19; + N13 -> N20; + N19 -> N20; + N20 -> N21; + N21 -> N5; + N6 -> N22; + N22 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index 5d1d1253b22..aa43ef51534 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -5,44 +5,48 @@ digraph block { N3[label="expr 13"]; N4[label="expr E13b(13)"]; N5[label="local x"]; - N6[label="local _y"]; - N7[label="expr x"]; - N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1, }"]; - N9[label="(dummy_node)"]; - N10[label="local E13a"]; - N11[label="expr 1"]; - N12[label="expr _y"]; - N13[label="expr _y = 1"]; - N14[label="(dummy_node)"]; - N15[label="local v"]; - N16[label="pat E13b(v)"]; - N17[label="expr v"]; - N18[label="expr 1"]; - N19[label="expr v + 1"]; - N20[label="expr _y"]; - N21[label="expr _y = v + 1"]; - N22[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"]; + N6[label="stmt let x = E13b(13);"]; + N7[label="local _y"]; + N8[label="stmt let _y;"]; + N9[label="expr x"]; + N10[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1, }"]; + N11[label="(dummy_node)"]; + N12[label="local E13a"]; + N13[label="expr 1"]; + N14[label="expr _y"]; + N15[label="expr _y = 1"]; + N16[label="(dummy_node)"]; + N17[label="local v"]; + N18[label="pat E13b(v)"]; + N19[label="expr v"]; + N20[label="expr 1"]; + N21[label="expr v + 1"]; + N22[label="expr _y"]; + N23[label="expr _y = v + 1"]; + N24[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N9; - N9 -> N10; - N10 -> N11; + N7 -> N8; + N8 -> N9; + N9 -> N11; N11 -> N12; N12 -> N13; - N13 -> N8; - N9 -> N14; + N13 -> N14; N14 -> N15; - N15 -> N16; + N15 -> N10; + N11 -> N16; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N8; - N8 -> N22; - N22 -> N1; + N21 -> N22; + N22 -> N23; + N23 -> N10; + N10 -> N24; + N24 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot index f8e4bd12bb0..bdb2c133bad 100644 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot @@ -3,26 +3,32 @@ digraph block { N1[label="exit"]; N2[label="expr 14i"]; N3[label="local x"]; - N4[label="expr x"]; - N5[label="expr 1i"]; - N6[label="expr x > 1i"]; - N7[label="expr return"]; - N8[label="(dummy_node)"]; - N9[label="expr \"unreachable\""]; - N10[label="block { return; \"unreachable\"; }"]; - N11[label="expr if x > 1i { return; \"unreachable\"; }"]; - N12[label="block { let x = 14i; if x > 1i { return; \"unreachable\"; } }"]; + N4[label="stmt let x = 14i;"]; + N5[label="expr x"]; + N6[label="expr 1i"]; + N7[label="expr x > 1i"]; + N8[label="expr return"]; + N9[label="(dummy_node)"]; + N10[label="stmt return;"]; + N11[label="expr \"unreachable\""]; + N12[label="stmt \"unreachable\";"]; + N13[label="block { return; \"unreachable\"; }"]; + N14[label="expr if x > 1i { return; \"unreachable\"; }"]; + N15[label="block { let x = 14i; if x > 1i { return; \"unreachable\"; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N1; - N8 -> N9; + N7 -> N8; + N8 -> N1; N9 -> N10; - N6 -> N11; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N7 -> N14; + N13 -> N14; + N14 -> N15; + N15 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 77ee0df5512..4bd9fc9ec1a 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -3,77 +3,101 @@ digraph block { N1[label="exit"]; N2[label="expr 15i"]; N3[label="local mut x"]; - N4[label="expr 151i"]; - N5[label="local mut y"]; - N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; + N4[label="stmt let mut x = 15i;"]; + N5[label="expr 151i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 151i;"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; - N10[label="expr x"]; - N11[label="expr 1i"]; - N12[label="expr x == 1i"]; - N13[label="expr break \'outer"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { break \'outer ; \"unreachable\"; }"]; - N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; - N18[label="expr y"]; - N19[label="expr 2i"]; - N20[label="expr y >= 2i"]; - N21[label="expr break"]; - N22[label="(dummy_node)"]; - N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\"; }"]; - N25[label="expr if y >= 2i { break ; \"unreachable\"; }"]; - N26[label="expr 3i"]; - N27[label="expr y"]; - N28[label="expr y -= 3i"]; - N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; - N30[label="expr 4i"]; - N31[label="expr y"]; - N32[label="expr y -= 4i"]; - N33[label="expr 5i"]; - N34[label="expr x"]; - N35[label="expr x -= 5i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; - N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; + N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; + N10[label="(dummy_node)"]; + N11[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; + N12[label="expr x"]; + N13[label="expr 1i"]; + N14[label="expr x == 1i"]; + N15[label="expr break \'outer"]; + N16[label="(dummy_node)"]; + N17[label="stmt break \'outer ;"]; + N18[label="expr \"unreachable\""]; + N19[label="stmt \"unreachable\";"]; + N20[label="block { break \'outer ; \"unreachable\"; }"]; + N21[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; + N22[label="stmt if x == 1i { break \'outer ; \"unreachable\"; }"]; + N23[label="expr y"]; + N24[label="expr 2i"]; + N25[label="expr y >= 2i"]; + N26[label="expr break"]; + N27[label="(dummy_node)"]; + N28[label="stmt break ;"]; + N29[label="expr \"unreachable\""]; + N30[label="stmt \"unreachable\";"]; + N31[label="block { break ; \"unreachable\"; }"]; + N32[label="expr if y >= 2i { break ; \"unreachable\"; }"]; + N33[label="stmt if y >= 2i { break ; \"unreachable\"; }"]; + N34[label="expr 3i"]; + N35[label="expr y"]; + N36[label="expr y -= 3i"]; + N37[label="stmt y -= 3i;"]; + N38[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; + N39[label="stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; + N40[label="expr 4i"]; + N41[label="expr y"]; + N42[label="expr y -= 4i"]; + N43[label="stmt y -= 4i;"]; + N44[label="expr 5i"]; + N45[label="expr x"]; + N46[label="expr x -= 5i"]; + N47[label="stmt x -= 5i;"]; + N48[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N49[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N8; + N6 -> N7; + N7 -> N8; N8 -> N10; - N10 -> N11; - N11 -> N12; + N10 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N13 -> N14; N14 -> N15; - N15 -> N16; - N12 -> N17; + N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; + N14 -> N21; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; + N21 -> N22; N22 -> N23; N23 -> N24; - N20 -> N25; N24 -> N25; N25 -> N26; - N26 -> N27; + N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N27 -> N28; N28 -> N29; - N29 -> N8; - N9 -> N30; + N29 -> N30; N30 -> N31; + N25 -> N32; N31 -> N32; N32 -> N33; N33 -> N34; N34 -> N35; N35 -> N36; - N36 -> N6; - N7 -> N37; - N37 -> N1; + N36 -> N37; + N37 -> N38; + N38 -> N10; + N11 -> N39; + N39 -> N40; + N40 -> N41; + N41 -> N42; + N42 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N47; + N47 -> N48; + N48 -> N8; + N9 -> N49; + N49 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index b5a867e6029..16b871bd844 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -3,79 +3,107 @@ digraph block { N1[label="exit"]; N2[label="expr 16i"]; N3[label="local mut x"]; - N4[label="expr 16i"]; - N5[label="local mut y"]; - N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N4[label="stmt let mut x = 16i;"]; + N5[label="expr 16i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 16i;"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; - N10[label="expr x"]; - N11[label="expr 1i"]; - N12[label="expr x == 1i"]; - N13[label="expr continue \'outer"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { continue \'outer ; \"unreachable\"; }"]; - N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; - N18[label="expr y"]; - N19[label="expr 1i"]; - N20[label="expr y >= 1i"]; - N21[label="expr break"]; - N22[label="(dummy_node)"]; - N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\"; }"]; - N25[label="expr if y >= 1i { break ; \"unreachable\"; }"]; - N26[label="expr 1i"]; - N27[label="expr y"]; - N28[label="expr y -= 1i"]; - N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; - N30[label="expr 1i"]; - N31[label="expr y"]; - N32[label="expr y -= 1i"]; - N33[label="expr 1i"]; - N34[label="expr x"]; - N35[label="expr x -= 1i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; - N37[label="expr \"unreachable\""]; - N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; + N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N10[label="(dummy_node)"]; + N11[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; + N12[label="expr x"]; + N13[label="expr 1i"]; + N14[label="expr x == 1i"]; + N15[label="expr continue \'outer"]; + N16[label="(dummy_node)"]; + N17[label="stmt continue \'outer ;"]; + N18[label="expr \"unreachable\""]; + N19[label="stmt \"unreachable\";"]; + N20[label="block { continue \'outer ; \"unreachable\"; }"]; + N21[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; + N22[label="stmt if x == 1i { continue \'outer ; \"unreachable\"; }"]; + N23[label="expr y"]; + N24[label="expr 1i"]; + N25[label="expr y >= 1i"]; + N26[label="expr break"]; + N27[label="(dummy_node)"]; + N28[label="stmt break ;"]; + N29[label="expr \"unreachable\""]; + N30[label="stmt \"unreachable\";"]; + N31[label="block { break ; \"unreachable\"; }"]; + N32[label="expr if y >= 1i { break ; \"unreachable\"; }"]; + N33[label="stmt if y >= 1i { break ; \"unreachable\"; }"]; + N34[label="expr 1i"]; + N35[label="expr y"]; + N36[label="expr y -= 1i"]; + N37[label="stmt y -= 1i;"]; + N38[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; + N39[label="stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; + N40[label="expr 1i"]; + N41[label="expr y"]; + N42[label="expr y -= 1i"]; + N43[label="stmt y -= 1i;"]; + N44[label="expr 1i"]; + N45[label="expr x"]; + N46[label="expr x -= 1i"]; + N47[label="stmt x -= 1i;"]; + N48[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N49[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N50[label="expr \"unreachable\""]; + N51[label="stmt \"unreachable\";"]; + N52[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N8; + N6 -> N7; + N7 -> N8; N8 -> N10; - N10 -> N11; - N11 -> N12; + N10 -> N12; N12 -> N13; - N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N13 -> N14; N14 -> N15; - N15 -> N16; - N12 -> N17; + N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; + N14 -> N21; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; + N21 -> N22; N22 -> N23; N23 -> N24; - N20 -> N25; N24 -> N25; N25 -> N26; - N26 -> N27; + N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N27 -> N28; N28 -> N29; - N29 -> N8; - N9 -> N30; + N29 -> N30; N30 -> N31; + N25 -> N32; N31 -> N32; N32 -> N33; N33 -> N34; N34 -> N35; N35 -> N36; - N36 -> N6; - N7 -> N37; + N36 -> N37; N37 -> N38; - N38 -> N1; + N38 -> N10; + N11 -> N39; + N39 -> N40; + N40 -> N41; + N41 -> N42; + N42 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N47; + N47 -> N48; + N48 -> N8; + N9 -> N49; + N49 -> N50; + N50 -> N51; + N51 -> N52; + N52 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot index d3e098a71f2..c78224c00df 100644 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot @@ -6,12 +6,14 @@ digraph block { N4[label="expr 17i"]; N5[label="expr [1i, 7i, 17i]"]; N6[label="local _v"]; - N7[label="block { let _v = [1i, 7i, 17i]; }"]; + N7[label="stmt let _v = [1i, 7i, 17i];"]; + N8[label="block { let _v = [1i, 7i, 17i]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N1; + N7 -> N8; + N8 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot index 6345b4effaf..c4a39a519ed 100644 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot @@ -1,17 +1,21 @@ digraph block { N0[label="entry"]; N1[label="exit"]; - N2[label="expr inner"]; + N2[label="stmt fn inner(x: int) -> int { x + x }"]; N3[label="expr inner"]; - N4[label="expr 18"]; - N5[label="expr inner(18)"]; - N6[label="expr inner(inner(18))"]; - N7[label="block {\l fn inner(x: int) -> int { x + x }\l inner(inner(18));\l}\l"]; + N4[label="expr inner"]; + N5[label="expr 18"]; + N6[label="expr inner(18)"]; + N7[label="expr inner(inner(18))"]; + N8[label="stmt inner(inner(18));"]; + N9[label="block {\l fn inner(x: int) -> int { x + x }\l inner(inner(18));\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N1; + N7 -> N8; + N8 -> N9; + N9 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot index 5fad18536e5..8d21ef80917 100644 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot @@ -1,13 +1,17 @@ digraph block { N0[label="entry"]; N1[label="exit"]; - N2[label="expr 19"]; - N3[label="expr S19{x: 19,}"]; - N4[label="local s"]; - N5[label="expr s"]; - N6[label="expr s.inner()"]; - N7[label="expr s.inner().inner()"]; - N8[label="block {\l struct S19 {\l x: int,\l }\l impl S19 {\l fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; + N2[label="stmt struct S19 {\l x: int,\l}\l"]; + N3[label="stmt impl S19 {\l fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l}\l"]; + N4[label="expr 19"]; + N5[label="expr S19{x: 19,}"]; + N6[label="local s"]; + N7[label="stmt let s = S19{x: 19,};"]; + N8[label="expr s"]; + N9[label="expr s.inner()"]; + N10[label="expr s.inner().inner()"]; + N11[label="stmt s.inner().inner();"]; + N12[label="block {\l struct S19 {\l x: int,\l }\l impl S19 {\l fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -15,5 +19,9 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N1; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot index 716ec469fb0..a625a1a0026 100644 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot @@ -6,10 +6,12 @@ digraph block { N4[label="expr 20u"]; N5[label="expr [2u, 0u, 20u]"]; N6[label="local v"]; - N7[label="expr v"]; - N8[label="expr 20u"]; - N9[label="expr v[20u]"]; - N10[label="block { let v = [2u, 0u, 20u]; v[20u]; }"]; + N7[label="stmt let v = [2u, 0u, 20u];"]; + N8[label="expr v"]; + N9[label="expr 20u"]; + N10[label="expr v[20u]"]; + N11[label="stmt v[20u];"]; + N12[label="block { let v = [2u, 0u, 20u]; v[20u]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -19,5 +21,7 @@ digraph block { N7 -> N8; N8 -> N9; N9 -> N10; - N10 -> N1; + N10 -> N11; + N11 -> N12; + N12 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot index 2bbc3e7e5c8..ad2ef60ce29 100644 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -3,73 +3,97 @@ digraph block { N1[label="exit"]; N2[label="expr 15i"]; N3[label="local mut x"]; - N4[label="expr 151i"]; - N5[label="local mut y"]; - N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l"]; + N4[label="stmt let mut x = 15i;"]; + N5[label="expr 151i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 151i;"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l"]; - N10[label="expr x"]; - N11[label="expr 1i"]; - N12[label="expr x == 1i"]; - N13[label="expr break \'outer"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { break \'outer ; \"unreachable\"; }"]; - N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; - N18[label="expr y"]; - N19[label="expr 2i"]; - N20[label="expr y >= 2i"]; - N21[label="expr return"]; - N22[label="(dummy_node)"]; - N23[label="expr \"unreachable\""]; - N24[label="block { return; \"unreachable\"; }"]; - N25[label="expr if y >= 2i { return; \"unreachable\"; }"]; - N26[label="expr 3i"]; - N27[label="expr y"]; - N28[label="expr y -= 3i"]; - N29[label="expr 5i"]; - N30[label="expr x"]; - N31[label="expr x -= 5i"]; - N32[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l"]; - N33[label="expr \"unreachable\""]; - N34[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; - N35[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l}\l"]; + N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l"]; + N10[label="(dummy_node)"]; + N11[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l"]; + N12[label="expr x"]; + N13[label="expr 1i"]; + N14[label="expr x == 1i"]; + N15[label="expr break \'outer"]; + N16[label="(dummy_node)"]; + N17[label="stmt break \'outer ;"]; + N18[label="expr \"unreachable\""]; + N19[label="stmt \"unreachable\";"]; + N20[label="block { break \'outer ; \"unreachable\"; }"]; + N21[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; + N22[label="stmt if x == 1i { break \'outer ; \"unreachable\"; }"]; + N23[label="expr y"]; + N24[label="expr 2i"]; + N25[label="expr y >= 2i"]; + N26[label="expr return"]; + N27[label="(dummy_node)"]; + N28[label="stmt return;"]; + N29[label="expr \"unreachable\""]; + N30[label="stmt \"unreachable\";"]; + N31[label="block { return; \"unreachable\"; }"]; + N32[label="expr if y >= 2i { return; \"unreachable\"; }"]; + N33[label="stmt if y >= 2i { return; \"unreachable\"; }"]; + N34[label="expr 3i"]; + N35[label="expr y"]; + N36[label="expr y -= 3i"]; + N37[label="stmt y -= 3i;"]; + N38[label="expr 5i"]; + N39[label="expr x"]; + N40[label="expr x -= 5i"]; + N41[label="stmt x -= 5i;"]; + N42[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l"]; + N43[label="stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l"]; + N44[label="expr \"unreachable\""]; + N45[label="stmt \"unreachable\";"]; + N46[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; + N47[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N8; + N6 -> N7; + N7 -> N8; N8 -> N10; - N10 -> N11; - N11 -> N12; + N10 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; + N13 -> N14; N14 -> N15; - N15 -> N16; - N12 -> N17; + N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; + N14 -> N21; N20 -> N21; - N21 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l"]; + N21 -> N22; N22 -> N23; N23 -> N24; - N20 -> N25; N24 -> N25; N25 -> N26; - N26 -> N27; + N26 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l }\l"]; N27 -> N28; N28 -> N29; N29 -> N30; N30 -> N31; + N25 -> N32; N31 -> N32; - N32 -> N8; - N9 -> N33; + N32 -> N33; N33 -> N34; - N34 -> N6; - N7 -> N35; - N35 -> N1; + N34 -> N35; + N35 -> N36; + N36 -> N37; + N37 -> N38; + N38 -> N39; + N39 -> N40; + N40 -> N41; + N41 -> N42; + N42 -> N10; + N11 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N8; + N9 -> N47; + N47 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot index 8ecddba21fc..dcceb5bb937 100644 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -3,75 +3,103 @@ digraph block { N1[label="exit"]; N2[label="expr 15i"]; N3[label="local mut x"]; - N4[label="expr 151i"]; - N5[label="local mut y"]; - N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l"]; + N4[label="stmt let mut x = 15i;"]; + N5[label="expr 151i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 151i;"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l"]; - N10[label="expr x"]; - N11[label="expr 1i"]; - N12[label="expr x == 1i"]; - N13[label="expr continue \'outer"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { continue \'outer ; \"unreachable\"; }"]; - N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; - N18[label="expr y"]; - N19[label="expr 2i"]; - N20[label="expr y >= 2i"]; - N21[label="expr return"]; - N22[label="(dummy_node)"]; - N23[label="expr \"unreachable\""]; - N24[label="block { return; \"unreachable\"; }"]; - N25[label="expr if y >= 2i { return; \"unreachable\"; }"]; - N26[label="expr 1i"]; - N27[label="expr x"]; - N28[label="expr x -= 1i"]; - N29[label="expr 3i"]; - N30[label="expr y"]; - N31[label="expr y -= 3i"]; - N32[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l"]; - N33[label="expr \"unreachable\""]; - N34[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; - N35[label="expr \"unreachable\""]; - N36[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; + N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l"]; + N10[label="(dummy_node)"]; + N11[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l"]; + N12[label="expr x"]; + N13[label="expr 1i"]; + N14[label="expr x == 1i"]; + N15[label="expr continue \'outer"]; + N16[label="(dummy_node)"]; + N17[label="stmt continue \'outer ;"]; + N18[label="expr \"unreachable\""]; + N19[label="stmt \"unreachable\";"]; + N20[label="block { continue \'outer ; \"unreachable\"; }"]; + N21[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; + N22[label="stmt if x == 1i { continue \'outer ; \"unreachable\"; }"]; + N23[label="expr y"]; + N24[label="expr 2i"]; + N25[label="expr y >= 2i"]; + N26[label="expr return"]; + N27[label="(dummy_node)"]; + N28[label="stmt return;"]; + N29[label="expr \"unreachable\""]; + N30[label="stmt \"unreachable\";"]; + N31[label="block { return; \"unreachable\"; }"]; + N32[label="expr if y >= 2i { return; \"unreachable\"; }"]; + N33[label="stmt if y >= 2i { return; \"unreachable\"; }"]; + N34[label="expr 1i"]; + N35[label="expr x"]; + N36[label="expr x -= 1i"]; + N37[label="stmt x -= 1i;"]; + N38[label="expr 3i"]; + N39[label="expr y"]; + N40[label="expr y -= 3i"]; + N41[label="stmt y -= 3i;"]; + N42[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l"]; + N43[label="stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l"]; + N44[label="expr \"unreachable\""]; + N45[label="stmt \"unreachable\";"]; + N46[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; + N47[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l"]; + N48[label="expr \"unreachable\""]; + N49[label="stmt \"unreachable\";"]; + N50[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N8; + N6 -> N7; + N7 -> N8; N8 -> N10; - N10 -> N11; - N11 -> N12; + N10 -> N12; N12 -> N13; - N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; + N13 -> N14; N14 -> N15; - N15 -> N16; - N12 -> N17; + N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; + N14 -> N21; N20 -> N21; - N21 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l"]; + N21 -> N22; N22 -> N23; N23 -> N24; - N20 -> N25; N24 -> N25; N25 -> N26; - N26 -> N27; + N26 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l }\l"]; N27 -> N28; N28 -> N29; N29 -> N30; N30 -> N31; + N25 -> N32; N31 -> N32; - N32 -> N8; - N9 -> N33; + N32 -> N33; N33 -> N34; - N34 -> N6; - N7 -> N35; + N34 -> N35; N35 -> N36; - N36 -> N1; + N36 -> N37; + N37 -> N38; + N38 -> N39; + N39 -> N40; + N40 -> N41; + N41 -> N42; + N42 -> N10; + N11 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N8; + N9 -> N47; + N47 -> N48; + N48 -> N49; + N49 -> N50; + N50 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot index 718d4687ef9..034ecfb7f20 100644 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot @@ -3,46 +3,55 @@ digraph block { N1[label="exit"]; N2[label="expr 23i"]; N3[label="local mut x"]; - N4[label="expr 23i"]; - N5[label="local mut y"]; - N6[label="expr 23i"]; - N7[label="local mut z"]; - N8[label="(dummy_node)"]; - N9[label="expr x"]; - N10[label="expr 0i"]; - N11[label="expr x > 0i"]; - N12[label="expr while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr 1i"]; - N14[label="expr x"]; - N15[label="expr x -= 1i"]; - N16[label="(dummy_node)"]; - N17[label="expr y"]; - N18[label="expr 0i"]; - N19[label="expr y > 0i"]; - N20[label="expr while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; - N21[label="expr 1i"]; - N22[label="expr y"]; - N23[label="expr y -= 1i"]; - N24[label="(dummy_node)"]; - N25[label="expr z"]; - N26[label="expr 0i"]; - N27[label="expr z > 0i"]; - N28[label="expr while z > 0i { z -= 1i; }"]; - N29[label="expr 1i"]; + N4[label="stmt let mut x = 23i;"]; + N5[label="expr 23i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 23i;"]; + N8[label="expr 23i"]; + N9[label="local mut z"]; + N10[label="stmt let mut z = 23i;"]; + N11[label="(dummy_node)"]; + N12[label="expr x"]; + N13[label="expr 0i"]; + N14[label="expr x > 0i"]; + N15[label="expr while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N16[label="expr 1i"]; + N17[label="expr x"]; + N18[label="expr x -= 1i"]; + N19[label="stmt x -= 1i;"]; + N20[label="(dummy_node)"]; + N21[label="expr y"]; + N22[label="expr 0i"]; + N23[label="expr y > 0i"]; + N24[label="expr while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N25[label="expr 1i"]; + N26[label="expr y"]; + N27[label="expr y -= 1i"]; + N28[label="stmt y -= 1i;"]; + N29[label="(dummy_node)"]; N30[label="expr z"]; - N31[label="expr z -= 1i"]; - N32[label="block { z -= 1i; }"]; - N33[label="expr x"]; - N34[label="expr 10i"]; - N35[label="expr x > 10i"]; - N36[label="expr return"]; - N37[label="(dummy_node)"]; - N38[label="expr \"unreachable\""]; - N39[label="block { return; \"unreachable\"; }"]; - N40[label="expr if x > 10i { return; \"unreachable\"; }"]; - N41[label="block { y -= 1i; while z > 0i { z -= 1i; } if x > 10i { return; \"unreachable\"; } }"]; - N42[label="block {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; - N43[label="block {\l let mut x = 23i;\l let mut y = 23i;\l let mut z = 23i;\l while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l }\l}\l"]; + N31[label="expr 0i"]; + N32[label="expr z > 0i"]; + N33[label="expr while z > 0i { z -= 1i; }"]; + N34[label="expr 1i"]; + N35[label="expr z"]; + N36[label="expr z -= 1i"]; + N37[label="stmt z -= 1i;"]; + N38[label="block { z -= 1i; }"]; + N39[label="stmt while z > 0i { z -= 1i; }"]; + N40[label="expr x"]; + N41[label="expr 10i"]; + N42[label="expr x > 10i"]; + N43[label="expr return"]; + N44[label="(dummy_node)"]; + N45[label="stmt return;"]; + N46[label="expr \"unreachable\""]; + N47[label="stmt \"unreachable\";"]; + N48[label="block { return; \"unreachable\"; }"]; + N49[label="expr if x > 10i { return; \"unreachable\"; }"]; + N50[label="block { y -= 1i; while z > 0i { z -= 1i; } if x > 10i { return; \"unreachable\"; } }"]; + N51[label="block {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N52[label="block {\l let mut x = 23i;\l let mut y = 23i;\l let mut z = 23i;\l while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -54,40 +63,49 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N11 -> N13; + N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N16; + N14 -> N16; N16 -> N17; N17 -> N18; N18 -> N19; N19 -> N20; - N19 -> N21; + N20 -> N21; N21 -> N22; N22 -> N23; N23 -> N24; - N24 -> N25; + N23 -> N25; N25 -> N26; N26 -> N27; N27 -> N28; - N27 -> N29; + N28 -> N29; N29 -> N30; N30 -> N31; N31 -> N32; - N32 -> N24; - N28 -> N33; - N33 -> N34; + N32 -> N33; + N32 -> N34; N34 -> N35; N35 -> N36; - N36 -> N1[label="exiting scope_0 expr while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N36 -> N37; N37 -> N38; - N38 -> N39; - N35 -> N40; + N38 -> N29; + N33 -> N39; N39 -> N40; N40 -> N41; - N41 -> N16; - N20 -> N42; - N42 -> N8; - N12 -> N43; - N43 -> N1; + N41 -> N42; + N42 -> N43; + N43 -> N1[label="exiting scope_0 expr while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0i {\l x -= 1i;\l while y > 0i {\l y -= 1i;\l while z > 0i { z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N44 -> N45; + N45 -> N46; + N46 -> N47; + N47 -> N48; + N42 -> N49; + N48 -> N49; + N49 -> N50; + N50 -> N20; + N24 -> N51; + N51 -> N11; + N15 -> N52; + N52 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot index 646d98a54a7..ddb5b865c2e 100644 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -3,61 +3,79 @@ digraph block { N1[label="exit"]; N2[label="expr 24i"]; N3[label="local mut x"]; - N4[label="expr 24i"]; - N5[label="local mut y"]; - N6[label="expr 24i"]; - N7[label="local mut z"]; - N8[label="(dummy_node)"]; - N9[label="expr loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; - N10[label="expr x"]; - N11[label="expr 0i"]; - N12[label="expr x == 0i"]; - N13[label="expr break"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { break ; \"unreachable\"; }"]; - N17[label="expr if x == 0i { break ; \"unreachable\"; }"]; - N18[label="expr 1i"]; - N19[label="expr x"]; - N20[label="expr x -= 1i"]; - N21[label="(dummy_node)"]; - N22[label="expr loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; - N23[label="expr y"]; - N24[label="expr 0i"]; - N25[label="expr y == 0i"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="expr \"unreachable\""]; - N29[label="block { break ; \"unreachable\"; }"]; - N30[label="expr if y == 0i { break ; \"unreachable\"; }"]; - N31[label="expr 1i"]; - N32[label="expr y"]; - N33[label="expr y -= 1i"]; + N4[label="stmt let mut x = 24i;"]; + N5[label="expr 24i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 24i;"]; + N8[label="expr 24i"]; + N9[label="local mut z"]; + N10[label="stmt let mut z = 24i;"]; + N11[label="(dummy_node)"]; + N12[label="expr loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N13[label="expr x"]; + N14[label="expr 0i"]; + N15[label="expr x == 0i"]; + N16[label="expr break"]; + N17[label="(dummy_node)"]; + N18[label="stmt break ;"]; + N19[label="expr \"unreachable\""]; + N20[label="stmt \"unreachable\";"]; + N21[label="block { break ; \"unreachable\"; }"]; + N22[label="expr if x == 0i { break ; \"unreachable\"; }"]; + N23[label="stmt if x == 0i { break ; \"unreachable\"; }"]; + N24[label="expr 1i"]; + N25[label="expr x"]; + N26[label="expr x -= 1i"]; + N27[label="stmt x -= 1i;"]; + N28[label="(dummy_node)"]; + N29[label="expr loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N30[label="expr y"]; + N31[label="expr 0i"]; + N32[label="expr y == 0i"]; + N33[label="expr break"]; N34[label="(dummy_node)"]; - N35[label="expr loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; - N36[label="expr z"]; - N37[label="expr 0i"]; - N38[label="expr z == 0i"]; - N39[label="expr break"]; - N40[label="(dummy_node)"]; - N41[label="expr \"unreachable\""]; - N42[label="block { break ; \"unreachable\"; }"]; - N43[label="expr if z == 0i { break ; \"unreachable\"; }"]; - N44[label="expr 1i"]; - N45[label="expr z"]; - N46[label="expr z -= 1i"]; - N47[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; - N48[label="expr x"]; - N49[label="expr 10i"]; - N50[label="expr x > 10i"]; - N51[label="expr return"]; - N52[label="(dummy_node)"]; + N35[label="stmt break ;"]; + N36[label="expr \"unreachable\""]; + N37[label="stmt \"unreachable\";"]; + N38[label="block { break ; \"unreachable\"; }"]; + N39[label="expr if y == 0i { break ; \"unreachable\"; }"]; + N40[label="stmt if y == 0i { break ; \"unreachable\"; }"]; + N41[label="expr 1i"]; + N42[label="expr y"]; + N43[label="expr y -= 1i"]; + N44[label="stmt y -= 1i;"]; + N45[label="(dummy_node)"]; + N46[label="expr loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N47[label="expr z"]; + N48[label="expr 0i"]; + N49[label="expr z == 0i"]; + N50[label="expr break"]; + N51[label="(dummy_node)"]; + N52[label="stmt break ;"]; N53[label="expr \"unreachable\""]; - N54[label="block { return; \"unreachable\"; }"]; - N55[label="expr if x > 10i { return; \"unreachable\"; }"]; - N56[label="block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; - N57[label="block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; - N58[label="block {\l let mut x = 24i;\l let mut y = 24i;\l let mut z = 24i;\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l }\l}\l"]; + N54[label="stmt \"unreachable\";"]; + N55[label="block { break ; \"unreachable\"; }"]; + N56[label="expr if z == 0i { break ; \"unreachable\"; }"]; + N57[label="stmt if z == 0i { break ; \"unreachable\"; }"]; + N58[label="expr 1i"]; + N59[label="expr z"]; + N60[label="expr z -= 1i"]; + N61[label="stmt z -= 1i;"]; + N62[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N63[label="stmt loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N64[label="expr x"]; + N65[label="expr 10i"]; + N66[label="expr x > 10i"]; + N67[label="expr return"]; + N68[label="(dummy_node)"]; + N69[label="stmt return;"]; + N70[label="expr \"unreachable\""]; + N71[label="stmt \"unreachable\";"]; + N72[label="block { return; \"unreachable\"; }"]; + N73[label="expr if x > 10i { return; \"unreachable\"; }"]; + N74[label="block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N75[label="block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N76[label="block {\l let mut x = 24i;\l let mut y = 24i;\l let mut z = 24i;\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -65,59 +83,77 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N10; + N8 -> N9; + N9 -> N10; N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N11 -> N13; + N13 -> N14; N14 -> N15; N15 -> N16; - N12 -> N17; - N16 -> N17; + N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; N17 -> N18; N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N23; + N15 -> N22; + N21 -> N22; + N22 -> N23; N23 -> N24; N24 -> N25; N25 -> N26; - N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N26 -> N27; N27 -> N28; - N28 -> N29; - N25 -> N30; - N29 -> N30; + N28 -> N30; N30 -> N31; N31 -> N32; N32 -> N33; - N33 -> N34; - N34 -> N36; + N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N34 -> N35; + N35 -> N36; N36 -> N37; N37 -> N38; + N32 -> N39; N38 -> N39; - N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N39 -> N40; N40 -> N41; N41 -> N42; - N38 -> N43; N42 -> N43; N43 -> N44; N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N34; - N35 -> N48; + N45 -> N47; + N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N51; - N51 -> N1[label="exiting scope_0 expr loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N51 -> N52; N52 -> N53; N53 -> N54; - N50 -> N55; N54 -> N55; + N49 -> N56; N55 -> N56; - N56 -> N21; - N22 -> N57; - N57 -> N8; - N9 -> N58; - N58 -> N1; + N56 -> N57; + N57 -> N58; + N58 -> N59; + N59 -> N60; + N60 -> N61; + N61 -> N62; + N62 -> N45; + N46 -> N63; + N63 -> N64; + N64 -> N65; + N65 -> N66; + N66 -> N67; + N67 -> N1[label="exiting scope_0 expr loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N68 -> N69; + N69 -> N70; + N70 -> N71; + N71 -> N72; + N66 -> N73; + N72 -> N73; + N73 -> N74; + N74 -> N28; + N29 -> N75; + N75 -> N11; + N12 -> N76; + N76 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot index 11b9c7ef05e..9fd4dbfc395 100644 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -3,61 +3,79 @@ digraph block { N1[label="exit"]; N2[label="expr 25i"]; N3[label="local mut x"]; - N4[label="expr 25i"]; - N5[label="local mut y"]; - N6[label="expr 25i"]; - N7[label="local mut z"]; - N8[label="(dummy_node)"]; - N9[label="expr \'a:\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l }\l"]; - N10[label="expr x"]; - N11[label="expr 0i"]; - N12[label="expr x == 0i"]; - N13[label="expr break"]; - N14[label="(dummy_node)"]; - N15[label="expr \"unreachable\""]; - N16[label="block { break ; \"unreachable\"; }"]; - N17[label="expr if x == 0i { break ; \"unreachable\"; }"]; - N18[label="expr 1i"]; - N19[label="expr x"]; - N20[label="expr x -= 1i"]; - N21[label="(dummy_node)"]; - N22[label="expr \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l"]; - N23[label="expr y"]; - N24[label="expr 0i"]; - N25[label="expr y == 0i"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="expr \"unreachable\""]; - N29[label="block { break ; \"unreachable\"; }"]; - N30[label="expr if y == 0i { break ; \"unreachable\"; }"]; - N31[label="expr 1i"]; - N32[label="expr y"]; - N33[label="expr y -= 1i"]; + N4[label="stmt let mut x = 25i;"]; + N5[label="expr 25i"]; + N6[label="local mut y"]; + N7[label="stmt let mut y = 25i;"]; + N8[label="expr 25i"]; + N9[label="local mut z"]; + N10[label="stmt let mut z = 25i;"]; + N11[label="(dummy_node)"]; + N12[label="expr \'a:\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l }\l"]; + N13[label="expr x"]; + N14[label="expr 0i"]; + N15[label="expr x == 0i"]; + N16[label="expr break"]; + N17[label="(dummy_node)"]; + N18[label="stmt break ;"]; + N19[label="expr \"unreachable\""]; + N20[label="stmt \"unreachable\";"]; + N21[label="block { break ; \"unreachable\"; }"]; + N22[label="expr if x == 0i { break ; \"unreachable\"; }"]; + N23[label="stmt if x == 0i { break ; \"unreachable\"; }"]; + N24[label="expr 1i"]; + N25[label="expr x"]; + N26[label="expr x -= 1i"]; + N27[label="stmt x -= 1i;"]; + N28[label="(dummy_node)"]; + N29[label="expr \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l"]; + N30[label="expr y"]; + N31[label="expr 0i"]; + N32[label="expr y == 0i"]; + N33[label="expr break"]; N34[label="(dummy_node)"]; - N35[label="expr \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; - N36[label="expr z"]; - N37[label="expr 0i"]; - N38[label="expr z == 0i"]; - N39[label="expr break"]; - N40[label="(dummy_node)"]; - N41[label="expr \"unreachable\""]; - N42[label="block { break ; \"unreachable\"; }"]; - N43[label="expr if z == 0i { break ; \"unreachable\"; }"]; - N44[label="expr 1i"]; - N45[label="expr z"]; - N46[label="expr z -= 1i"]; - N47[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; - N48[label="expr x"]; - N49[label="expr 10i"]; - N50[label="expr x > 10i"]; - N51[label="expr continue \'a"]; - N52[label="(dummy_node)"]; + N35[label="stmt break ;"]; + N36[label="expr \"unreachable\""]; + N37[label="stmt \"unreachable\";"]; + N38[label="block { break ; \"unreachable\"; }"]; + N39[label="expr if y == 0i { break ; \"unreachable\"; }"]; + N40[label="stmt if y == 0i { break ; \"unreachable\"; }"]; + N41[label="expr 1i"]; + N42[label="expr y"]; + N43[label="expr y -= 1i"]; + N44[label="stmt y -= 1i;"]; + N45[label="(dummy_node)"]; + N46[label="expr \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N47[label="expr z"]; + N48[label="expr 0i"]; + N49[label="expr z == 0i"]; + N50[label="expr break"]; + N51[label="(dummy_node)"]; + N52[label="stmt break ;"]; N53[label="expr \"unreachable\""]; - N54[label="block { continue \'a ; \"unreachable\"; }"]; - N55[label="expr if x > 10i { continue \'a ; \"unreachable\"; }"]; - N56[label="block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; - N57[label="block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; - N58[label="block {\l let mut x = 25i;\l let mut y = 25i;\l let mut z = 25i;\l \'a:\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a:\l loop {\l if z == 0i { break ; \"unreachable\"; }\l z -= 1i;\l }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; + N54[label="stmt \"unreachable\";"]; + N55[label="block { break ; \"unreachable\"; }"]; + N56[label="expr if z == 0i { break ; \"unreachable\"; }"]; + N57[label="stmt if z == 0i { break ; \"unreachable\"; }"]; + N58[label="expr 1i"]; + N59[label="expr z"]; + N60[label="expr z -= 1i"]; + N61[label="stmt z -= 1i;"]; + N62[label="block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N63[label="stmt \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N64[label="expr x"]; + N65[label="expr 10i"]; + N66[label="expr x > 10i"]; + N67[label="expr continue \'a"]; + N68[label="(dummy_node)"]; + N69[label="stmt continue \'a ;"]; + N70[label="expr \"unreachable\""]; + N71[label="stmt \"unreachable\";"]; + N72[label="block { continue \'a ; \"unreachable\"; }"]; + N73[label="expr if x > 10i { continue \'a ; \"unreachable\"; }"]; + N74[label="block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N75[label="block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; + N76[label="block {\l let mut x = 25i;\l let mut y = 25i;\l let mut z = 25i;\l \'a:\l loop {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a:\l loop {\l if z == 0i { break ; \"unreachable\"; }\l z -= 1i;\l }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -65,59 +83,77 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N10; + N8 -> N9; + N9 -> N10; N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; + N11 -> N13; + N13 -> N14; N14 -> N15; N15 -> N16; - N12 -> N17; - N16 -> N17; + N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; N17 -> N18; N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N23; + N15 -> N22; + N21 -> N22; + N22 -> N23; N23 -> N24; N24 -> N25; N25 -> N26; - N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N26 -> N27; N27 -> N28; - N28 -> N29; - N25 -> N30; - N29 -> N30; + N28 -> N30; N30 -> N31; N31 -> N32; N32 -> N33; - N33 -> N34; - N34 -> N36; + N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N34 -> N35; + N35 -> N36; N36 -> N37; N37 -> N38; + N32 -> N39; N38 -> N39; - N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N39 -> N40; N40 -> N41; N41 -> N42; - N38 -> N43; N42 -> N43; N43 -> N44; N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N34; - N35 -> N48; + N45 -> N47; + N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N51; - N51 -> N21[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N51 -> N52; N52 -> N53; N53 -> N54; - N50 -> N55; N54 -> N55; + N49 -> N56; N55 -> N56; - N56 -> N21; - N22 -> N57; - N57 -> N8; - N9 -> N58; - N58 -> N1; + N56 -> N57; + N57 -> N58; + N58 -> N59; + N59 -> N60; + N60 -> N61; + N61 -> N62; + N62 -> N45; + N46 -> N63; + N63 -> N64; + N64 -> N65; + N65 -> N66; + N66 -> N67; + N67 -> N28[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N68 -> N69; + N69 -> N70; + N70 -> N71; + N71 -> N72; + N66 -> N73; + N72 -> N73; + N73 -> N74; + N74 -> N28; + N29 -> N75; + N75 -> N11; + N12 -> N76; + N76 -> N1; } diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs index dec53672d87..6e67b3f6add 100644 --- a/src/test/run-pass/alignment-gep-tup-like-1.rs +++ b/src/test/run-pass/alignment-gep-tup-like-1.rs @@ -29,11 +29,11 @@ impl Invokable for Invoker { } } -fn f(a: A, b: u16) -> Box> { +fn f(a: A, b: u16) -> Box+'static> { box Invoker { a: a, b: b, - } as (Box>) + } as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/borrowck-freeze-frozen-mut.rs b/src/test/run-pass/borrowck-freeze-frozen-mut.rs index 4044e9f06af..f224042bc79 100644 --- a/src/test/run-pass/borrowck-freeze-frozen-mut.rs +++ b/src/test/run-pass/borrowck-freeze-frozen-mut.rs @@ -10,7 +10,7 @@ // Test that a `&mut` inside of an `&` is freezable. -struct MutSlice<'a, T> { +struct MutSlice<'a, T:'a> { data: &'a mut [T] } diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs index 59d532a40e7..69878d4a06b 100644 --- a/src/test/run-pass/close-over-big-then-small-data.rs +++ b/src/test/run-pass/close-over-big-then-small-data.rs @@ -33,11 +33,11 @@ impl Invokable for Invoker { } } -fn f(a: A, b: u16) -> Box> { +fn f(a: A, b: u16) -> Box+'static> { box Invoker { a: a, b: b, - } as (Box>) + } as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index c05f2502a89..aa4d48e5ae0 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -26,7 +26,7 @@ fn call_this(f: |&str|:Send) { f("Hello!"); } -fn call_that(f: <'a>|&'a int, &'a int|: -> int) { +fn call_that(f: <'a>|&'a int, &'a int| -> int) { let (ten, forty_two) = (10, 42); println!("Your lucky number is {}", f(&ten, &forty_two)); } diff --git a/src/test/run-pass/closure-syntax.rs b/src/test/run-pass/closure-syntax.rs index 7b8d1dd7576..c2fbc2a4bf2 100644 --- a/src/test/run-pass/closure-syntax.rs +++ b/src/test/run-pass/closure-syntax.rs @@ -13,16 +13,16 @@ fn foo() {} trait Bar1 {} -impl Bar1 for proc() {} +impl Bar1 for proc():'static {} trait Bar2 {} -impl Bar2 for proc(): Send {} +impl Bar2 for proc():Send {} trait Bar3 {} impl<'b> Bar3 for <'a>|&'a int|: 'b + Send -> &'a int {} trait Bar4 {} -impl Bar4 for proc<'a>(&'a int) -> &'a int {} +impl Bar4 for proc<'a>(&'a int):'static -> &'a int {} struct Foo<'a> { a: ||: 'a, @@ -30,9 +30,9 @@ struct Foo<'a> { c: <'b>||: 'a, d: ||: 'a + Sync, e: <'b>|int|: 'a + Sync -> &'b f32, - f: proc(), - g: proc(): 'static + Sync, - h: proc<'b>(int): Sync -> &'b f32, + f: proc():'static, + g: proc():'static+Sync, + h: proc<'b>(int):'static+Sync -> &'b f32, } fn f<'a>(a: &'a int, f: <'b>|&'b int| -> &'b int) -> &'a int { diff --git a/src/test/run-pass/colorful-write-macros.rs b/src/test/run-pass/colorful-write-macros.rs index 724e57bdef2..60b6d8f8be0 100644 --- a/src/test/run-pass/colorful-write-macros.rs +++ b/src/test/run-pass/colorful-write-macros.rs @@ -18,7 +18,7 @@ use std::fmt; use std::fmt::FormatWriter; struct Foo<'a> { - writer: &'a mut Writer, + writer: &'a mut Writer+'a, other: &'a str, } diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index ac2922e92d4..e95b1ed2f0e 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -13,8 +13,8 @@ * * The hash should concentrate entropy in the lower bits. */ -type HashFn = proc(K) -> uint; -type EqFn = proc(K, K) -> bool; +type HashFn = proc(K):'static -> uint; +type EqFn = proc(K, K):'static -> bool; struct LM { resize_at: uint, size: uint } diff --git a/src/test/run-pass/issue-10802.rs b/src/test/run-pass/issue-10802.rs index 4fda506ae64..7487ea81fa8 100644 --- a/src/test/run-pass/issue-10802.rs +++ b/src/test/run-pass/issue-10802.rs @@ -30,9 +30,9 @@ trait MyTrait { } impl MyTrait for Box {} impl MyTrait for Box {} -struct Whatever { w: Box } +struct Whatever { w: Box } impl Whatever { - fn new(w: Box) -> Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs index 5b52bc34d2b..c2c291c0bec 100644 --- a/src/test/run-pass/issue-11205.rs +++ b/src/test/run-pass/issue-11205.rs @@ -49,7 +49,7 @@ fn main() { foog(x, &[box 1i]); struct T<'a> { - t: [&'a Foo, ..2] + t: [&'a Foo+'a, ..2] } let _n = T { t: [&1i, &2i] @@ -64,7 +64,7 @@ fn main() { }; struct F<'b> { - t: &'b [&'b Foo] + t: &'b [&'b Foo+'b] } let _n = F { t: &[&1i, &2i] @@ -80,7 +80,7 @@ fn main() { }; struct M<'a> { - t: &'a [Box] + t: &'a [Box] } let _n = M { t: &[box 1i, box 2i] diff --git a/src/test/run-pass/issue-11612.rs b/src/test/run-pass/issue-11612.rs index 5fb2274a446..fa25d25df05 100644 --- a/src/test/run-pass/issue-11612.rs +++ b/src/test/run-pass/issue-11612.rs @@ -14,7 +14,7 @@ trait A {} -struct B<'a, T> { +struct B<'a, T:'a> { f: &'a T } diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs index 5a244250852..14c1b1b06ea 100644 --- a/src/test/run-pass/issue-11677.rs +++ b/src/test/run-pass/issue-11677.rs @@ -14,7 +14,8 @@ trait X {} -struct S {f: Box>, g: Box>} +struct S {f: Box+'static>, + g: Box+'static>} struct F; impl X for F {} diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index b53c2258736..c2bd8c5b3e5 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -14,7 +14,7 @@ trait Foo {} struct Bar; -impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar { +impl<'a> std::ops::Fn<(&'a Foo+'a,), ()> for Bar { extern "rust-call" fn call(&self, _: (&'a Foo,)) {} } diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index af0bc78094e..74b9df9b88d 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -33,8 +33,8 @@ impl Alloy { } } -impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> { - extern "rust-call" fn call(&self, (_res,): (&'b mut Response,)) {} +impl<'a, 'b> Fn<(&'b mut Response+'b,),()> for SendFile<'a> { + extern "rust-call" fn call(&self, (_res,): (&'b mut Response+'b,)) {} } impl Ingot for HelloWorld { diff --git a/src/test/run-pass/issue-2734.rs b/src/test/run-pass/issue-2734.rs index 11ebf014bc6..9eec2d048d4 100644 --- a/src/test/run-pass/issue-2734.rs +++ b/src/test/run-pass/issue-2734.rs @@ -12,8 +12,8 @@ trait hax { } impl hax for A { } -fn perform_hax(x: Box) -> Box { - box x as Box +fn perform_hax(x: Box) -> Box { + box x as Box } fn deadcode() { diff --git a/src/test/run-pass/issue-2735.rs b/src/test/run-pass/issue-2735.rs index 1a5b175cffc..74b64bb87cf 100644 --- a/src/test/run-pass/issue-2735.rs +++ b/src/test/run-pass/issue-2735.rs @@ -12,8 +12,8 @@ trait hax { } impl hax for A { } -fn perform_hax(x: Box) -> Box { - box x as Box +fn perform_hax(x: Box) -> Box { + box x as Box } fn deadcode() { diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index b7818ea732a..2dac64b2ec8 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -15,7 +15,7 @@ use std::path::{Path}; use std::path; use std::result; -type rsrc_loader = proc(path: &Path) -> result::Result; +type rsrc_loader = proc(path: &Path):'static -> result::Result; fn tester() { diff --git a/src/test/run-pass/issue-5192.rs b/src/test/run-pass/issue-5192.rs index 0dd6623a349..3b1a8c4a190 100644 --- a/src/test/run-pass/issue-5192.rs +++ b/src/test/run-pass/issue-5192.rs @@ -28,12 +28,12 @@ impl EventLoop for UvEventLoop { } pub struct Scheduler { - event_loop: Box, + event_loop: Box, } impl Scheduler { - pub fn new(event_loop: Box) -> Scheduler { + pub fn new(event_loop: Box) -> Scheduler { Scheduler { event_loop: event_loop, } diff --git a/src/test/run-pass/issue-5554.rs b/src/test/run-pass/issue-5554.rs index 9151fb2b764..24dcc3838c5 100644 --- a/src/test/run-pass/issue-5554.rs +++ b/src/test/run-pass/issue-5554.rs @@ -17,7 +17,10 @@ pub struct X { } // reordering these bounds stops the ICE -impl Default for X { +// +// nmatsakis: This test used to have the bounds Default + PartialEq + +// Default, but having duplicate bounds became illegal. +impl Default for X { fn default() -> X { X { a: Default::default() } } diff --git a/src/test/run-pass/issue-5708.rs b/src/test/run-pass/issue-5708.rs index 2bb320e5562..6168753b6d7 100644 --- a/src/test/run-pass/issue-5708.rs +++ b/src/test/run-pass/issue-5708.rs @@ -29,7 +29,7 @@ impl Inner for int { } struct Outer<'a> { - inner: &'a Inner + inner: &'a Inner+'a } impl<'a> Outer<'a> { @@ -51,7 +51,7 @@ pub fn main() { trait MyTrait { } pub struct MyContainer<'a, T> { - foos: Vec<&'a MyTrait> , + foos: Vec<&'a MyTrait+'a> , } impl<'a, T> MyContainer<'a, T> { diff --git a/src/test/run-pass/issue-6318.rs b/src/test/run-pass/issue-6318.rs index 6512db3b1c5..a4576bc7c8c 100644 --- a/src/test/run-pass/issue-6318.rs +++ b/src/test/run-pass/issue-6318.rs @@ -10,7 +10,7 @@ pub enum Thing { - A(Box) + A(Box) } pub trait Foo {} @@ -20,7 +20,7 @@ pub struct Struct; impl Foo for Struct {} pub fn main() { - match A(box Struct as Box) { + match A(box Struct as Box) { A(_a) => 0i, }; } diff --git a/src/test/run-pass/issue-8249.rs b/src/test/run-pass/issue-8249.rs index 3ca6c806ef5..dae5db11b0a 100644 --- a/src/test/run-pass/issue-8249.rs +++ b/src/test/run-pass/issue-8249.rs @@ -13,7 +13,7 @@ struct B; impl A for B {} struct C<'a> { - foo: &'a mut A, + foo: &'a mut A+'a, } fn foo(a: &mut A) { diff --git a/src/test/run-pass/issue-9719.rs b/src/test/run-pass/issue-9719.rs index ac200e6c1ac..0f054a3083d 100644 --- a/src/test/run-pass/issue-9719.rs +++ b/src/test/run-pass/issue-9719.rs @@ -16,7 +16,7 @@ mod a { pub trait X {} impl X for int {} - pub struct Z<'a>(Enum<&'a X>); + pub struct Z<'a>(Enum<&'a X+'a>); fn foo() { let x = 42i; let z = Z(A(&x as &X)); let _ = z; } } @@ -24,7 +24,7 @@ mod b { trait X {} impl X for int {} struct Y<'a>{ - x:Option<&'a X>, + x:Option<&'a X+'a>, } fn bar() { @@ -36,7 +36,7 @@ mod b { mod c { pub trait X { fn f(&self); } impl X for int { fn f(&self) {} } - pub struct Z<'a>(Option<&'a X>); + pub struct Z<'a>(Option<&'a X+'a>); fn main() { let x = 42i; let z = Z(Some(&x as &X)); let _ = z; } } diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs index 511629a6d7a..fbd6c92a020 100644 --- a/src/test/run-pass/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs @@ -17,9 +17,8 @@ impl repeat for Box { } } -fn repeater(v: Box) -> Box> { - // Note: owned kind is not necessary as A appears in the trait type - box v as Box> // No +fn repeater(v: Box) -> Box+'static> { + box v as Box+'static> // No } pub fn main() { diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs index 84d49820239..f704545af33 100644 --- a/src/test/run-pass/newlambdas-ret-infer.rs +++ b/src/test/run-pass/newlambdas-ret-infer.rs @@ -11,7 +11,7 @@ // Test that the lambda kind is inferred correctly as a return // expression -fn unique() -> proc() { return proc() (); } +fn unique() -> proc():'static { return proc() (); } pub fn main() { } diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index 86ad53c0228..22e51ea9a75 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -11,7 +11,7 @@ // Test that the lambda kind is inferred correctly as a return // expression -fn unique() -> proc() { proc() () } +fn unique() -> proc():'static { proc() () } pub fn main() { } diff --git a/src/test/run-pass/overloaded-autoderef-indexing.rs b/src/test/run-pass/overloaded-autoderef-indexing.rs index 37e7ee6c216..5c4befcd0c8 100644 --- a/src/test/run-pass/overloaded-autoderef-indexing.rs +++ b/src/test/run-pass/overloaded-autoderef-indexing.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct DerefArray<'a, T> { +struct DerefArray<'a, T:'a> { inner: &'a [T] } diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 6deae8618fa..27ef90d7376 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -30,7 +30,7 @@ fn object_invoke1<'d>(x: &'d Trait<'d>) -> (int, int) { } struct Struct1<'e> { - f: &'e Trait<'e> + f: &'e Trait<'e>+'e } fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (int,int) { @@ -40,7 +40,7 @@ fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (int,int) { } struct Struct2<'h, 'i> { - f: &'h Trait<'i> + f: &'h Trait<'i>+'h } fn object_invoke2<'j, 'k>(x: &'k Trait<'j>) -> int { @@ -78,8 +78,8 @@ impl<'s> Trait<'s> for (int,int) { } } -impl<'t> MakerTrait<'t> for Box> { - fn mk() -> Box> { box() (4i,5i) as Box } +impl<'t> MakerTrait<'t> for Box+'static> { + fn mk() -> Box+'static> { box() (4i,5i) as Box } } enum List<'l> { diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs index c262370ac5d..58de2e0e20e 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs @@ -15,7 +15,7 @@ trait GetRef<'a, T> { fn get(&self) -> &'a T; } -struct Box<'a, T> { +struct Box<'a, T:'a> { t: &'a T } diff --git a/src/test/run-pass/swap-overlapping.rs b/src/test/run-pass/swap-overlapping.rs index 1a96af43d23..f33483d31bf 100644 --- a/src/test/run-pass/swap-overlapping.rs +++ b/src/test/run-pass/swap-overlapping.rs @@ -34,8 +34,8 @@ pub enum TestName { } pub enum TestFn { - DynTestFn(proc()), - DynBenchFn(proc(&mut int)) + DynTestFn(proc():'static), + DynBenchFn(proc(&mut int):'static) } pub struct TestDesc { diff --git a/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs b/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs index 55ad22dd0bf..5b744a44132 100644 --- a/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs +++ b/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs @@ -17,7 +17,7 @@ trait A { } impl A for int { - fn foo(&self) {} + fn foo(&self) {} // Ord implies Eq, so this is ok. } fn main() {} diff --git a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs index ebcaf772db4..e3234f03754 100644 --- a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs +++ b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs @@ -12,11 +12,11 @@ trait U {} trait T {} trait S2 { - fn m(x: Box>) {} + fn m(x: Box+'static>) {} } struct St { - f: Box>, + f: Box+'static>, } impl St { diff --git a/src/test/run-pass/trait-object-generics.rs b/src/test/run-pass/trait-object-generics.rs index 3c5ae6b57a3..b20915763f2 100644 --- a/src/test/run-pass/trait-object-generics.rs +++ b/src/test/run-pass/trait-object-generics.rs @@ -21,7 +21,7 @@ pub struct Impl { * task failed at 'index out of bounds: the len is 1 but the index is 1', * src/librustc/middle/subst.rs:58 */ - t: Box> + t: Box+'static> } impl Impl { diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs index c4b990abf7e..746af1b9cf5 100644 --- a/src/test/run-pass/unboxed-closures-boxed.rs +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -12,8 +12,8 @@ use std::ops::FnMut; -fn make_adder(x: int) -> Box> { - (box |&mut: y: int| -> int { x + y }) as Box> + fn make_adder(x: int) -> Box+'static> { + (box |&mut: y: int| -> int { x + y }) as Box+'static> } pub fn main() {