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

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

View File

@ -105,9 +105,9 @@ pub trait BoxAny {
}
#[stable]
impl BoxAny for Box<Any> {
impl BoxAny for Box<Any+'static> {
#[inline]
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any+'static>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
@ -132,7 +132,7 @@ impl<T: fmt::Show> fmt::Show for Box<T> {
}
}
impl fmt::Show for Box<Any> {
impl fmt::Show for Box<Any+'static> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Box<Any>")
}

View File

@ -49,19 +49,29 @@ struct Node<T> {
value: T,
}
/// An iterator over references to the items of a `DList`.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Items<'a, T> {
head: &'a Link<T>,
tail: Rawlink<Node<T>>,
nelem: uint,
}
/// An iterator over references to the items of a `DList`.
#[cfg(not(stage0))]
pub struct Items<'a, T:'a> {
head: &'a Link<T>,
tail: Rawlink<Node<T>>,
nelem: uint,
}
// FIXME #11820: the &'a Option<> of the Link stops clone working.
impl<'a, T> Clone for Items<'a, T> {
fn clone(&self) -> Items<'a, T> { *self }
}
/// An iterator over mutable references to the items of a `DList`.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct MutItems<'a, T> {
list: &'a mut DList<T>,
head: Rawlink<Node<T>>,
@ -69,7 +79,16 @@ pub struct MutItems<'a, T> {
nelem: uint,
}
/// A consuming iterator over the items of a `DList`.
/// An iterator over mutable references to the items of a `DList`.
#[cfg(not(stage0))]
pub struct MutItems<'a, T:'a> {
list: &'a mut DList<T>,
head: Rawlink<Node<T>>,
tail: Rawlink<Node<T>>,
nelem: uint,
}
/// An iterator over mutable references to the items of a `DList`.
#[deriving(Clone)]
pub struct MoveItems<T> {
list: DList<T>

View File

@ -515,11 +515,18 @@ impl<T: Ord> PriorityQueue<T> {
}
}
/// `PriorityQueue` iterator.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Items <'a, T> {
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() }

View File

@ -293,7 +293,8 @@ impl<T> RingBuf<T> {
}
}
/// `RingBuf` iterator.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Items<'a, T> {
lo: uint,
index: uint,
@ -301,6 +302,15 @@ pub struct Items<'a, T> {
elts: &'a [Option<T>],
}
/// `RingBuf` iterator.
#[cfg(not(stage0))]
pub struct Items<'a, T:'a> {
lo: uint,
index: uint,
rindex: uint,
elts: &'a [Option<T>],
}
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a T> {
@ -348,13 +358,22 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
}
}
/// `RingBuf` mutable iterator.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct MutItems<'a, T> {
remaining1: &'a mut [Option<T>],
remaining2: &'a mut [Option<T>],
nelts: uint,
}
/// `RingBuf` mutable iterator.
#[cfg(not(stage0))]
pub struct MutItems<'a, T:'a> {
remaining1: &'a mut [Option<T>],
remaining2: &'a mut [Option<T>],
nelts: uint,
}
impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> {
#[inline]
#[allow(deprecated)] // mut_shift_ref

View File

@ -489,19 +489,37 @@ macro_rules! double_ended_iterator {
}
}
/// Forward iterator over a map.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Entries<'a, T> {
front: uint,
back: uint,
iter: slice::Items<'a, Option<T>>
}
/// Forward iterator over a map.
#[cfg(not(stage0))]
pub struct Entries<'a, T:'a> {
front: uint,
back: uint,
iter: slice::Items<'a, Option<T>>
}
iterator!(impl Entries -> (uint, &'a T), get_ref)
double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref)
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct MutEntries<'a, T> {
front: uint,
back: uint,
iter: slice::MutItems<'a, Option<T>>
}
/// Forward iterator over the key-value pairs of a map, with the
/// values being mutable.
pub struct MutEntries<'a, T> {
#[cfg(not(stage0))]
pub struct MutEntries<'a, T:'a> {
front: uint,
back: uint,
iter: slice::MutItems<'a, Option<T>>

View File

@ -668,7 +668,8 @@ impl<K: Ord, V> TreeMap<K, V> {
}
}
/// A lazy forward iterator over a map.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Entries<'a, K, V> {
stack: Vec<&'a TreeNode<K, V>>,
// See the comment on MutEntries; this is just to allow
@ -679,13 +680,32 @@ pub struct Entries<'a, K, V> {
remaining_max: uint
}
/// Lazy backward iterator over a map.
/// Lazy forward iterator over a map
#[cfg(not(stage0))]
pub struct Entries<'a, K:'a, V:'a> {
stack: Vec<&'a TreeNode<K, V>>,
// See the comment on MutEntries; this is just to allow
// code-sharing (for this immutable-values iterator it *could* very
// well be Option<&'a TreeNode<K,V>>).
node: *const TreeNode<K, V>,
remaining_min: uint,
remaining_max: uint
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct RevEntries<'a, K, V> {
iter: Entries<'a, K, V>,
}
/// A lazy forward iterator over a map that allows for the mutation of
/// the values.
/// Lazy backward iterator over a map
#[cfg(not(stage0))]
pub struct RevEntries<'a, K:'a, V:'a> {
iter: Entries<'a, K, V>,
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct MutEntries<'a, K, V> {
stack: Vec<&'a mut TreeNode<K, V>>,
// Unfortunately, we require some unsafe-ness to get around the
@ -712,11 +732,46 @@ pub struct MutEntries<'a, K, V> {
remaining_max: uint
}
/// Lazy backward iterator over a map.
/// Lazy forward iterator over a map that allows for the mutation of
/// the values.
#[cfg(not(stage0))]
pub struct MutEntries<'a, K:'a, V:'a> {
stack: Vec<&'a mut TreeNode<K, V>>,
// Unfortunately, we require some unsafe-ness to get around the
// fact that we would be storing a reference *into* one of the
// nodes in the stack.
//
// As far as the compiler knows, this would let us invalidate the
// reference by assigning a new value to this node's position in
// its parent, which would cause this current one to be
// deallocated so this reference would be invalid. (i.e. the
// compilers complaints are 100% correct.)
//
// However, as far as you humans reading this code know (or are
// about to know, if you haven't read far enough down yet), we are
// only reading from the TreeNode.{left,right} fields. the only
// thing that is ever mutated is the .value field (although any
// actual mutation that happens is done externally, by the
// iterator consumer). So, don't be so concerned, rustc, we've got
// it under control.
//
// (This field can legitimately be null.)
node: *mut TreeNode<K, V>,
remaining_min: uint,
remaining_max: uint
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct RevMutEntries<'a, K, V> {
iter: MutEntries<'a, K, V>,
}
/// Lazy backward iterator over a map
#[cfg(not(stage0))]
pub struct RevMutEntries<'a, K:'a, V:'a> {
iter: MutEntries<'a, K, V>,
}
/// TreeMap keys iterator.
pub type Keys<'a, K, V> =
@ -885,9 +940,7 @@ fn mut_deref<K, V>(x: &mut Option<Box<TreeNode<K, V>>>)
}
}
/// A lazy forward iterator over a map that consumes the map while iterating.
/// Lazy forward iterator over a map that consumes the map while iterating
pub struct MoveEntries<K, V> {
stack: Vec<TreeNode<K, V>>,
remaining: uint
@ -1322,45 +1375,90 @@ impl<T: Ord> TreeSet<T> {
}
}
/// A lazy forward iterator over a set.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct SetItems<'a, T> {
iter: Entries<'a, T, ()>
}
/// Lazy backward iterator over a set.
/// A lazy forward iterator over a set.
#[cfg(not(stage0))]
pub struct SetItems<'a, T:'a> {
iter: Entries<'a, T, ()>
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct RevSetItems<'a, T> {
iter: RevEntries<'a, T, ()>
}
/// A lazy backward iterator over a set.
#[cfg(not(stage0))]
pub struct RevSetItems<'a, T:'a> {
iter: RevEntries<'a, T, ()>
}
/// A lazy forward iterator over a set that consumes the set while iterating.
pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
/// A lazy iterator producing elements in the set difference (in-order).
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct DifferenceItems<'a, T> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// A lazy iterator producing elements in the set symmetric difference (in-order).
/// A lazy iterator producing elements in the set difference (in-order).
#[cfg(not(stage0))]
pub struct DifferenceItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct SymDifferenceItems<'a, T> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// A lazy iterator producing elements in the set intersection (in-order).
/// A lazy iterator producing elements in the set symmetric difference (in-order).
#[cfg(not(stage0))]
pub struct SymDifferenceItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct IntersectionItems<'a, T> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// A lazy iterator producing elements in the set union (in-order).
/// A lazy iterator producing elements in the set intersection (in-order).
#[cfg(not(stage0))]
pub struct IntersectionItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct UnionItems<'a, T> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is
/// `None`.
/// A lazy iterator producing elements in the set union (in-order).
#[cfg(not(stage0))]
pub struct UnionItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
short: Ordering, long: Ordering) -> Ordering {
match (x, y) {

View File

@ -857,7 +857,8 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint,
return ret;
}
/// A forward iterator over a map.
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Entries<'a, T> {
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
@ -865,9 +866,28 @@ pub struct Entries<'a, T> {
remaining_max: uint
}
/// A forward iterator over a map.
#[cfg(not(stage0))]
pub struct Entries<'a, T:'a> {
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
remaining_min: uint,
remaining_max: uint
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct MutEntries<'a, T> {
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
remaining_min: uint,
remaining_max: uint
}
/// A forward iterator over the key-value pairs of a map, with the
/// values being mutable.
pub struct MutEntries<'a, T> {
#[cfg(not(stage0))]
pub struct MutEntries<'a, T:'a> {
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
remaining_min: uint,

View File

@ -1620,9 +1620,13 @@ pub struct MoveItems<T> {
impl<T> Iterator<T> for MoveItems<T> {
#[inline]
fn next(&mut self) -> Option<T> {
fn next<'a>(&'a mut self) -> Option<T> {
unsafe {
self.iter.next().map(|x| ptr::read(x))
// Unsafely transmute from Items<'static, T> to Items<'a,
// T> because otherwise the type checker requires that T
// be bounded by 'static.
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
iter.next().map(|x| ptr::read(x))
}
}
@ -1634,9 +1638,13 @@ impl<T> Iterator<T> for MoveItems<T> {
impl<T> DoubleEndedIterator<T> for MoveItems<T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
fn next_back<'a>(&'a mut self) -> Option<T> {
unsafe {
self.iter.next_back().map(|x| ptr::read(x))
// Unsafely transmute from Items<'static, T> to Items<'a,
// T> because otherwise the type checker requires that T
// be bounded by 'static.
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
iter.next_back().map(|x| ptr::read(x))
}
}
}

View File

@ -132,7 +132,7 @@ pub trait AnyRefExt<'a> {
}
#[stable]
impl<'a> AnyRefExt<'a> for &'a Any {
impl<'a> AnyRefExt<'a> for &'a Any+'a {
#[inline]
#[stable]
fn is<T: 'static>(self) -> bool {
@ -181,7 +181,7 @@ pub trait AnyMutRefExt<'a> {
}
#[stable]
impl<'a> AnyMutRefExt<'a> for &'a mut Any {
impl<'a> AnyMutRefExt<'a> for &'a mut Any+'a {
#[inline]
#[unstable = "naming conventions around acquiring references may change"]
fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {

View File

@ -324,6 +324,16 @@ impl<T: PartialEq> PartialEq for RefCell<T> {
/// Wraps a borrowed reference to a value in a `RefCell` box.
#[unstable]
#[cfg(not(stage0))]
pub struct Ref<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}
/// Dox.
#[unstable]
#[cfg(stage0)]
pub struct Ref<'b, T> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
@ -369,6 +379,16 @@ pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
#[unstable]
#[cfg(not(stage0))]
pub struct RefMut<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}
/// Dox.
#[unstable]
#[cfg(stage0)]
pub struct RefMut<'b, T> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref

View File

@ -102,6 +102,13 @@ pub fn try_finally<T,U,R>(mutate: &mut T,
try_fn(&mut *f.mutate, drop)
}
#[cfg(not(stage0))]
struct Finallyalizer<'a,A:'a> {
mutate: &'a mut A,
dtor: |&mut A|: 'a
}
#[cfg(stage0)]
struct Finallyalizer<'a,A> {
mutate: &'a mut A,
dtor: |&mut A|: 'a

View File

@ -92,7 +92,7 @@ pub struct Formatter<'a> {
/// Optionally specified precision for numeric types
pub precision: Option<uint>,
buf: &'a mut FormatWriter,
buf: &'a mut FormatWriter+'a,
curarg: slice::Items<'a, Argument<'a>>,
args: &'a [Argument<'a>],
}
@ -524,7 +524,7 @@ impl<'a, T: Show> Show for &'a T {
impl<'a, T: Show> Show for &'a mut T {
fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
}
impl<'a> Show for &'a Show {
impl<'a> Show for &'a Show+'a {
fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) }
}
@ -692,7 +692,7 @@ macro_rules! tuple (
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
impl<'a> Show for &'a any::Any {
impl<'a> Show for &'a any::Any+'a {
fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
}

View File

@ -673,7 +673,7 @@ pub trait MutableDoubleEndedIterator {
fn reverse_(&mut self);
}
impl<'a, A, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
impl<'a, A:'a, T: DoubleEndedIterator<&'a mut A>> MutableDoubleEndedIterator for T {
// FIXME: #5898: should be called `reverse`
/// Use an iterator to reverse a container in-place
fn reverse_(&mut self) {
@ -777,18 +777,26 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
/// A mutable reference to an iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[cfg(not(stage0))]
pub struct ByRef<'a, T:'a> {
iter: &'a mut T
}
/// Dox
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[cfg(stage0)]
pub struct ByRef<'a, T> {
iter: &'a mut T
}
impl<'a, A, T: Iterator<A>> Iterator<A> for ByRef<'a, T> {
impl<'a, A, T: Iterator<A>+'a> Iterator<A> for ByRef<'a, T> {
#[inline]
fn next(&mut self) -> Option<A> { self.iter.next() }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
impl<'a, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'a, T> {
impl<'a, A, T: DoubleEndedIterator<A>+'a> DoubleEndedIterator<A> for ByRef<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
}

View File

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

View File

@ -369,7 +369,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
#[inline]
#[unstable = "this function may be removed in the future due to its \
questionable utility"]
pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
pub unsafe fn copy_lifetime<'a, S, T:'a>(_ptr: &'a S, ptr: &T) -> &'a T {
transmute(ptr)
}
@ -377,7 +377,7 @@ pub unsafe fn copy_lifetime<'a, S, T>(_ptr: &'a S, ptr: &T) -> &'a T {
#[inline]
#[unstable = "this function may be removed in the future due to its \
questionable utility"]
pub unsafe fn copy_mut_lifetime<'a, S, T>(_ptr: &'a mut S,
pub unsafe fn copy_mut_lifetime<'a, S, T:'a>(_ptr: &'a mut S,
ptr: &mut T) -> &'a mut T {
transmute(ptr)
}

View File

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

View File

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

View File

@ -95,7 +95,7 @@ pub struct ReprVisitor<'a> {
ptr: *const u8,
ptr_stk: Vec<*const u8>,
var_stk: Vec<VariantState>,
writer: &'a mut io::Writer,
writer: &'a mut io::Writer+'a,
last_err: Option<io::IoError>,
}

View File

@ -72,8 +72,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("fourcc", expand_syntax_ext);
}
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult> {
pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult+'cx> {
let (expr, endian) = parse_tts(cx, tts);
let little = match endian {

View File

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

View File

@ -34,6 +34,14 @@ use std::slice;
/// Some clients will have a pre-allocated vector ready to hand off in
/// a slice; others will want to create the set on the fly and hand
/// off ownership, via `Growable`.
#[cfg(not(stage0))]
pub enum MaybeOwnedVector<'a,T:'a> {
Growable(Vec<T>),
Borrowed(&'a [T]),
}
/// Stage0 only.
#[cfg(stage0)]
pub enum MaybeOwnedVector<'a,T> {
Growable(Vec<T>),
Borrowed(&'a [T]),
@ -45,7 +53,7 @@ pub trait IntoMaybeOwnedVector<'a,T> {
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T>;
}
impl<'a,T> IntoMaybeOwnedVector<'a,T> for Vec<T> {
impl<'a,T:'a> IntoMaybeOwnedVector<'a,T> for Vec<T> {
#[inline]
fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
}

View File

@ -82,7 +82,7 @@ impl Runtime for SimpleTask {
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> { None }
fn stack_bounds(&self) -> (uint, uint) { fail!() }
fn can_block(&self) -> bool { true }
fn wrap(self: Box<SimpleTask>) -> Box<Any> { fail!() }
fn wrap(self: Box<SimpleTask>) -> Box<Any+'static> { fail!() }
}
pub fn task() -> Box<Task> {

View File

@ -488,7 +488,9 @@ impl Runtime for GreenTask {
fn can_block(&self) -> bool { false }
fn wrap(self: Box<GreenTask>) -> Box<Any> { self as Box<Any> }
fn wrap(self: Box<GreenTask>) -> Box<Any+'static> {
self as Box<Any+'static>
}
}
#[cfg(test)]

View File

@ -105,7 +105,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
}
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult> {
-> Box<base::MacResult+'static> {
let (expr, ty_lit) = parse_tts(cx, tts);
let ty = match ty_lit {

View File

@ -145,8 +145,8 @@ impl rt::Runtime for Ops {
Local::put(cur_task);
}
fn wrap(self: Box<Ops>) -> Box<Any> {
self as Box<Any>
fn wrap(self: Box<Ops>) -> Box<Any+'static> {
self as Box<Any+'static>
}
fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds }

View File

@ -79,6 +79,13 @@ pub struct Weighted<T> {
pub item: T,
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct WeightedChoice<'a, T> {
items: &'a mut [Weighted<T>],
weight_range: Range<uint>
}
/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
@ -105,7 +112,8 @@ pub struct Weighted<T> {
/// println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
pub struct WeightedChoice<'a, T> {
#[cfg(not(stage0))]
pub struct WeightedChoice<'a, T:'a> {
items: &'a mut [Weighted<T>],
weight_range: Range<uint>
}

View File

@ -269,10 +269,17 @@ pub trait Rng {
}
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct Generator<'a, T, R> {
rng: &'a mut R,
}
/// Iterator which will generate a stream of random items.
///
/// This iterator is created via the `gen_iter` method on `Rng`.
pub struct Generator<'a, T, R> {
#[cfg(not(stage0))]
pub struct Generator<'a, T, R:'a> {
rng: &'a mut R,
}
@ -282,10 +289,17 @@ impl<'a, T: Rand, R: Rng> Iterator<T> for Generator<'a, T, R> {
}
}
/// Note: stage0-specific version.
#[cfg(stage0)]
pub struct AsciiGenerator<'a, R> {
rng: &'a mut R,
}
/// Iterator which will continuously generate random ascii characters.
///
/// This iterator is created via the `gen_ascii_chars` method on `Rng`.
pub struct AsciiGenerator<'a, R> {
#[cfg(not(stage0))]
pub struct AsciiGenerator<'a, R:'a> {
rng: &'a mut R,
}

View File

@ -24,7 +24,7 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![feature(macro_rules, phase, issue_5723_bootstrap)]
#![allow(missing_doc)]
extern crate serialize;
@ -662,11 +662,19 @@ pub mod writer {
pub type EncodeResult = io::IoResult<()>;
// rbml writing
#[cfg(stage0)]
pub struct Encoder<'a, W> {
pub writer: &'a mut W,
size_positions: Vec<uint>,
}
// rbml writing
#[cfg(not(stage0))]
pub struct Encoder<'a, W:'a> {
pub writer: &'a mut W,
size_positions: Vec<uint>,
}
fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
match size {
1u => w.write(&[0x80u8 | (n as u8)]),

View File

@ -77,7 +77,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
/// strategy is identical and vm.rs has comments and will be easier to follow.
#[allow(experimental)]
fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
-> Box<MacResult> {
-> Box<MacResult+'static> {
let regex = match parse(cx, tts) {
Some(r) => r,
// error is logged in 'parse' with cx.span_err

View File

@ -958,11 +958,11 @@ pub fn pretty_print_input(sess: Session,
let mut rdr = MemReader::new(src);
let out = match ofile {
None => box io::stdout() as Box<Writer>,
None => box io::stdout() as Box<Writer+'static>,
Some(p) => {
let r = io::File::create(&p);
match r {
Ok(w) => box w as Box<Writer>,
Ok(w) => box w as Box<Writer+'static>,
Err(e) => fail!("print-print failed to open {} due to {}",
p.display(), e),
}

View File

@ -74,7 +74,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
// A temporary feature gate used to enable parser extensions needed
// to bootstrap fix for #5723.
("issue_5723_bootstrap", Active),
("issue_5723_bootstrap", Accepted),
// These are used to test this portion of the compiler, they don't actually
// mean anything
@ -97,7 +97,6 @@ enum Status {
/// A set of features to be used by later passes.
pub struct Features {
pub default_type_params: Cell<bool>,
pub issue_5723_bootstrap: Cell<bool>,
pub overloaded_calls: Cell<bool>,
pub rustc_diagnostic_macros: Cell<bool>,
pub import_shadowing: Cell<bool>,
@ -107,7 +106,6 @@ impl Features {
pub fn new() -> Features {
Features {
default_type_params: Cell::new(false),
issue_5723_bootstrap: Cell::new(false),
overloaded_calls: Cell::new(false),
rustc_diagnostic_macros: Cell::new(false),
import_shadowing: Cell::new(false),
@ -310,7 +308,7 @@ impl<'a> Visitor<()> for Context<'a> {
fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
match t.node {
ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
ast::TyClosure(closure) if closure.onceness == ast::Once => {
self.gate_feature("once_fns", t.span,
"once functions are \
experimental and likely to be removed");
@ -439,7 +437,6 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
sess.abort_if_errors();
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));

View File

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

View File

@ -27,8 +27,6 @@ pub static tag_items_data_item: uint = 0x04;
pub static tag_items_data_item_family: uint = 0x05;
pub static tag_items_data_item_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;

View File

@ -18,9 +18,9 @@ use metadata::common::*;
use metadata::csearch::StaticMethodInfo;
use metadata::csearch;
use metadata::cstore;
use metadata::tydecode::{parse_ty_data, parse_def_id};
use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data};
use metadata::tydecode::{parse_trait_ref_data};
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
parse_type_param_def_data, parse_bounds_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::def;
use middle::lang_items;
use middle::resolve::TraitItemKind;
@ -242,48 +242,14 @@ fn item_trait_ref(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef {
doc_trait_ref(tp, tcx, cdata)
}
fn item_ty_param_defs(item: rbml::Doc,
tcx: &ty::ctxt,
cdata: Cmd,
tag: uint)
-> subst::VecPerParamSpace<ty::TypeParameterDef> {
let mut bounds = subst::VecPerParamSpace::empty();
reader::tagged_docs(item, tag, |p| {
let bd = parse_type_param_def_data(
p.data, p.start, cdata.cnum, tcx,
|_, did| translate_def_id(cdata, did));
bounds.push(bd.space, bd);
true
});
bounds
fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
|_, did| translate_def_id(cdata, did))
}
fn item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd)
-> subst::VecPerParamSpace<ty::RegionParameterDef>
{
let mut v = subst::VecPerParamSpace::empty();
reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
let ident_str_doc = reader::get_doc(rp_doc,
tag_region_param_def_ident);
let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
let def_id_doc = reader::get_doc(rp_doc,
tag_region_param_def_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id);
let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
let index = reader::doc_as_u64(doc) as uint;
v.push(space, ty::RegionParameterDef { name: ident.name,
def_id: def_id,
space: space,
index: index });
true
});
v
fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
let d = reader::get_doc(doc, tag_trait_def_bounds);
doc_bounds(d, tcx, cdata)
}
fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
@ -382,24 +348,11 @@ pub fn get_trait_def(cdata: Cmd,
tcx: &ty::ctxt) -> ty::TraitDef
{
let item_doc = lookup_item(item_id, cdata.data());
let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
tag_items_data_item_ty_param_bounds);
let rp_defs = item_region_param_defs(item_doc, cdata);
let mut bounds = ty::empty_builtin_bounds();
// Collect the builtin bounds from the encoded supertraits.
// FIXME(#8559): They should be encoded directly.
reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
// NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| {
bounds.add(bound);
});
true
});
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
let bounds = trait_def_bounds(item_doc, tcx, cdata);
ty::TraitDef {
generics: ty::Generics {types: tp_defs,
regions: rp_defs},
generics: generics,
bounds: bounds,
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
}
@ -413,12 +366,10 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
cdata);
let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
let rp_defs = item_region_param_defs(item, cdata);
let generics = doc_generics(item, tcx, cdata, tag_item_generics);
ty::Polytype {
generics: ty::Generics {types: tp_defs,
regions: rp_defs},
generics: generics,
ty: t
}
}
@ -794,6 +745,7 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
tcx: &ty::ctxt)
-> ty::ImplOrTraitItem {
let method_doc = lookup_item(id, cdata.data());
let def_id = item_def_id(method_doc, cdata);
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
@ -808,18 +760,13 @@ pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
match item_sort(method_doc) {
'r' | 'p' => {
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, cdata);
let generics = doc_generics(method_doc, tcx, cdata,
tag_method_ty_generics);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
let provided_source = get_provided_source(method_doc, cdata);
let generics = ty::Generics {
types: type_param_defs,
regions: rp_defs,
};
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
fty,
@ -1392,3 +1339,57 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
_ => false,
}
}
fn doc_generics(base_doc: rbml::Doc,
tcx: &ty::ctxt,
cdata: Cmd,
tag: uint)
-> ty::Generics
{
let doc = reader::get_doc(base_doc, tag);
let mut types = subst::VecPerParamSpace::empty();
reader::tagged_docs(doc, tag_type_param_def, |p| {
let bd = parse_type_param_def_data(
p.data, p.start, cdata.cnum, tcx,
|_, did| translate_def_id(cdata, did));
types.push(bd.space, bd);
true
});
let mut regions = subst::VecPerParamSpace::empty();
reader::tagged_docs(doc, tag_region_param_def, |rp_doc| {
let ident_str_doc = reader::get_doc(rp_doc,
tag_region_param_def_ident);
let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
let def_id_doc = reader::get_doc(rp_doc,
tag_region_param_def_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id);
let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
let index = reader::doc_as_u64(doc) as uint;
let mut bounds = Vec::new();
reader::tagged_docs(rp_doc, tag_items_data_region, |p| {
bounds.push(
parse_region_data(
p.data, cdata.cnum, p.start, tcx,
|_, did| translate_def_id(cdata, did)));
true
});
regions.push(space, ty::RegionParameterDef { name: ident.name,
def_id: def_id,
space: space,
index: index,
bounds: bounds });
true
});
ty::Generics { types: types, regions: regions }
}

View File

@ -19,8 +19,7 @@ use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
use metadata::tyencode;
use middle::subst::VecPerParamSpace;
use middle::ty::{node_id_to_type, lookup_item_type};
use middle::ty::{lookup_item_type};
use middle::astencode;
use middle::ty;
use middle::typeck;
@ -150,45 +149,6 @@ pub fn def_to_string(did: DefId) -> String {
format!("{}:{}", did.krate, did.node)
}
fn encode_ty_type_param_defs(rbml_w: &mut Encoder,
ecx: &EncodeContext,
params: &VecPerParamSpace<ty::TypeParameterDef>,
tag: uint) {
let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
for param in params.iter() {
rbml_w.start_tag(tag);
tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
rbml_w.end_tag();
}
}
fn encode_region_param_defs(rbml_w: &mut Encoder,
params: &VecPerParamSpace<ty::RegionParameterDef>) {
for param in params.iter() {
rbml_w.start_tag(tag_region_param_def);
rbml_w.start_tag(tag_region_param_def_ident);
encode_name(rbml_w, param.name);
rbml_w.end_tag();
rbml_w.wr_tagged_str(tag_region_param_def_def_id,
def_to_string(param.def_id).as_slice());
rbml_w.wr_tagged_u64(tag_region_param_def_space,
param.space.to_uint() as u64);
rbml_w.wr_tagged_u64(tag_region_param_def_index,
param.index as u64);
rbml_w.end_tag();
}
}
fn encode_item_variances(rbml_w: &mut Encoder,
ecx: &EncodeContext,
id: ast::NodeId) {
@ -201,9 +161,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
fn encode_bounds_and_type(rbml_w: &mut Encoder,
ecx: &EncodeContext,
pty: &ty::Polytype) {
encode_ty_type_param_defs(rbml_w, ecx, &pty.generics.types,
tag_items_data_item_ty_param_bounds);
encode_region_param_defs(rbml_w, &pty.generics.regions);
encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
encode_type(ecx, rbml_w, pty.ty);
}
@ -238,6 +196,33 @@ pub fn write_type(ecx: &EncodeContext,
tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ);
}
pub fn write_region(ecx: &EncodeContext,
rbml_w: &mut Encoder,
r: ty::Region) {
let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
tyencode::enc_region(rbml_w.writer, ty_str_ctxt, r);
}
fn encode_bounds(rbml_w: &mut Encoder,
ecx: &EncodeContext,
bounds: &ty::ParamBounds,
tag: uint) {
rbml_w.start_tag(tag);
let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs };
tyencode::enc_bounds(rbml_w.writer, ty_str_ctxt, bounds);
rbml_w.end_tag();
}
fn encode_type(ecx: &EncodeContext,
rbml_w: &mut Encoder,
typ: ty::t) {
@ -246,6 +231,14 @@ fn encode_type(ecx: &EncodeContext,
rbml_w.end_tag();
}
fn encode_region(ecx: &EncodeContext,
rbml_w: &mut Encoder,
r: ty::Region) {
rbml_w.start_tag(tag_items_data_region);
write_region(ecx, rbml_w, r);
rbml_w.end_tag();
}
fn encode_method_fty(ecx: &EncodeContext,
rbml_w: &mut Encoder,
typ: &ty::BareFnTy) {
@ -728,7 +721,6 @@ fn encode_info_for_struct(ecx: &EncodeContext,
/* Each class has its own index, since different classes
may have fields with the same name */
let mut index = Vec::new();
let tcx = ecx.tcx;
/* We encode both private and public fields -- need to include
private fields to get the offsets right */
for field in fields.iter() {
@ -745,7 +737,8 @@ fn encode_info_for_struct(ecx: &EncodeContext,
token::get_name(nm), id);
encode_struct_field_family(rbml_w, field.vis);
encode_name(rbml_w, nm);
encode_type(ecx, rbml_w, node_id_to_type(tcx, id));
encode_bounds_and_type(rbml_w, ecx,
&lookup_item_type(ecx.tcx, local_def(id)));
encode_def_id(rbml_w, local_def(id));
let stab = stability::lookup(ecx.tcx, field.id);
@ -773,7 +766,6 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
encode_bounds_and_type(rbml_w, ecx,
&lookup_item_type(ecx.tcx, local_def(ctor_id)));
encode_name(rbml_w, name.name);
encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, ctor_id));
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
encode_parent_item(rbml_w, local_def(struct_id));
@ -793,13 +785,60 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
rbml_w.end_tag();
}
fn encode_generics(rbml_w: &mut Encoder,
ecx: &EncodeContext,
generics: &ty::Generics,
tag: uint)
{
rbml_w.start_tag(tag);
// Type parameters
let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
for param in generics.types.iter() {
rbml_w.start_tag(tag_type_param_def);
tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
rbml_w.end_tag();
}
// Region parameters
for param in generics.regions.iter() {
rbml_w.start_tag(tag_region_param_def);
rbml_w.start_tag(tag_region_param_def_ident);
encode_name(rbml_w, param.name);
rbml_w.end_tag();
rbml_w.wr_tagged_str(tag_region_param_def_def_id,
def_to_string(param.def_id).as_slice());
rbml_w.wr_tagged_u64(tag_region_param_def_space,
param.space.to_uint() as u64);
rbml_w.wr_tagged_u64(tag_region_param_def_index,
param.index as u64);
for &bound_region in param.bounds.iter() {
encode_region(ecx, rbml_w, bound_region);
}
rbml_w.end_tag();
}
rbml_w.end_tag();
}
fn encode_method_ty_fields(ecx: &EncodeContext,
rbml_w: &mut Encoder,
method_ty: &ty::Method) {
encode_def_id(rbml_w, method_ty.def_id);
encode_name(rbml_w, method_ty.ident.name);
encode_ty_type_param_defs(rbml_w, ecx, &method_ty.generics.types,
tag_item_method_tps);
encode_generics(rbml_w, ecx, &method_ty.generics,
tag_method_ty_generics);
encode_method_fty(ecx, rbml_w, &method_ty.fty);
encode_visibility(rbml_w, method_ty.vis);
encode_explicit_self(rbml_w, &method_ty.explicit_self);
@ -982,7 +1021,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
} else {
encode_family(rbml_w, 'c');
}
encode_type(ecx, rbml_w, node_id_to_type(tcx, item.id));
encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
encode_symbol(ecx, rbml_w, item.id);
encode_name(rbml_w, item.ident.name);
encode_path(rbml_w, path);
@ -1222,17 +1261,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
}
}
ItemTrait(_, _, ref super_traits, ref ms) => {
ItemTrait(_, _, _, ref ms) => {
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
encode_def_id(rbml_w, def_id);
encode_family(rbml_w, 'I');
encode_item_variances(rbml_w, ecx, item.id);
let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_ty_type_param_defs(rbml_w, ecx,
&trait_def.generics.types,
tag_items_data_item_ty_param_bounds);
encode_region_param_defs(rbml_w, &trait_def.generics.regions);
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
encode_name(rbml_w, item.ident.name);
encode_attributes(rbml_w, item.attrs.as_slice());
@ -1253,13 +1289,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
rbml_w.end_tag();
}
encode_path(rbml_w, path.clone());
// FIXME(#8559): This should use the tcx's supertrait cache instead of
// reading the AST's list, because the former has already filtered out
// the builtin-kinds-as-supertraits. See corresponding fixme in decoder.
for ast_trait_ref in super_traits.iter() {
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_super_trait_ref);
}
encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
// Encode the implementations of this trait.
encode_extension_implementations(ecx, rbml_w, def_id);
@ -1390,7 +1421,8 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
} else {
encode_family(rbml_w, 'c');
}
encode_type(ecx, rbml_w, node_id_to_type(ecx.tcx, nitem.id));
encode_bounds_and_type(rbml_w, ecx,
&lookup_item_type(ecx.tcx,local_def(nitem.id)));
encode_symbol(ecx, rbml_w, nitem.id);
encode_name(rbml_w, nitem.ident.name);
}
@ -1434,7 +1466,7 @@ fn my_visit_foreign_item(ni: &ForeignItem,
});
}
struct EncodeVisitor<'a,'b> {
struct EncodeVisitor<'a,'b:'a> {
rbml_w_for_visit_item: &'a mut Encoder<'b>,
ecx_ptr:*const int,
index: &'a mut Vec<entry<i64>>,
@ -1738,7 +1770,7 @@ fn encode_unboxed_closures<'a>(
}
fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
struct StructFieldVisitor<'a, 'b> {
struct StructFieldVisitor<'a, 'b:'a> {
rbml_w: &'a mut Encoder<'b>,
}
@ -1760,7 +1792,7 @@ fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &Crate) {
struct ImplVisitor<'a,'b,'c> {
struct ImplVisitor<'a,'b:'a,'c:'a> {
ecx: &'a EncodeContext<'b>,
rbml_w: &'a mut Encoder<'c>,
}

View File

@ -147,6 +147,13 @@ pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty:
parse_ty(&mut st, conv)
}
pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::Region {
debug!("parse_region_data {}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_region(&mut st, conv)
}
pub fn parse_bare_fn_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::BareFnTy {
debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos));
@ -168,6 +175,27 @@ pub fn parse_substs_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx:
parse_substs(&mut st, conv)
}
pub fn parse_bounds_data(data: &[u8], crate_num: ast::CrateNum,
pos: uint, tcx: &ty::ctxt, conv: conv_did)
-> ty::ParamBounds {
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_bounds(&mut st, conv)
}
pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum,
pos: uint, tcx: &ty::ctxt, conv: conv_did)
-> ty::ExistentialBounds {
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_existential_bounds(&mut st, conv)
}
pub fn parse_builtin_bounds_data(data: &[u8], crate_num: ast::CrateNum,
pos: uint, tcx: &ty::ctxt, conv: conv_did)
-> ty::BuiltinBounds {
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_builtin_bounds(&mut st, conv)
}
fn parse_size(st: &mut PState) -> Option<uint> {
assert_eq!(next(st), '/');
@ -355,9 +383,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
assert_eq!(next(st), '[');
let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
let bounds = parse_bounds(st, |x,y| conv(x,y));
let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
return ty::mk_trait(st.tcx, def, substs, bounds.builtin_bounds);
return ty::mk_trait(st.tcx, def, substs, bounds);
}
'p' => {
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
@ -515,14 +543,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
let fn_style = parse_fn_style(next(st));
let onceness = parse_onceness(next(st));
let store = parse_trait_store(st, |x,y| conv(x,y));
let bounds = parse_bounds(st, |x,y| conv(x,y));
let bounds = parse_existential_bounds(st, |x,y| conv(x,y));
let sig = parse_sig(st, |x,y| conv(x,y));
let abi = parse_abi_set(st);
ty::ClosureTy {
fn_style: fn_style,
onceness: onceness,
store: store,
bounds: bounds.builtin_bounds,
bounds: bounds,
sig: sig,
abi: abi,
}
@ -601,7 +629,7 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
assert_eq!(next(st), '|');
let index = parse_uint(st);
assert_eq!(next(st), '|');
let bounds = Rc::new(parse_bounds(st, |x,y| conv(x,y)));
let bounds = parse_bounds(st, |x,y| conv(x,y));
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
ty::TypeParameterDef {
@ -614,27 +642,51 @@ fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef
}
}
fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds {
let r = parse_region(st, |x,y| conv(x,y));
let bb = parse_builtin_bounds(st, conv);
return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb };
}
fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds {
let mut builtin_bounds = ty::empty_builtin_bounds();
loop {
match next(st) {
'S' => {
builtin_bounds.add(ty::BoundSend);
}
'Z' => {
builtin_bounds.add(ty::BoundSized);
}
'P' => {
builtin_bounds.add(ty::BoundCopy);
}
'T' => {
builtin_bounds.add(ty::BoundSync);
}
'.' => {
return builtin_bounds;
}
c => {
fail!("parse_bounds: bad builtin bounds ('{}')", c)
}
}
}
}
fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));
let mut param_bounds = ty::ParamBounds {
builtin_bounds: ty::empty_builtin_bounds(),
opt_region_bound: None,
builtin_bounds: builtin_bounds,
trait_bounds: Vec::new()
};
loop {
match next(st) {
'S' => {
param_bounds.builtin_bounds.add(ty::BoundSend);
}
'O' => {
param_bounds.builtin_bounds.add(ty::BoundStatic);
}
'Z' => {
param_bounds.builtin_bounds.add(ty::BoundSized);
}
'P' => {
param_bounds.builtin_bounds.add(ty::BoundCopy);
}
'T' => {
param_bounds.builtin_bounds.add(ty::BoundSync);
'R' => {
param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
}
'I' => {
param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));

View File

@ -127,7 +127,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
}
}
fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
match r {
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));
}

View File

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

View File

@ -79,12 +79,14 @@ impl<'a> CFGBuilder<'a> {
fn stmt(&mut self, stmt: Gc<ast::Stmt>, pred: CFGIndex) -> CFGIndex {
match stmt.node {
ast::StmtDecl(ref decl, _) => {
self.decl(&**decl, pred)
ast::StmtDecl(ref decl, id) => {
let exit = self.decl(&**decl, pred);
self.add_node(id, [exit])
}
ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => {
self.expr(expr.clone(), pred)
ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
let exit = self.expr(expr.clone(), pred);
self.add_node(id, [exit])
}
ast::StmtMac(..) => {

View File

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

View File

@ -80,11 +80,18 @@ pub trait DataFlowOperator : BitwiseOperator {
fn initial_value(&self) -> bool;
}
#[cfg(stage0)]
struct PropagationContext<'a, 'b, O> {
dfcx: &'a mut DataFlowContext<'b, O>,
changed: bool
}
#[cfg(not(stage0))]
struct PropagationContext<'a, 'b:'a, O:'a> {
dfcx: &'a mut DataFlowContext<'b, O>,
changed: bool
}
fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
let opt_cfgindex = index.find(&id).map(|&i|i);
opt_cfgindex.unwrap_or_else(|| {
@ -458,7 +465,7 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> {
});
}
fn pretty_print_to(&self, wr: Box<io::Writer>,
fn pretty_print_to(&self, wr: Box<io::Writer+'static>,
blk: &ast::Block) -> io::IoResult<()> {
let mut ps = pprust::rust_printer_annotated(wr, self);
try!(ps.cbox(pprust::indent_unit));

View File

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

View File

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

View File

@ -144,14 +144,17 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
// If this trait has builtin-kind supertraits, meet them.
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
debug!("checking impl with self type {}", ty::get(self_ty).sty);
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
span_err!(cx.tcx.sess, self_type.span, E0142,
"the type `{}', which does not fulfill `{}`, cannot implement this trait",
ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
span_note!(cx.tcx.sess, self_type.span,
"types implementing this trait must fulfill `{}`",
trait_def.bounds.user_string(cx.tcx));
});
check_builtin_bounds(
cx, self_ty, trait_def.bounds.builtin_bounds,
|missing| {
span_err!(cx.tcx.sess, self_type.span, E0142,
"the type `{}', which does not fulfill `{}`, \
cannot implement this trait",
ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
span_note!(cx.tcx.sess, self_type.span,
"types implementing this trait must fulfill `{}`",
trait_def.bounds.user_string(cx.tcx));
});
// If this is a destructor, check kinds.
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
@ -297,17 +300,15 @@ fn with_appropriate_checker(cx: &Context,
match ty::get(fty).sty {
ty::ty_closure(box ty::ClosureTy {
store: ty::UniqTraitStore,
bounds: mut bounds, ..
bounds: bounds,
..
}) => {
// Procs can't close over non-static references!
bounds.add(ty::BoundStatic);
b(|cx, fv| check_for_uniq(cx, fv, bounds))
b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds))
}
ty::ty_closure(box ty::ClosureTy {
store: ty::RegionTraitStore(region, _), bounds, ..
}) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
}) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)),
ty::ty_bare_fn(_) => {
b(check_for_bare)
@ -377,13 +378,6 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
expression_type);
match e.node {
ExprBox(ref loc, ref interior) => {
let def = ty::resolve_expr(cx.tcx, &**loc);
if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
let interior_type = ty::expr_ty(cx.tcx, &**interior);
let _ = check_static(cx.tcx, interior_type, interior.span);
}
}
ExprCast(ref source, _) => {
let source_ty = ty::expr_ty(cx.tcx, &**source);
let target_ty = ty::expr_ty(cx.tcx, e);
@ -562,7 +556,6 @@ fn check_trait_cast(cx: &mut Context,
target_ty: ty::t,
span: Span,
method_call: MethodCall) {
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
match ty::get(target_ty).sty {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
match ty::get(ty).sty {
@ -580,7 +573,8 @@ fn check_trait_cast(cx: &mut Context,
vtable_res)
}
};
check_trait_cast_bounds(cx, span, source_ty, bounds);
check_trait_cast_bounds(cx, span, source_ty,
bounds.builtin_bounds);
}
_ => {}
}
@ -620,7 +614,7 @@ pub fn check_builtin_bounds(cx: &Context,
let kind = ty::type_contents(cx.tcx, ty);
let mut missing = ty::empty_builtin_bounds();
for bound in bounds.iter() {
if !kind.meets_bound(cx.tcx, bound) {
if !kind.meets_builtin_bound(cx.tcx, bound) {
missing.add(bound);
}
}
@ -764,132 +758,6 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
}
}
pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
if !ty::type_is_static(tcx, ty) {
match ty::get(ty).sty {
ty::ty_param(..) => {
span_err!(tcx.sess, sp, E0149,
"value may contain references; \
add `'static` bound to `{}`",
ty_to_string(tcx, ty));
}
_ => {
span_err!(tcx.sess, sp, E0150,
"value may contain references");
}
}
false
} else {
true
}
}
/// This is rather subtle. When we are casting a value to an instantiated
/// trait like `a as trait<'r>`, regionck already ensures that any references
/// that appear in the type of `a` are bounded by `'r` (ed.: rem
/// FIXME(#5723)). However, it is possible that there are *type parameters*
/// in the type of `a`, and those *type parameters* may have references
/// within them. We have to guarantee that the regions which appear in those
/// type parameters are not obscured.
///
/// Therefore, we ensure that one of three conditions holds:
///
/// (1) The trait instance cannot escape the current fn. This is
/// guaranteed if the region bound `&r` is some scope within the fn
/// itself. This case is safe because whatever references are
/// found within the type parameter, they must enclose the fn body
/// itself.
///
/// (2) The type parameter appears in the type of the trait. For
/// example, if the type parameter is `T` and the trait type is
/// `deque<T>`, then whatever references may appear in `T` also
/// appear in `deque<T>`.
///
/// (3) The type parameter is sendable (and therefore does not contain
/// references).
///
/// FIXME(#5723)---This code should probably move into regionck.
pub fn check_cast_for_escaping_regions(
cx: &Context,
source_ty: ty::t,
target_ty: ty::t,
source_span: Span)
{
// Determine what type we are casting to; if it is not a trait, then no
// worries.
if !ty::type_is_trait(target_ty) {
return;
}
// Collect up the regions that appear in the target type. We want to
// ensure that these lifetimes are shorter than all lifetimes that are in
// the source type. See test `src/test/compile-fail/regions-trait-2.rs`
let mut target_regions = Vec::new();
ty::walk_regions_and_ty(
cx.tcx,
target_ty,
|r| {
if !r.is_bound() {
target_regions.push(r);
}
},
|_| ());
// Check, based on the region associated with the trait, whether it can
// possibly escape the enclosing fn item (note that all type parameters
// must have been declared on the enclosing fn item).
if target_regions.iter().any(|r| is_ReScope(*r)) {
return; /* case (1) */
}
// Assuming the trait instance can escape, then ensure that each parameter
// either appears in the trait type or is sendable.
let target_params = ty::param_tys_in_type(target_ty);
ty::walk_regions_and_ty(
cx.tcx,
source_ty,
|_r| {
// FIXME(#5723) --- turn this check on once &Objects are usable
//
// if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
// cx.tcx.sess.span_err(
// source_span,
// format!("source contains reference with lifetime \
// not found in the target type `{}`",
// ty_to_string(cx.tcx, target_ty)));
// note_and_explain_region(
// cx.tcx, "source data is only valid for ", r, "");
// }
},
|ty| {
match ty::get(ty).sty {
ty::ty_param(source_param) => {
if source_param.space == subst::SelfSpace {
// FIXME (#5723) -- there is no reason that
// Self should be exempt from this check,
// except for historical accident. Bottom
// line, we need proper region bounding.
} else if target_params.iter().any(|x| x == &source_param) {
/* case (2) */
} else {
check_static(cx.tcx, ty, source_span); /* case (3) */
}
}
_ => {}
}
});
#[allow(non_snake_case_functions)]
fn is_ReScope(r: ty::Region) -> bool {
match r {
ty::ReScope(..) => true,
_ => false
}
}
}
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
if !ty::type_is_sized(tcx, ty) {

View File

@ -240,10 +240,16 @@ impl ast_node for ast::Pat {
fn span(&self) -> Span { self.span }
}
#[cfg(stage0)]
pub struct MemCategorizationContext<'t,TYPER> {
typer: &'t TYPER
}
#[cfg(not(stage0))]
pub struct MemCategorizationContext<'t,TYPER:'t> {
typer: &'t TYPER
}
pub type McResult<T> = Result<T, ()>;
/**

View File

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

View File

@ -25,6 +25,7 @@ use driver::session::Session;
use middle::ty::{FreeRegion};
use middle::ty;
use util::nodemap::NodeMap;
use util::common::can_reach;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
@ -78,7 +79,7 @@ The region maps encode information about region relationships.
pub struct RegionMaps {
scope_map: RefCell<NodeMap<ast::NodeId>>,
var_map: RefCell<NodeMap<ast::NodeId>>,
free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion> >>,
free_region_map: RefCell<HashMap<FreeRegion, Vec<FreeRegion>>>,
rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
terminating_scopes: RefCell<HashSet<ast::NodeId>>,
}
@ -255,34 +256,7 @@ impl RegionMaps {
* (that is, the user can give two different names to the same lifetime).
*/
if sub == sup {
return true;
}
// Do a little breadth-first-search here. The `queue` list
// doubles as a way to detect if we've seen a particular FR
// before. Note that we expect this graph to be an *extremely
// shallow* tree.
let mut queue = vec!(sub);
let mut i = 0;
while i < queue.len() {
match self.free_region_map.borrow().find(queue.get(i)) {
Some(parents) => {
for parent in parents.iter() {
if *parent == sup {
return true;
}
if !queue.iter().any(|x| x == parent) {
queue.push(*parent);
}
}
}
None => {}
}
i += 1;
}
return false;
can_reach(&*self.free_region_map.borrow(), sub, sup)
}
pub fn is_subregion_of(&self,
@ -300,6 +274,7 @@ impl RegionMaps {
sub_region == super_region || {
match (sub_region, super_region) {
(ty::ReEmpty, _) |
(_, ty::ReStatic) => {
true
}

View File

@ -30,10 +30,10 @@ use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, Method};
use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
use syntax::ast::{OtherRegionTyParamBound, P, Pat, PatEnum, PatIdent, PatLit};
use syntax::ast::{P, Pat, PatEnum, PatIdent, PatLit};
use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic};
use syntax::ast::{StaticRegionTyParamBound, StmtDecl, StructField};
use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
@ -901,7 +901,7 @@ struct Resolver<'a> {
used_imports: HashSet<(NodeId, Namespace)>,
}
struct BuildReducedGraphVisitor<'a, 'b> {
struct BuildReducedGraphVisitor<'a, 'b:'a> {
resolver: &'a mut Resolver<'b>,
}
@ -933,7 +933,9 @@ impl<'a, 'b> Visitor<ReducedGraphParent> for BuildReducedGraphVisitor<'a, 'b> {
}
struct UnusedImportCheckVisitor<'a, 'b> { resolver: &'a mut Resolver<'b> }
struct UnusedImportCheckVisitor<'a, 'b:'a> {
resolver: &'a mut Resolver<'b>
}
impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> {
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@ -3946,7 +3948,7 @@ impl<'a> Resolver<'a> {
impl_items.as_slice());
}
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
// Create a new rib for the self type.
let self_type_rib = Rib::new(ItemRibKind);
@ -3965,10 +3967,9 @@ impl<'a> Resolver<'a> {
this.resolve_type_parameters(&generics.ty_params);
this.resolve_where_clause(&generics.where_clause);
// Resolve derived traits.
for trt in traits.iter() {
this.resolve_trait_reference(item.id, trt, TraitDerivation);
}
this.resolve_type_parameter_bounds(item.id, bounds,
TraitDerivation);
match unbound {
&Some(ast::TraitTyParamBound(ref tpb)) => {
this.resolve_trait_reference(item.id, tpb, TraitDerivation);
@ -4199,10 +4200,13 @@ impl<'a> Resolver<'a> {
type_parameters: &OwnedSlice<TyParam>) {
for type_parameter in type_parameters.iter() {
for bound in type_parameter.bounds.iter() {
self.resolve_type_parameter_bound(type_parameter.id, bound);
self.resolve_type_parameter_bound(type_parameter.id, bound,
TraitBoundingTypeParameter);
}
match &type_parameter.unbound {
&Some(ref unbound) => self.resolve_type_parameter_bound(type_parameter.id, unbound),
&Some(ref unbound) =>
self.resolve_type_parameter_bound(
type_parameter.id, unbound, TraitBoundingTypeParameter),
&None => {}
}
match type_parameter.default {
@ -4212,12 +4216,23 @@ impl<'a> Resolver<'a> {
}
}
fn resolve_type_parameter_bounds(&mut self,
id: NodeId,
type_parameter_bounds: &OwnedSlice<TyParamBound>,
reference_type: TraitReferenceType) {
for type_parameter_bound in type_parameter_bounds.iter() {
self.resolve_type_parameter_bound(id, type_parameter_bound,
reference_type);
}
}
fn resolve_type_parameter_bound(&mut self,
id: NodeId,
type_parameter_bound: &TyParamBound) {
type_parameter_bound: &TyParamBound,
reference_type: TraitReferenceType) {
match *type_parameter_bound {
TraitTyParamBound(ref tref) => {
self.resolve_trait_reference(id, tref, TraitBoundingTypeParameter)
self.resolve_trait_reference(id, tref, reference_type)
}
UnboxedFnTyParamBound(ref unboxed_function) => {
for argument in unboxed_function.decl.inputs.iter() {
@ -4226,7 +4241,7 @@ impl<'a> Resolver<'a> {
self.resolve_type(&*unboxed_function.decl.output);
}
StaticRegionTyParamBound | OtherRegionTyParamBound(_) => {}
RegionTyParamBound(..) => {}
}
}
@ -4240,7 +4255,7 @@ impl<'a> Resolver<'a> {
let usage_str = match reference_type {
TraitBoundingTypeParameter => "bound type parameter with",
TraitImplementation => "implement",
TraitDerivation => "derive"
TraitDerivation => "derive",
};
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@ -4295,7 +4310,8 @@ impl<'a> Resolver<'a> {
}
for bound in predicate.bounds.iter() {
self.resolve_type_parameter_bound(predicate.id, bound);
self.resolve_type_parameter_bound(predicate.id, bound,
TraitBoundingTypeParameter);
}
}
}
@ -4679,18 +4695,14 @@ impl<'a> Resolver<'a> {
}
bounds.as_ref().map(|bound_vec| {
for bound in bound_vec.iter() {
self.resolve_type_parameter_bound(ty.id, bound);
}
self.resolve_type_parameter_bounds(ty.id, bound_vec,
TraitBoundingTypeParameter);
});
}
TyClosure(c, _) | TyProc(c) => {
c.bounds.as_ref().map(|bounds| {
for bound in bounds.iter() {
self.resolve_type_parameter_bound(ty.id, bound);
}
});
TyClosure(c) | TyProc(c) => {
self.resolve_type_parameter_bounds(ty.id, &c.bounds,
TraitBoundingTypeParameter);
visit::walk_ty(self, ty, ());
}

View File

@ -21,7 +21,6 @@ use driver::session::Session;
use middle::subst;
use syntax::ast;
use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::special_idents;
use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_string};
@ -99,8 +98,10 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
ast::ItemStruct(_, ref generics) |
ast::ItemImpl(ref generics, _, _, _) |
ast::ItemTrait(ref generics, _, _, _) => {
self.check_lifetime_names(&generics.lifetimes);
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root)
let scope: ScopeChain =
EarlyScope(subst::TypeSpace, &generics.lifetimes, &root);
self.check_lifetime_defs(&generics.lifetimes, &scope);
scope
}
};
debug!("entering scope {:?}", scope);
@ -126,7 +127,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
fn visit_ty(&mut self, ty: &ast::Ty, scope: Scope<'a>) {
match ty.node {
ast::TyClosure(c, _) | ast::TyProc(c) => {
ast::TyClosure(c) | ast::TyProc(c) => {
push_fn_scope(self, ty, scope, &c.lifetimes);
}
ast::TyBareFn(c) => push_fn_scope(self, ty, scope, &c.lifetimes),
@ -137,8 +138,8 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
ty: &ast::Ty,
scope: Scope,
lifetimes: &Vec<ast::LifetimeDef>) {
let scope1 = LateScope(ty.id, lifetimes, scope);
this.check_lifetime_names(lifetimes);
let scope1: ScopeChain = LateScope(ty.id, lifetimes, scope);
this.check_lifetime_defs(lifetimes, &scope1);
debug!("pushing fn scope id={} due to type", ty.id);
visit::walk_ty(this, ty, &scope1);
debug!("popping fn scope id={} due to type", ty.id);
@ -204,24 +205,22 @@ impl<'a> LifetimeContext<'a> {
* the ordering is not important there.
*/
self.check_lifetime_names(&generics.lifetimes);
let referenced_idents = free_lifetimes(&generics.ty_params,
&generics.where_clause);
let referenced_idents = early_bound_lifetime_names(generics);
debug!("pushing fn scope id={} due to fn item/method\
referenced_idents={:?}",
n,
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
if referenced_idents.is_empty() {
let scope1 = LateScope(n, &generics.lifetimes, scope);
walk(self, &scope1)
let scope1: ScopeChain = LateScope(n, &generics.lifetimes, scope);
self.check_lifetime_defs(&generics.lifetimes, &scope1);
walk(self, &scope1);
} else {
let (early, late) = generics.lifetimes.clone().partition(
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
let scope1 = EarlyScope(subst::FnSpace, &early, scope);
let scope2 = LateScope(n, &late, &scope1);
let scope2: ScopeChain = LateScope(n, &late, &scope1);
self.check_lifetime_defs(&generics.lifetimes, &scope2);
walk(self, &scope2);
}
debug!("popping fn scope id={} due to fn item/method", n);
@ -335,7 +334,9 @@ impl<'a> LifetimeContext<'a> {
token::get_name(lifetime_ref.name)).as_slice());
}
fn check_lifetime_names(&self, lifetimes: &Vec<ast::LifetimeDef>) {
fn check_lifetime_defs<'b>(&mut self,
lifetimes: &Vec<ast::LifetimeDef>,
scope: Scope<'b>) {
for i in range(0, lifetimes.len()) {
let lifetime_i = lifetimes.get(i);
@ -364,11 +365,7 @@ impl<'a> LifetimeContext<'a> {
}
for bound in lifetime_i.bounds.iter() {
if !self.sess.features.issue_5723_bootstrap.get() {
self.sess.span_err(
bound.span,
"region bounds require `issue_5723_bootstrap`");
}
self.resolve_lifetime_ref(bound, scope);
}
}
}
@ -404,8 +401,7 @@ fn search_lifetimes(lifetimes: &Vec<ast::LifetimeDef>,
///////////////////////////////////////////////////////////////////////////
pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::LifetimeDef> {
let referenced_idents = free_lifetimes(&generics.ty_params,
&generics.where_clause);
let referenced_idents = early_bound_lifetime_names(generics);
if referenced_idents.is_empty() {
return Vec::new();
}
@ -416,34 +412,72 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::Lifeti
.collect()
}
pub fn free_lifetimes(ty_params: &OwnedSlice<ast::TyParam>,
where_clause: &ast::WhereClause)
-> Vec<ast::Name> {
fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
/*!
* Gathers up and returns the names of any lifetimes that appear
* free in `ty_params`. Of course, right now, all lifetimes appear
* free, since we don't currently have any binders in type parameter
* declarations; just being forwards compatible with future extensions.
* Given a set of generic declarations, returns a list of names
* containing all early bound lifetime names for those
* generics. (In fact, this list may also contain other names.)
*/
let mut collector = FreeLifetimeCollector { names: vec!() };
for ty_param in ty_params.iter() {
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
}
for predicate in where_clause.predicates.iter() {
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
}
return collector.names;
// Create two lists, dividing the lifetimes into early/late bound.
// Initially, all of them are considered late, but we will move
// things from late into early as we go if we find references to
// them.
let mut early_bound = Vec::new();
let mut late_bound = generics.lifetimes.iter()
.map(|l| l.lifetime.name)
.collect();
struct FreeLifetimeCollector {
names: Vec<ast::Name>,
// Any lifetime that appears in a type bound is early.
{
let mut collector =
FreeLifetimeCollector { early_bound: &mut early_bound,
late_bound: &mut late_bound };
for ty_param in generics.ty_params.iter() {
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds, ());
}
for predicate in generics.where_clause.predicates.iter() {
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
}
}
impl Visitor<()> for FreeLifetimeCollector {
// Any lifetime that either has a bound or is referenced by a
// bound is early.
for lifetime_def in generics.lifetimes.iter() {
if !lifetime_def.bounds.is_empty() {
shuffle(&mut early_bound, &mut late_bound,
lifetime_def.lifetime.name);
for bound in lifetime_def.bounds.iter() {
shuffle(&mut early_bound, &mut late_bound,
bound.name);
}
}
}
return early_bound;
struct FreeLifetimeCollector<'a> {
early_bound: &'a mut Vec<ast::Name>,
late_bound: &'a mut Vec<ast::Name>,
}
impl<'a> Visitor<()> for FreeLifetimeCollector<'a> {
fn visit_lifetime_ref(&mut self,
lifetime_ref: &ast::Lifetime,
_: ()) {
self.names.push(lifetime_ref.name);
shuffle(self.early_bound, self.late_bound,
lifetime_ref.name);
}
}
fn shuffle(early_bound: &mut Vec<ast::Name>,
late_bound: &mut Vec<ast::Name>,
name: ast::Name) {
match late_bound.iter().position(|n| *n == name) {
Some(index) => {
late_bound.swap_remove(index);
early_bound.push(name);
}
None => { }
}
}
}

View File

@ -50,6 +50,7 @@ use syntax::attr;
use syntax::codemap::*;
use syntax::parse::token;
use syntax::parse::token::{get_ident,keywords};
use syntax::owned_slice::OwnedSlice;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::print::pprust::{path_to_string,ty_to_string};
@ -653,7 +654,7 @@ impl <'l> DxrVisitor<'l> {
item: &ast::Item,
e: DxrVisitorEnv,
generics: &ast::Generics,
trait_refs: &Vec<ast::TraitRef>,
trait_refs: &OwnedSlice<ast::TyParamBound>,
methods: &Vec<ast::TraitItem>) {
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
@ -665,7 +666,16 @@ impl <'l> DxrVisitor<'l> {
e.cur_scope);
// super-traits
for trait_ref in trait_refs.iter() {
for super_bound in trait_refs.iter() {
let trait_ref = match *super_bound {
ast::TraitTyParamBound(ref trait_ref) => {
trait_ref
}
ast::UnboxedFnTyParamBound(..) | ast::RegionTyParamBound(..) => {
continue;
}
};
match self.lookup_type_ref(trait_ref.ref_id) {
Some(id) => {
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
@ -1499,7 +1509,7 @@ pub fn process_crate(sess: &Session,
collected_paths: vec!(),
collecting: false,
fmt: FmtStrs::new(box Recorder {
out: output_file as Box<Writer>,
out: output_file as Box<Writer+'static>,
dump_spans: false,
},
SpanUtils {

View File

@ -19,7 +19,7 @@ use syntax::codemap::*;
pub struct Recorder {
// output file
pub out: Box<Writer>,
pub out: Box<Writer+'static>,
pub dump_spans: bool,
}

View File

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

View File

@ -340,6 +340,15 @@ struct ArmData<'a, 'b> {
* As we proceed `bound_ptrs` are filled with pointers to values to be bound,
* these pointers are stored in llmatch variables just before executing `data` arm.
*/
#[cfg(not(stage0))]
struct Match<'a, 'b:'a> {
pats: Vec<Gc<ast::Pat>>,
data: &'a ArmData<'a, 'b>,
bound_ptrs: Vec<(Ident, ValueRef)>
}
///Dox
#[cfg(stage0)]
struct Match<'a, 'b> {
pats: Vec<Gc<ast::Pat>>,
data: &'a ArmData<'a, 'b>,

View File

@ -25,7 +25,6 @@ use middle::ty;
use syntax::ast;
use util::ppaux::Repr;
pub struct CleanupScope<'a> {
// The id of this cleanup scope. If the id is None,
// this is a *temporary scope* that is pushed during trans to
@ -35,7 +34,7 @@ pub struct CleanupScope<'a> {
kind: CleanupScopeKind<'a>,
// Cleanups to run upon scope exit.
cleanups: Vec<Box<Cleanup>>,
cleanups: Vec<CleanupObj>,
cached_early_exits: Vec<CachedEarlyExit>,
cached_landing_pad: Option<BasicBlockRef>,
@ -73,6 +72,8 @@ pub trait Cleanup {
fn trans<'a>(&self, bcx: &'a Block<'a>) -> &'a Block<'a>;
}
pub type CleanupObj = Box<Cleanup+'static>;
pub enum ScopeId {
AstScope(ast::NodeId),
CustomScope(CustomScopeIndex)
@ -238,7 +239,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
cleanup_scope,
self.ccx.tn.val_to_string(val));
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
fn schedule_drop_mem(&self,
@ -264,7 +265,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
self.ccx.tn.val_to_string(val),
ty.repr(self.ccx.tcx()));
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
fn schedule_drop_and_zero_mem(&self,
@ -291,7 +292,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
ty.repr(self.ccx.tcx()),
true);
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
fn schedule_drop_immediate(&self,
@ -316,7 +317,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
self.ccx.tn.val_to_string(val),
ty.repr(self.ccx.tcx()));
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
fn schedule_free_value(&self,
@ -336,12 +337,12 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
self.ccx.tn.val_to_string(val),
heap);
self.schedule_clean(cleanup_scope, drop as Box<Cleanup>);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
fn schedule_clean(&self,
cleanup_scope: ScopeId,
cleanup: Box<Cleanup>) {
cleanup: CleanupObj) {
match cleanup_scope {
AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup),
@ -350,7 +351,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
fn schedule_clean_in_ast_scope(&self,
cleanup_scope: ast::NodeId,
cleanup: Box<Cleanup>) {
cleanup: CleanupObj) {
/*!
* Schedules a cleanup to occur upon exit from `cleanup_scope`.
* If `cleanup_scope` is not provided, then the cleanup is scheduled
@ -378,7 +379,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
fn schedule_clean_in_custom_scope(&self,
custom_scope: CustomScopeIndex,
cleanup: Box<Cleanup>) {
cleanup: CleanupObj) {
/*!
* Schedules a cleanup to occur in the top-most scope,
* which must be a temporary scope.
@ -1021,13 +1022,13 @@ pub trait CleanupMethods<'a> {
content_ty: ty::t);
fn schedule_clean(&self,
cleanup_scope: ScopeId,
cleanup: Box<Cleanup>);
cleanup: CleanupObj);
fn schedule_clean_in_ast_scope(&self,
cleanup_scope: ast::NodeId,
cleanup: Box<Cleanup>);
cleanup: CleanupObj);
fn schedule_clean_in_custom_scope(&self,
custom_scope: CustomScopeIndex,
cleanup: Box<Cleanup>);
cleanup: CleanupObj);
fn needs_invoke(&self) -> bool;
fn get_landing_pad(&'a self) -> BasicBlockRef;
}

View File

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

View File

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

View File

@ -273,7 +273,7 @@ pub enum UnsizeKind {
// An unsize coercion applied to the tail field of a struct.
// The uint is the index of the type parameter which is unsized.
UnsizeStruct(Box<UnsizeKind>, uint),
UnsizeVtable(ty::BuiltinBounds,
UnsizeVtable(ty::ExistentialBounds,
ast::DefId, /* Trait ID */
subst::Substs /* Trait substitutions */)
}
@ -464,7 +464,6 @@ pub struct ctxt {
pub lang_items: middle::lang_items::LanguageItems,
/// A mapping of fake provided method def_ids to the default implementation
pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
pub supertraits: RefCell<DefIdMap<Rc<Vec<Rc<TraitRef>>>>>,
pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
pub struct_fields: RefCell<DefIdMap<Rc<Vec<field_ty>>>>,
@ -620,7 +619,7 @@ pub struct ClosureTy {
pub fn_style: ast::FnStyle,
pub onceness: ast::Onceness,
pub store: TraitStore,
pub bounds: BuiltinBounds,
pub bounds: ExistentialBounds,
pub sig: FnSig,
pub abi: abi::Abi,
}
@ -932,7 +931,7 @@ pub enum sty {
pub struct TyTrait {
pub def_id: DefId,
pub substs: Substs,
pub bounds: BuiltinBounds
pub bounds: ExistentialBounds
}
#[deriving(PartialEq, Eq, Hash, Show)]
@ -995,18 +994,30 @@ pub enum type_err {
terr_variadic_mismatch(expected_found<bool>)
}
#[deriving(PartialEq, Eq, Hash, Show)]
/// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
/// as well as the existential type parameter in an object type.
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
pub struct ParamBounds {
pub opt_region_bound: Option<ty::Region>,
pub builtin_bounds: BuiltinBounds,
pub trait_bounds: Vec<Rc<TraitRef>>
}
/// Bounds suitable for an existentially quantified type parameter
/// such as those that appear in object types or closure types. The
/// major difference between this case and `ParamBounds` is that
/// general purpose trait bounds are omitted.
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
pub struct ExistentialBounds {
pub region_bound: ty::Region,
pub builtin_bounds: BuiltinBounds
}
pub type BuiltinBounds = EnumSet<BuiltinBound>;
#[deriving(Clone, Encodable, PartialEq, Eq, Decodable, Hash, Show)]
#[repr(uint)]
pub enum BuiltinBound {
BoundStatic,
BoundSend,
BoundSized,
BoundCopy,
@ -1019,13 +1030,21 @@ pub fn empty_builtin_bounds() -> BuiltinBounds {
pub fn all_builtin_bounds() -> BuiltinBounds {
let mut set = EnumSet::empty();
set.add(BoundStatic);
set.add(BoundSend);
set.add(BoundSized);
set.add(BoundSync);
set
}
pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds {
/*!
* An existential bound that does not implement any traits.
*/
ty::ExistentialBounds { region_bound: r,
builtin_bounds: empty_builtin_bounds() }
}
impl CLike for BuiltinBound {
fn to_uint(&self) -> uint {
*self as uint
@ -1141,8 +1160,8 @@ pub struct TypeParameterDef {
pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: uint,
pub bounds: Rc<ParamBounds>,
pub default: Option<ty::t>
pub bounds: ParamBounds,
pub default: Option<ty::t>,
}
#[deriving(Encodable, Decodable, Clone, Show)]
@ -1151,6 +1170,7 @@ pub struct RegionParameterDef {
pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: uint,
pub bounds: Vec<ty::Region>,
}
/// Information about the type/lifetime parameters associated with an
@ -1198,6 +1218,12 @@ pub struct ParameterEnvironment {
/// Bounds on the various type parameters
pub bounds: VecPerParamSpace<ParamBounds>,
/// Each type parameter has an implicit region bound that
/// indicates it must outlive at least the function body (the user
/// may specify stronger requirements). This field indicates the
/// region of the callee.
pub implicit_region_bound: ty::Region,
}
impl ParameterEnvironment {
@ -1292,7 +1318,7 @@ pub struct Polytype {
/// As `Polytype` but for a trait ref.
pub struct TraitDef {
pub generics: Generics,
pub bounds: BuiltinBounds,
pub bounds: ParamBounds,
pub trait_ref: Rc<ty::TraitRef>,
}
@ -1382,7 +1408,6 @@ pub fn mk_ctxt(s: Session,
normalized_cache: RefCell::new(HashMap::new()),
lang_items: lang_items,
provided_method_sources: RefCell::new(DefIdMap::new()),
supertraits: RefCell::new(DefIdMap::new()),
superstructs: RefCell::new(DefIdMap::new()),
struct_fields: RefCell::new(DefIdMap::new()),
destructor_for_type: RefCell::new(DefIdMap::new()),
@ -1459,6 +1484,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
}
return f;
}
fn flags_for_bounds(bounds: &ExistentialBounds) -> uint {
rflags(bounds.region_bound)
}
match &st {
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
&ty_str => {}
@ -1483,8 +1511,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
flags |= sflags(substs);
}
&ty_trait(box ty::TyTrait { ref substs, .. }) => {
&ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => {
flags |= sflags(substs);
flags |= flags_for_bounds(bounds);
}
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
flags |= get(tt).flags
@ -1514,6 +1543,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
flags |= get(f.sig.output).flags;
// T -> _|_ is *not* _|_ !
flags &= !(has_ty_bot as uint);
flags |= flags_for_bounds(&f.bounds);
}
}
@ -1711,8 +1741,8 @@ pub fn mk_ctor_fn(cx: &ctxt,
pub fn mk_trait(cx: &ctxt,
did: ast::DefId,
substs: Substs,
bounds: BuiltinBounds)
-> t {
bounds: ExistentialBounds)
-> t {
// take a copy of substs so that we own the vectors inside
let inner = box TyTrait {
def_id: did,
@ -1800,6 +1830,27 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|)
|t| { fldt(t); t }).fold_ty(ty)
}
impl ParamTy {
pub fn new(space: subst::ParamSpace,
index: uint,
def_id: ast::DefId)
-> ParamTy {
ParamTy { space: space, idx: index, def_id: def_id }
}
pub fn for_self(trait_def_id: ast::DefId) -> ParamTy {
ParamTy::new(subst::SelfSpace, 0, trait_def_id)
}
pub fn for_def(def: &TypeParameterDef) -> ParamTy {
ParamTy::new(def.space, def.index, def.def_id)
}
pub fn to_ty(self, tcx: &ty::ctxt) -> ty::t {
ty::mk_param(tcx, self.space, self.idx, self.def_id)
}
}
impl ItemSubsts {
pub fn empty() -> ItemSubsts {
ItemSubsts { substs: Substs::empty() }
@ -2115,9 +2166,6 @@ def_type_content_sets!(
// that it neither reaches nor owns a managed pointer.
Nonsendable = 0b0000_0111__0000_0100__0000,
// Things that prevent values from being considered 'static
Nonstatic = 0b0000_0010__0000_0000__0000,
// Things that prevent values from being considered sized
Nonsized = 0b0000_0000__0000_0000__0001,
@ -2142,9 +2190,8 @@ def_type_content_sets!(
)
impl TypeContents {
pub fn meets_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
pub fn meets_builtin_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
match bb {
BoundStatic => self.is_static(cx),
BoundSend => self.is_sendable(cx),
BoundSized => self.is_sized(cx),
BoundCopy => self.is_copy(cx),
@ -2160,10 +2207,6 @@ impl TypeContents {
(self.bits & tc.bits) != 0
}
pub fn is_static(&self, _: &ctxt) -> bool {
!self.intersects(TC::Nonstatic)
}
pub fn is_sendable(&self, _: &ctxt) -> bool {
!self.intersects(TC::Nonsendable)
}
@ -2272,10 +2315,6 @@ impl fmt::Show for TypeContents {
}
}
pub fn type_is_static(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_static(cx)
}
pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_sendable(cx)
}
@ -2482,10 +2521,11 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
let ty_param_defs = cx.ty_param_defs.borrow();
let tp_def = ty_param_defs.get(&p.def_id.node);
kind_bounds_to_contents(cx,
tp_def.bounds.builtin_bounds,
tp_def.bounds.trait_bounds.as_slice())
}
kind_bounds_to_contents(
cx,
tp_def.bounds.builtin_bounds,
tp_def.bounds.trait_bounds.as_slice())
}
ty_infer(_) => {
// This occurs during coherence, but shouldn't occur at other
@ -2577,10 +2617,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
}
fn object_contents(cx: &ctxt,
bounds: BuiltinBounds)
bounds: ExistentialBounds)
-> TypeContents {
// These are the type contents of the (opaque) interior
kind_bounds_to_contents(cx, bounds, [])
kind_bounds_to_contents(cx, bounds.builtin_bounds, [])
}
fn kind_bounds_to_contents(cx: &ctxt,
@ -2591,7 +2631,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
let mut tc = TC::All;
each_inherited_builtin_bound(cx, bounds, traits, |bound| {
tc = tc - match bound {
BoundStatic => TC::Nonstatic,
BoundSend => TC::Nonsendable,
BoundSized => TC::Nonsized,
BoundCopy => TC::Noncopy,
@ -2612,7 +2651,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
each_bound_trait_and_supertraits(cx, traits, |trait_ref| {
let trait_def = lookup_trait_def(cx, trait_ref.def_id);
for bound in trait_def.bounds.iter() {
for bound in trait_def.bounds.builtin_bounds.iter() {
f(bound);
}
true
@ -3272,16 +3311,19 @@ pub fn adjust_ty(cx: &ctxt,
AutoAddEnv(store) => {
match ty::get(unadjusted_ty).sty {
ty::ty_bare_fn(ref b) => {
let bounds = ty::ExistentialBounds {
region_bound: ReStatic,
builtin_bounds: all_builtin_bounds(),
};
ty::mk_closure(
cx,
ty::ClosureTy {
fn_style: b.fn_style,
onceness: ast::Many,
store: store,
bounds: ty::all_builtin_bounds(),
sig: b.sig.clone(),
abi: b.abi,
})
ty::ClosureTy {fn_style: b.fn_style,
onceness: ast::Many,
store: store,
bounds: bounds,
sig: b.sig.clone(),
abi: b.abi})
}
ref b => {
cx.sess.bug(
@ -3920,30 +3962,6 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
}
}
pub fn trait_supertraits(cx: &ctxt, id: ast::DefId) -> Rc<Vec<Rc<TraitRef>>> {
// Check the cache.
match cx.supertraits.borrow().find(&id) {
Some(trait_refs) => { return trait_refs.clone(); }
None => {} // Continue.
}
// Not in the cache. It had better be in the metadata, which means it
// shouldn't be local.
assert!(!is_local(id));
// Get the supertraits out of the metadata and create the
// TraitRef for each.
let result = Rc::new(csearch::get_supertraits(cx, id));
cx.supertraits.borrow_mut().insert(id, result.clone());
result
}
pub fn trait_ref_supertraits(cx: &ctxt, trait_ref: &ty::TraitRef) -> Vec<Rc<TraitRef>> {
let supertrait_refs = trait_supertraits(cx, trait_ref.def_id);
supertrait_refs.iter().map(
|supertrait_ref| supertrait_ref.subst(cx, &trait_ref.substs)).collect()
}
fn lookup_locally_or_in_crate_store<V:Clone>(
descr: &str,
def_id: ast::DefId,
@ -4055,9 +4073,12 @@ pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
def.def_id()
}
pub fn try_add_builtin_trait(tcx: &ctxt,
trait_def_id: ast::DefId,
builtin_bounds: &mut BuiltinBounds) -> bool {
pub fn try_add_builtin_trait(
tcx: &ctxt,
trait_def_id: ast::DefId,
builtin_bounds: &mut EnumSet<BuiltinBound>)
-> bool
{
//! Checks whether `trait_ref` refers to one of the builtin
//! traits, like `Send`, and adds the corresponding
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
@ -4343,6 +4364,18 @@ pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc<ty::TraitDef> {
}
}
/// Given a reference to a trait, returns the bounds declared on the
/// trait, with appropriate substitutions applied.
pub fn bounds_for_trait_ref(tcx: &ctxt,
trait_ref: &TraitRef)
-> ty::ParamBounds
{
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})",
trait_def.repr(tcx), trait_ref.repr(tcx));
trait_def.bounds.subst(tcx, &trait_ref.substs)
}
/// Iterate over attributes of a definition.
// (This should really be an iterator, but that would require csearch and
// decoder to use iterators instead of higher-order functions.)
@ -4410,14 +4443,10 @@ pub fn lookup_field_type(tcx: &ctxt,
node_id_to_type(tcx, id.node)
} else {
let mut tcache = tcx.tcache.borrow_mut();
match tcache.find(&id) {
Some(&Polytype {ty, ..}) => ty,
None => {
let tpt = csearch::get_field_type(tcx, struct_id, id);
tcache.insert(id, tpt.clone());
tpt.ty
}
}
let pty = tcache.find_or_insert_with(id, |_| {
csearch::get_field_type(tcx, struct_id, id)
});
pty.ty
};
t.subst(tcx, substs)
}
@ -4745,9 +4774,10 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
}
// Add supertraits to supertrait_set
let supertrait_refs = trait_ref_supertraits(tcx,
&**trait_refs.get(i));
for supertrait_ref in supertrait_refs.iter() {
let trait_ref = trait_refs.get(i).clone();
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
for supertrait_ref in trait_def.bounds.trait_bounds.iter() {
let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs);
debug!("each_bound_trait_and_supertraits(supertrait_ref={})",
supertrait_ref.repr(tcx));
@ -4765,6 +4795,61 @@ pub fn each_bound_trait_and_supertraits(tcx: &ctxt,
return true;
}
pub fn required_region_bounds(tcx: &ctxt,
region_bounds: &[ty::Region],
builtin_bounds: BuiltinBounds,
trait_bounds: &[Rc<TraitRef>])
-> Vec<ty::Region>
{
/*!
* Given a type which must meet the builtin bounds and trait
* bounds, returns a set of lifetimes which the type must outlive.
*
* Requires that trait definitions have been processed.
*/
let mut all_bounds = Vec::new();
debug!("required_region_bounds(builtin_bounds={}, trait_bounds={})",
builtin_bounds.repr(tcx),
trait_bounds.repr(tcx));
all_bounds.push_all(region_bounds);
push_region_bounds([],
builtin_bounds,
&mut all_bounds);
debug!("from builtin bounds: all_bounds={}", all_bounds.repr(tcx));
each_bound_trait_and_supertraits(
tcx,
trait_bounds,
|trait_ref| {
let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
push_region_bounds(bounds.opt_region_bound.as_slice(),
bounds.builtin_bounds,
&mut all_bounds);
debug!("from {}: bounds={} all_bounds={}",
trait_ref.repr(tcx),
bounds.repr(tcx),
all_bounds.repr(tcx));
true
});
return all_bounds;
fn push_region_bounds(region_bounds: &[ty::Region],
builtin_bounds: ty::BuiltinBounds,
all_bounds: &mut Vec<ty::Region>) {
all_bounds.push_all(region_bounds.as_slice());
if builtin_bounds.contains_elem(ty::BoundSend) {
all_bounds.push(ty::ReStatic);
}
}
}
pub fn get_tydesc_ty(tcx: &ctxt) -> Result<t, String> {
tcx.lang_items.require(TyDescStructLangItem).map(|tydesc_lang_item| {
tcx.intrinsic_defs.borrow().find_copy(&tydesc_lang_item)
@ -4780,7 +4865,10 @@ pub fn get_opaque_ty(tcx: &ctxt) -> Result<t, String> {
}
pub fn visitor_object_ty(tcx: &ctxt,
region: ty::Region) -> Result<(Rc<TraitRef>, t), String> {
ptr_region: ty::Region,
trait_region: ty::Region)
-> Result<(Rc<TraitRef>, t), String>
{
let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) {
Ok(id) => id,
Err(s) => { return Err(s); }
@ -4788,11 +4876,12 @@ pub fn visitor_object_ty(tcx: &ctxt,
let substs = Substs::empty();
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
Ok((trait_ref.clone(),
mk_rptr(tcx, region, mt {mutbl: ast::MutMutable,
ty: mk_trait(tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
empty_builtin_bounds()) })))
mk_rptr(tcx, ptr_region,
mt {mutbl: ast::MutMutable,
ty: mk_trait(tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
ty::region_existential_bound(trait_region))})))
}
pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
@ -5184,6 +5273,18 @@ pub fn construct_parameter_environment(
generics.types.get_slice(space));
}
//
// Compute region bounds. For now, these relations are stored in a
// global table on the tcx, so just enter them there. I'm not
// crazy about this scheme, but it's convenient, at least.
//
for &space in subst::ParamSpace::all().iter() {
record_region_bounds_from_defs(tcx, space, &free_substs,
generics.regions.get_slice(space));
}
debug!("construct_parameter_environment: free_id={} \
free_subst={} \
bounds={}",
@ -5193,7 +5294,8 @@ pub fn construct_parameter_environment(
return ty::ParameterEnvironment {
free_substs: free_substs,
bounds: bounds
bounds: bounds,
implicit_region_bound: ty::ReScope(free_id),
};
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
@ -5222,10 +5324,41 @@ pub fn construct_parameter_environment(
free_substs: &subst::Substs,
defs: &[TypeParameterDef]) {
for def in defs.iter() {
let b = (*def.bounds).subst(tcx, free_substs);
let b = def.bounds.subst(tcx, free_substs);
bounds.push(space, b);
}
}
fn record_region_bounds_from_defs(tcx: &ty::ctxt,
space: subst::ParamSpace,
free_substs: &subst::Substs,
defs: &[RegionParameterDef]) {
for (subst_region, def) in
free_substs.regions().get_slice(space).iter().zip(
defs.iter())
{
// For each region parameter 'subst...
let bounds = def.bounds.subst(tcx, free_substs);
for bound_region in bounds.iter() {
// Which is declared with a bound like 'subst:'bound...
match (subst_region, bound_region) {
(&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => {
// Record that 'subst outlives 'bound. Or, put
// another way, 'bound <= 'subst.
tcx.region_maps.relate_free_regions(bound_fr, subst_fr);
},
_ => {
// All named regions are instantiated with free regions.
tcx.sess.bug(
format!("push_region_bounds_from_defs: \
non free region: {} / {}",
subst_region.repr(tcx),
bound_region.repr(tcx)).as_slice());
}
}
}
}
}
}
impl BorrowKind {
@ -5346,4 +5479,3 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
}
})
}

View File

@ -85,6 +85,11 @@ pub trait TypeFolder {
super_fold_trait_store(self, s)
}
fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds)
-> ty::ExistentialBounds {
super_fold_existential_bounds(self, s)
}
fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef {
super_fold_autoref(self, ar)
}
@ -236,9 +241,16 @@ impl TypeFoldable for ty::BuiltinBounds {
}
}
impl TypeFoldable for ty::ExistentialBounds {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ExistentialBounds {
folder.fold_existential_bounds(*self)
}
}
impl TypeFoldable for ty::ParamBounds {
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::ParamBounds {
ty::ParamBounds {
opt_region_bound: self.opt_region_bound.fold_with(folder),
builtin_bounds: self.builtin_bounds.fold_with(folder),
trait_bounds: self.trait_bounds.fold_with(folder),
}
@ -259,8 +271,14 @@ impl TypeFoldable for ty::TypeParameterDef {
}
impl TypeFoldable for ty::RegionParameterDef {
fn fold_with<F:TypeFolder>(&self, _folder: &mut F) -> ty::RegionParameterDef {
*self
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::RegionParameterDef {
ty::RegionParameterDef {
name: self.name,
def_id: self.def_id,
space: self.space,
index: self.index,
bounds: self.bounds.fold_with(folder)
}
}
}
@ -340,7 +358,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
sig: fty.sig.fold_with(this),
fn_style: fty.fn_style,
onceness: fty.onceness,
bounds: fty.bounds,
bounds: fty.bounds.fold_with(this),
abi: fty.abi,
}
}
@ -389,7 +407,7 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
ty::ty_trait(box ty::TyTrait {
def_id: def_id,
substs: substs.fold_with(this),
bounds: bounds
bounds: this.fold_existential_bounds(bounds),
})
}
ty::ty_tup(ref ts) => {
@ -430,6 +448,15 @@ pub fn super_fold_trait_store<T:TypeFolder>(this: &mut T,
}
}
pub fn super_fold_existential_bounds<T:TypeFolder>(this: &mut T,
bounds: ty::ExistentialBounds)
-> ty::ExistentialBounds {
ty::ExistentialBounds {
region_bound: bounds.region_bound.fold_with(this),
builtin_bounds: bounds.builtin_bounds,
}
}
pub fn super_fold_autoref<T:TypeFolder>(this: &mut T,
autoref: &ty::AutoRef)
-> ty::AutoRef

View File

@ -57,19 +57,19 @@ use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
use middle::ty;
use middle::ty_fold::TypeFolder;
use middle::typeck::rscope::RegionScope;
use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
use middle::typeck::lookup_def_tcx;
use middle::typeck::infer;
use middle::typeck::rscope::{ExplicitRscope, RegionScope, SpecificRscope};
use middle::typeck::rscope;
use middle::typeck::TypeAndSubsts;
use middle::typeck;
use util::ppaux::Repr;
use util::ppaux::{Repr, UserString};
use std::collections::HashMap;
use std::rc::Rc;
use syntax::abi;
use syntax::{ast, ast_util};
use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice;
use syntax::print::pprust::{lifetime_to_string, path_to_string};
pub trait AstConv {
fn tcx<'a>(&'a self) -> &'a ty::ctxt;
@ -111,8 +111,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
};
debug!("ast_region_to_region(lifetime={} id={}) yields {}",
lifetime_to_string(lifetime),
lifetime.id, r.repr(tcx));
lifetime.repr(tcx),
lifetime.id,
r.repr(tcx));
r
}
@ -145,7 +146,7 @@ pub fn opt_ast_region_to_region<AC:AstConv,RS:RegionScope>(
};
debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}",
opt_lifetime.as_ref().map(|e| lifetime_to_string(e)),
opt_lifetime.repr(this.tcx()),
r.repr(this.tcx()));
r
@ -284,11 +285,11 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope>(
}
pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
this: &AC,
rscope: &RS,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts
this: &AC,
rscope: &RS,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts
{
let tcx = this.tcx();
let ty::Polytype {
@ -370,7 +371,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
None => {
tcx.sess.span_bug(ast_ty.span,
format!("unbound path {}",
path_to_string(path)).as_slice())
path.repr(tcx)).as_slice())
}
Some(&d) => d
};
@ -430,7 +431,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
.sess
.span_bug(ast_ty.span,
format!("unbound path {}",
path_to_string(path)).as_slice())
path.repr(this.tcx())).as_slice())
}
Some(&d) => d
};
@ -520,6 +521,16 @@ enum PointerTy {
Uniq
}
impl PointerTy {
fn default_region(&self) -> ty::Region {
match *self {
Box => ty::ReStatic,
Uniq => ty::ReStatic,
RPtr(r) => r,
}
}
}
pub fn trait_ref_for_unboxed_function<AC:AstConv,
RS:RegionScope>(
this: &AC,
@ -589,10 +600,11 @@ fn mk_pointer<AC:AstConv,
rscope,
&**unboxed_function,
None);
let r = ptr_ty.default_region();
let tr = ty::mk_trait(this.tcx(),
def_id,
substs,
ty::empty_builtin_bounds());
ty::region_existential_bound(r));
match ptr_ty {
Uniq => {
return ty::mk_uniq(this.tcx(), tr);
@ -612,7 +624,7 @@ fn mk_pointer<AC:AstConv,
}
}
ast::TyPath(ref path, ref bounds, id) => {
ast::TyPath(ref path, ref opt_bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
// will run after this as long as the path isn't a trait.
@ -636,14 +648,22 @@ fn mk_pointer<AC:AstConv,
Some(&def::DefTrait(trait_def_id)) => {
let result = ast_path_to_trait_ref(
this, rscope, trait_def_id, None, path);
let static_region = match ptr_ty {
RPtr(r) if r == ty::ReStatic => true,
_ => false
let bounds = match *opt_bounds {
None => {
conv_existential_bounds(this,
rscope,
path.span,
[result.clone()].as_slice(),
[].as_slice())
}
Some(ref bounds) => {
conv_existential_bounds(this,
rscope,
path.span,
[result.clone()].as_slice(),
bounds.as_slice())
}
};
let bounds = conv_builtin_bounds(this.tcx(),
path.span,
bounds,
static_region);
let tr = ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
@ -737,27 +757,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
bf.abi, &*bf.decl))
}
ast::TyClosure(ref f, ref region) => {
// resolve the function bound region in the original region
// scope `rscope`, not the scope of the function parameters
let bound_region = opt_ast_region_to_region(this, rscope,
ast_ty.span, region);
ast::TyClosure(ref f) => {
// Use corresponding trait store to figure out default bounds
// if none were specified.
let bounds = conv_builtin_bounds(this.tcx(),
ast_ty.span,
&f.bounds,
bound_region == ty::ReStatic);
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
let bounds = conv_existential_bounds(this,
rscope,
ast_ty.span,
[].as_slice(),
f.bounds.as_slice());
let fn_decl = ty_of_closure(this,
ast_ty.id,
f.fn_style,
f.onceness,
bounds,
store,
ty::RegionTraitStore(
bounds.region_bound,
ast::MutMutable),
&*f.decl,
abi::Rust,
None);
@ -766,10 +781,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
ast::TyProc(ref f) => {
// Use corresponding trait store to figure out default bounds
// if none were specified.
let bounds = conv_builtin_bounds(this.tcx(),
ast_ty.span,
&f.bounds,
false);
let bounds = conv_existential_bounds(this, rscope,
ast_ty.span,
[].as_slice(),
f.bounds.as_slice());
let fn_decl = ty_of_closure(this,
ast_ty.id,
@ -780,6 +795,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
&*f.decl,
abi::Rust,
None);
ty::mk_closure(tcx, fn_decl)
}
ast::TyUnboxedFn(..) => {
@ -793,7 +809,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
tcx.sess
.span_bug(ast_ty.span,
format!("unbound path {}",
path_to_string(path)).as_slice())
path.repr(tcx)).as_slice())
}
Some(&d) => d
};
@ -808,16 +824,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
}
match a_def {
def::DefTrait(trait_def_id) => {
let result = ast_path_to_trait_ref(
this, rscope, trait_def_id, None, path);
let bounds = conv_builtin_bounds(this.tcx(),
path.span,
bounds,
false);
ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
bounds)
let result = ast_path_to_trait_ref(
this, rscope, trait_def_id, None, path);
let empty_bounds: &[ast::TyParamBound] = &[];
let ast_bounds = match *bounds {
Some(ref b) => b.as_slice(),
None => empty_bounds
};
let bounds = conv_existential_bounds(this,
rscope,
ast_ty.span,
&[result.clone()],
ast_bounds);
ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
bounds)
}
def::DefTy(did) | def::DefStruct(did) => {
ast_path_to_ty(this, rscope, did, path).ty
@ -1022,9 +1044,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv>(
_ => {
match implied_output_region {
Some(implied_output_region) => {
let rb = ImpliedSingleRscope {
region: implied_output_region,
};
let rb = SpecificRscope::new(implied_output_region);
ast_ty_to_ty(this, &rb, &*decl.output)
}
None => {
@ -1130,7 +1150,7 @@ pub fn ty_of_closure<AC:AstConv>(
id: ast::NodeId,
fn_style: ast::FnStyle,
onceness: ast::Onceness,
bounds: ty::BuiltinBounds,
bounds: ty::ExistentialBounds,
store: ty::TraitStore,
decl: &ast::FnDecl,
abi: abi::Abi,
@ -1176,67 +1196,250 @@ pub fn ty_of_closure<AC:AstConv>(
}
}
fn conv_builtin_bounds(tcx: &ty::ctxt,
span: Span,
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
static_region: bool)
-> ty::BuiltinBounds {
//! Converts a list of bounds from the AST into a `BuiltinBounds`
//! struct. Reports an error if any of the bounds that appear
//! in the AST refer to general traits and not the built-in traits
//! like `Send`. Used to translate the bounds that
//! appear in closure and trait types, where only builtin bounds are
//! legal.
//! If no bounds were specified, we choose a "default" bound based on
//! the allocation type of the fn/trait, as per issue #7264. The user can
//! override this with an empty bounds list, e.g. "Box<fn:()>" or
//! "Box<Trait:>".
pub fn conv_existential_bounds<AC:AstConv, RS:RegionScope>(
this: &AC,
rscope: &RS,
span: Span,
main_trait_refs: &[Rc<ty::TraitRef>],
ast_bounds: &[ast::TyParamBound])
-> ty::ExistentialBounds
{
/*!
* Given an existential type like `Foo+'a+Bar`, this routine
* converts the `'a` and `Bar` intos an `ExistentialBounds`
* struct. The `main_trait_refs` argument specifies the `Foo` --
* it is absent for closures. Eventually this should all be
* normalized, I think, so that there is no "main trait ref" and
* instead we just have a flat list of bounds as the existential
* type.
*/
match ast_bounds {
&Some(ref bound_vec) => {
let mut builtin_bounds = ty::empty_builtin_bounds();
for ast_bound in bound_vec.iter() {
match *ast_bound {
ast::TraitTyParamBound(ref b) => {
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
def::DefTrait(trait_did) => {
if ty::try_add_builtin_trait(tcx, trait_did,
&mut builtin_bounds) {
continue; // success
}
}
_ => { }
}
tcx.sess.span_fatal(
b.path.span,
"only the builtin traits can be used as closure \
or object bounds");
}
ast::StaticRegionTyParamBound => {
builtin_bounds.add(ty::BoundStatic);
}
ast::UnboxedFnTyParamBound(_) => {
tcx.sess.span_err(span,
"unboxed functions are not allowed \
here");
}
ast::OtherRegionTyParamBound(span) => {
if !tcx.sess.features.issue_5723_bootstrap.get() {
tcx.sess.span_err(
span,
"only the 'static lifetime is accepted \
here.");
}
}
}
}
builtin_bounds
},
// &'static Trait is sugar for &'static Trait:'static.
&None if static_region => {
let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set
}
&None => ty::empty_builtin_bounds(),
let ast_bound_refs: Vec<&ast::TyParamBound> =
ast_bounds.iter().collect();
let PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds,
unboxed_fn_ty_bounds } =
partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
if !trait_bounds.is_empty() {
let b = trait_bounds.get(0);
this.tcx().sess.span_err(
b.path.span,
format!("only the builtin traits can be used \
as closure or object bounds").as_slice());
}
if !unboxed_fn_ty_bounds.is_empty() {
this.tcx().sess.span_err(
span,
format!("only the builtin traits can be used \
as closure or object bounds").as_slice());
}
// The "main trait refs", rather annoyingly, have no type
// specified for the `Self` parameter of the trait. The reason for
// this is that they are, after all, *existential* types, and
// hence that type is unknown. However, leaving this type missing
// causes the substitution code to go all awry when walking the
// bounds, so here we clone those trait refs and insert ty::err as
// the self type. Perhaps we should do this more generally, it'd
// be convenient (or perhaps something else, i.e., ty::erased).
let main_trait_refs: Vec<Rc<ty::TraitRef>> =
main_trait_refs.iter()
.map(|t|
Rc::new(ty::TraitRef {
def_id: t.def_id,
substs: t.substs.with_self_ty(ty::mk_err()) }))
.collect();
let region_bound = compute_region_bound(this,
rscope,
span,
builtin_bounds,
region_bounds.as_slice(),
main_trait_refs.as_slice());
ty::ExistentialBounds {
region_bound: region_bound,
builtin_bounds: builtin_bounds,
}
}
pub fn compute_opt_region_bound(tcx: &ty::ctxt,
span: Span,
builtin_bounds: ty::BuiltinBounds,
region_bounds: &[&ast::Lifetime],
trait_bounds: &[Rc<ty::TraitRef>])
-> Option<ty::Region>
{
/*!
* Given the bounds on a type parameter / existential type,
* determines what single region bound (if any) we can use to
* summarize this type. The basic idea is that we will use the
* bound the user provided, if they provided one, and otherwise
* search the supertypes of trait bounds for region bounds. It may
* be that we can derive no bound at all, in which case we return
* `None`.
*/
if region_bounds.len() > 1 {
tcx.sess.span_err(
region_bounds[1].span,
format!("only a single explicit lifetime bound is permitted").as_slice());
}
if region_bounds.len() != 0 {
// Explicitly specified region bound. Use that.
let r = region_bounds[0];
return Some(ast_region_to_region(tcx, r));
}
// No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those.
let derived_region_bounds =
ty::required_region_bounds(
tcx,
[],
builtin_bounds,
trait_bounds);
// If there are no derived region bounds, then report back that we
// can find no region bound.
if derived_region_bounds.len() == 0 {
return None;
}
// If any of the derived region bounds are 'static, that is always
// the best choice.
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
return Some(ty::ReStatic);
}
// Determine whether there is exactly one unique region in the set
// of derived region bounds. If so, use that. Otherwise, report an
// error.
let r = *derived_region_bounds.get(0);
if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) {
tcx.sess.span_err(
span,
format!("ambiguous lifetime bound, \
explicit lifetime bound required").as_slice());
}
return Some(r);
}
fn compute_region_bound<AC:AstConv, RS:RegionScope>(
this: &AC,
rscope: &RS,
span: Span,
builtin_bounds: ty::BuiltinBounds,
region_bounds: &[&ast::Lifetime],
trait_bounds: &[Rc<ty::TraitRef>])
-> ty::Region
{
/*!
* A version of `compute_opt_region_bound` for use where some
* region bound is required (existential types,
* basically). Reports an error if no region bound can be derived
* and we are in an `rscope` that does not provide a default.
*/
match compute_opt_region_bound(this.tcx(), span, builtin_bounds,
region_bounds, trait_bounds) {
Some(r) => r,
None => {
match rscope.default_region_bound(span) {
Some(r) => { r }
None => {
this.tcx().sess.span_err(
span,
format!("explicit lifetime bound required").as_slice());
ty::ReStatic
}
}
}
}
}
pub struct PartitionedBounds<'a> {
pub builtin_bounds: ty::BuiltinBounds,
pub trait_bounds: Vec<&'a ast::TraitRef>,
pub unboxed_fn_ty_bounds: Vec<&'a ast::UnboxedFnTy>,
pub region_bounds: Vec<&'a ast::Lifetime>,
}
pub fn partition_bounds<'a>(tcx: &ty::ctxt,
_span: Span,
ast_bounds: &'a [&ast::TyParamBound])
-> PartitionedBounds<'a>
{
/*!
* Divides a list of bounds from the AST into three groups:
* builtin bounds (Copy, Sized etc), general trait bounds,
* and region bounds.
*/
let mut builtin_bounds = ty::empty_builtin_bounds();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
let mut unboxed_fn_ty_bounds = Vec::new();
let mut trait_def_ids = HashMap::new();
for &ast_bound in ast_bounds.iter() {
match *ast_bound {
ast::TraitTyParamBound(ref b) => {
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
def::DefTrait(trait_did) => {
match trait_def_ids.find(&trait_did) {
// Already seen this trait. We forbid
// duplicates in the list (for some
// reason).
Some(span) => {
span_err!(
tcx.sess, b.path.span, E0127,
"trait `{}` already appears in the \
list of bounds",
b.path.user_string(tcx));
tcx.sess.span_note(
*span,
"previous appearance is here");
continue;
}
None => { }
}
trait_def_ids.insert(trait_did, b.path.span);
if ty::try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {
continue; // success
}
}
_ => {
// Not a trait? that's an error, but it'll get
// reported later.
}
}
trait_bounds.push(b);
}
ast::RegionTyParamBound(ref l) => {
region_bounds.push(l);
}
ast::UnboxedFnTyParamBound(ref unboxed_function) => {
unboxed_fn_ty_bounds.push(unboxed_function);
}
}
}
PartitionedBounds {
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
region_bounds: region_bounds,
unboxed_fn_ty_bounds: unboxed_fn_ty_bounds
}
}

View File

@ -87,7 +87,6 @@ use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
use middle::typeck::check;
use middle::typeck::infer::MiscVariable;
use middle::typeck::infer;
use middle::typeck::MethodCallee;
use middle::typeck::{MethodOrigin, MethodParam};
@ -240,6 +239,7 @@ fn construct_transformed_self_ty_for_object(
span: Span,
trait_def_id: ast::DefId,
rcvr_substs: &subst::Substs,
rcvr_bounds: ty::ExistentialBounds,
method_ty: &ty::Method)
-> ty::t
{
@ -276,8 +276,7 @@ fn construct_transformed_self_ty_for_object(
tcx.sess.span_bug(span, "static method for object type receiver");
}
ByValueExplicitSelfCategory => {
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
ty::empty_builtin_bounds());
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds);
ty::mk_uniq(tcx, tr)
}
ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => {
@ -286,12 +285,12 @@ fn construct_transformed_self_ty_for_object(
ty::ty_rptr(r, mt) => { // must be SelfRegion
let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
ty::empty_builtin_bounds());
rcvr_bounds);
ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
}
ty::ty_uniq(_) => { // must be SelfUniq
let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
ty::empty_builtin_bounds());
rcvr_bounds);
ty::mk_uniq(tcx, tr)
}
_ => {
@ -442,8 +441,9 @@ impl<'a> LookupContext<'a> {
let span = self.self_expr.map_or(self.span, |e| e.span);
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
ty_trait(box TyTrait { def_id, ref substs, .. }) => {
self.push_inherent_candidates_from_object(def_id, substs);
ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => {
self.push_inherent_candidates_from_object(
def_id, substs, bounds);
self.push_inherent_impl_candidates_for_type(def_id);
}
ty_enum(did, _) |
@ -538,15 +538,13 @@ impl<'a> LookupContext<'a> {
}
let vcx = self.fcx.vtable_context();
let region_params =
vec!(vcx.infcx.next_region_var(MiscVariable(self.span)));
// Get the tupled type of the arguments.
let arguments_type = *closure_function_type.sig.inputs.get(0);
let return_type = closure_function_type.sig.output;
let closure_region =
vcx.infcx.next_region_var(MiscVariable(self.span));
vcx.infcx.next_region_var(infer::MiscVariable(self.span));
let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
closure_did,
closure_region);
@ -555,7 +553,7 @@ impl<'a> LookupContext<'a> {
RcvrMatchesIfSubtype(unboxed_closure_type),
rcvr_substs: subst::Substs::new_trait(
vec![arguments_type, return_type],
region_params,
vec![],
*vcx.infcx.next_ty_vars(1).get(0)),
method_ty: method,
origin: MethodStaticUnboxedClosure(closure_did),
@ -595,11 +593,11 @@ impl<'a> LookupContext<'a> {
fn push_inherent_candidates_from_object(&mut self,
did: DefId,
substs: &subst::Substs) {
substs: &subst::Substs,
bounds: ty::ExistentialBounds) {
debug!("push_inherent_candidates_from_object(did={}, substs={})",
self.did_to_string(did),
substs.repr(self.tcx()));
let _indenter = indenter();
let tcx = self.tcx();
let span = self.span;
@ -617,28 +615,30 @@ impl<'a> LookupContext<'a> {
substs: rcvr_substs.clone()
});
self.push_inherent_candidates_from_bounds_inner(&[trait_ref.clone()],
|new_trait_ref, m, method_num, _bound_num| {
let vtable_index = get_method_index(tcx, &*new_trait_ref,
trait_ref.clone(), method_num);
let mut m = (*m).clone();
// We need to fix up the transformed self type.
*m.fty.sig.inputs.get_mut(0) =
construct_transformed_self_ty_for_object(
tcx, span, did, &rcvr_substs, &m);
self.push_inherent_candidates_from_bounds_inner(
&[trait_ref.clone()],
|_this, new_trait_ref, m, method_num, _bound_num| {
let vtable_index =
get_method_index(tcx, &*new_trait_ref,
trait_ref.clone(), method_num);
let mut m = (*m).clone();
// We need to fix up the transformed self type.
*m.fty.sig.inputs.get_mut(0) =
construct_transformed_self_ty_for_object(
tcx, span, did, &rcvr_substs, bounds, &m);
Some(Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: new_trait_ref.substs.clone(),
method_ty: Rc::new(m),
origin: MethodObject(MethodObject {
Some(Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: new_trait_ref.substs.clone(),
method_ty: Rc::new(m),
origin: MethodObject(MethodObject {
trait_id: new_trait_ref.def_id,
object_trait_id: did,
method_num: method_num,
real_index: vtable_index
})
})
});
})
});
}
fn push_inherent_candidates_from_param(&mut self,
@ -666,7 +666,7 @@ impl<'a> LookupContext<'a> {
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
.as_slice();
self.push_inherent_candidates_from_bounds_inner(bounds,
|trait_ref, m, method_num, bound_num| {
|this, trait_ref, m, method_num, bound_num| {
match restrict_to {
Some(trait_did) => {
if trait_did != trait_ref.def_id {
@ -675,6 +675,18 @@ impl<'a> LookupContext<'a> {
}
_ => {}
}
debug!("found match: trait_ref={} substs={} m={}",
trait_ref.repr(this.tcx()),
trait_ref.substs.repr(this.tcx()),
m.repr(this.tcx()));
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
Some(Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
rcvr_substs: trait_ref.substs.clone(),
@ -691,13 +703,15 @@ impl<'a> LookupContext<'a> {
// Do a search through a list of bounds, using a callback to actually
// create the candidates.
fn push_inherent_candidates_from_bounds_inner(&mut self,
bounds: &[Rc<TraitRef>],
mk_cand: |tr: Rc<TraitRef>,
m: Rc<ty::Method>,
method_num: uint,
bound_num: uint|
-> Option<Candidate>) {
fn push_inherent_candidates_from_bounds_inner(
&mut self,
bounds: &[Rc<TraitRef>],
mk_cand: |this: &mut LookupContext,
tr: Rc<TraitRef>,
m: Rc<ty::Method>,
method_num: uint,
bound_num: uint|
-> Option<Candidate>) {
let tcx = self.tcx();
let mut next_bound_idx = 0; // count only trait bounds
@ -719,7 +733,8 @@ impl<'a> LookupContext<'a> {
ty::MethodTraitItem(ref method) => (*method).clone(),
};
match mk_cand(bound_trait_ref,
match mk_cand(self,
bound_trait_ref,
method,
pos,
this_bound_idx) {
@ -1338,6 +1353,11 @@ impl<'a> LookupContext<'a> {
}
}
self.fcx.add_region_obligations_for_parameters(
self.span,
&all_substs,
&candidate.method_ty.generics);
MethodCallee {
origin: candidate.origin,
ty: fty,

File diff suppressed because it is too large Load Diff

View File

@ -126,14 +126,14 @@ use middle::ty::{ReScope};
use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::check::FnCtxt;
use middle::typeck::check::regionmanip::relate_nested_regions;
use middle::typeck::check::regionmanip;
use middle::typeck::infer::resolve_and_force_all_but_regions;
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::MethodCall;
use middle::pat_util;
use util::nodemap::{DefIdMap, NodeMap};
use util::ppaux::{ty_to_string, region_to_string, Repr};
use util::ppaux::{ty_to_string, Repr};
use syntax::ast;
use syntax::codemap::Span;
@ -143,6 +143,46 @@ use syntax::visit::Visitor;
use std::cell::RefCell;
use std::gc::Gc;
///////////////////////////////////////////////////////////////////////////
// PUBLIC ENTRY POINTS
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
let mut rcx = Rcx::new(fcx, e.id);
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_expr(e, ());
rcx.visit_region_obligations(e.id);
}
fcx.infcx().resolve_regions_and_report_errors();
}
pub fn regionck_type_defn(fcx: &FnCtxt,
span: Span,
component_tys: &[ty::t]) {
let mut rcx = Rcx::new(fcx, 0);
for &component_ty in component_tys.iter() {
// Check that each type outlives the empty region. Since the
// empty region is a subregion of all others, this can't fail
// unless the type does not meet the well-formedness
// requirements.
type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
component_ty, ty::ReEmpty);
}
fcx.infcx().resolve_regions_and_report_errors();
}
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
let mut rcx = Rcx::new(fcx, blk.id);
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_fn_body(id, blk);
}
fcx.infcx().resolve_regions_and_report_errors();
}
///////////////////////////////////////////////////////////////////////////
// INTERNALS
// If mem categorization results in an error, it's because the type
// check failed (or will fail, when the error is uncovered and
// reported during writeback). In this case, we just ignore this part
@ -159,10 +199,32 @@ macro_rules! ignore_err(
pub struct Rcx<'a> {
fcx: &'a FnCtxt<'a>,
region_param_pairs: Vec<(ty::Region, ty::ParamTy)>,
// id of innermost fn or loop
repeating_scope: ast::NodeId,
}
/// When entering a function, we can derive relationships from the
/// signature between various regions and type parameters. Consider
/// a function like:
///
/// fn foo<'a, A>(x: &'a A) { ... }
///
/// Here, we can derive that `A` must outlive `'a`, because otherwise
/// the caller would be illegal. We record this by storing a series of
/// pairs (in this case, `('a, A)`). These pairs will be consulted
/// later during regionck.
///
/// In the case of nested fns, additional relationships may be
/// derived. The result is a link list walking up the stack (hence
/// the `previous` field).
#[deriving(Clone)]
pub struct RegionSubParamConstraints<'a> {
pairs: Vec<(ty::Region, ty::ParamTy)>,
previous: Option<&'a RegionSubParamConstraints<'a>>,
}
fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
/*!
* Returns the validity region of `def` -- that is, how long
@ -189,6 +251,13 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region {
}
impl<'a> Rcx<'a> {
pub fn new(fcx: &'a FnCtxt<'a>,
initial_repeating_scope: ast::NodeId) -> Rcx<'a> {
Rcx { fcx: fcx,
repeating_scope: initial_repeating_scope,
region_param_pairs: Vec::new() }
}
pub fn tcx(&self) -> &'a ty::ctxt {
self.fcx.ccx.tcx
}
@ -259,6 +328,114 @@ impl<'a> Rcx<'a> {
|method_call| self.resolve_method_type(method_call))
}
}
fn visit_fn_body(&mut self,
id: ast::NodeId,
body: &ast::Block)
{
// When we enter a function, we can derive
let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
let fn_sig = match fn_sig_map.find(&id) {
Some(f) => f,
None => {
self.tcx().sess.bug(
format!("No fn-sig entry for id={}", id).as_slice());
}
};
let len = self.region_param_pairs.len();
self.relate_free_regions(fn_sig.as_slice(), body.id);
self.visit_block(body, ());
self.visit_region_obligations(body.id);
self.region_param_pairs.truncate(len);
}
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
{
debug!("visit_region_obligations: node_id={}", node_id);
let region_obligations = self.fcx.inh.region_obligations.borrow();
match region_obligations.find(&node_id) {
None => { }
Some(vec) => {
for r_o in vec.iter() {
debug!("visit_region_obligations: r_o={}",
r_o.repr(self.tcx()));
let sup_type = self.resolve_type(r_o.sup_type);
type_must_outlive(self, r_o.origin.clone(),
sup_type, r_o.sub_region);
}
}
}
}
fn relate_free_regions(&mut self,
fn_sig_tys: &[ty::t],
body_id: ast::NodeId) {
/*!
* This method populates the region map's `free_region_map`.
* It walks over the transformed argument and return types for
* each function just before we check the body of that
* function, looking for types where you have a borrowed
* pointer to other borrowed data (e.g., `&'a &'b [uint]`. We
* do not allow references to outlive the things they point
* at, so we can assume that `'a <= 'b`. This holds for both
* the argument and return types, basically because, on the caller
* side, the caller is responsible for checking that the type of
* every expression (including the actual values for the arguments,
* as well as the return type of the fn call) is well-formed.
*
* Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
*/
debug!("relate_free_regions >>");
let tcx = self.tcx();
for &ty in fn_sig_tys.iter() {
let ty = self.resolve_type(ty);
debug!("relate_free_regions(t={})", ty.repr(tcx));
let body_scope = ty::ReScope(body_id);
let constraints =
regionmanip::region_wf_constraints(
tcx,
ty,
body_scope);
for constraint in constraints.iter() {
debug!("constraint: {}", constraint.repr(tcx));
match *constraint {
regionmanip::RegionSubRegionConstraint(_,
ty::ReFree(free_a),
ty::ReFree(free_b)) => {
tcx.region_maps.relate_free_regions(free_a, free_b);
}
regionmanip::RegionSubRegionConstraint(_,
ty::ReFree(free_a),
ty::ReInfer(ty::ReVar(vid_b))) => {
self.fcx.inh.infcx.add_given(free_a, vid_b);
}
regionmanip::RegionSubRegionConstraint(..) => {
// In principle, we could record (and take
// advantage of) every relationship here, but
// we are also free not to -- it simply means
// strictly less that we can successfully type
// check. (It may also be that we should
// revise our inference system to be more
// general and to make use of *every*
// relationship that arises here, but
// presently we do not.)
}
regionmanip::RegionSubParamConstraint(_, r_a, p_b) => {
debug!("RegionSubParamConstraint: {} <= {}",
r_a.repr(tcx), p_b.repr(tcx));
self.region_param_pairs.push((r_a, p_b));
}
}
}
}
debug!("<< relate_free_regions");
}
}
impl<'fcx> mc::Typer for Rcx<'fcx> {
@ -302,26 +479,6 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
}
}
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
let mut rcx = Rcx { fcx: fcx, repeating_scope: e.id };
let rcx = &mut rcx;
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_expr(e, ());
}
fcx.infcx().resolve_regions_and_report_errors();
}
pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
let mut rcx = Rcx { fcx: fcx, repeating_scope: blk.id };
let rcx = &mut rcx;
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_block(blk, ());
}
fcx.infcx().resolve_regions_and_report_errors();
}
impl<'a> Visitor<()> for Rcx<'a> {
// (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
// However, right now we run into an issue whereby some free
@ -331,6 +488,11 @@ impl<'a> Visitor<()> for Rcx<'a> {
// hierarchy, and in particular the relationships between free
// regions, until regionck, as described in #3238.
fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl,
b: &ast::Block, _s: Span, id: ast::NodeId, _e: ()) {
self.visit_fn_body(id, b)
}
fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(self, i); }
fn visit_expr(&mut self, ex: &ast::Expr, _: ()) { visit_expr(self, ex); }
@ -396,9 +558,9 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
// variable's type enclose at least the variable's scope.
let var_region = tcx.region_maps.var_region(id);
constrain_regions_in_type_of_node(
rcx, id, var_region,
infer::BindingTypeIsNotValidAtDecl(span));
type_of_node_must_outlive(
rcx, infer::BindingTypeIsNotValidAtDecl(span),
id, var_region);
})
}
@ -406,6 +568,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
// No matter what, the type of each expression must outlive the
// scope of that expression. This also guarantees basic WF.
let expr_ty = rcx.resolve_node_type(expr.id);
type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span),
expr_ty, ty::ReScope(expr.id));
let method_call = MethodCall::expr(expr.id);
let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
@ -416,40 +585,28 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
let expr_ty = rcx.resolve_node_type(expr.id);
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
match ty::adjusted_object_region(adjustment) {
Some(trait_region) => {
// Determine if we are casting `expr` to a trait
// instance. If so, we have to be sure that the type of
// the source obeys the trait's region bound.
//
// Note: there is a subtle point here concerning type
// parameters. It is possible that the type of `source`
// contains type parameters, which in turn may contain
// regions that are not visible to us (only the caller
// knows about them). The kind checker is ultimately
// responsible for guaranteeing region safety in that
// particular case. There is an extensive comment on the
// function check_cast_for_escaping_regions() in kind.rs
// explaining how it goes about doing that.
for autoref in opt_autoref.iter() {
link_autoref(rcx, expr, autoderefs, autoref);
constrain_regions_in_type(rcx, trait_region,
infer::RelateObjectBound(expr.span), expr_ty);
}
None => {
for autoref in opt_autoref.iter() {
link_autoref(rcx, expr, autoderefs, autoref);
// Require that the resulting region encompasses
// the current node.
//
// FIXME(#6268) remove to support nested method calls
constrain_regions_in_type_of_node(
rcx, expr.id, ty::ReScope(expr.id),
infer::AutoBorrow(expr.span));
}
}
// Require that the resulting region encompasses
// the current node.
//
// FIXME(#6268) remove to support nested method calls
type_of_node_must_outlive(
rcx, infer::AutoBorrow(expr.span),
expr.id, ty::ReScope(expr.id));
}
}
/*
ty::AutoObject(_, ref bounds, _, _) => {
// Determine if we are casting `expr` to a trait
// instance. If so, we have to be sure that the type
// of the source obeys the new region bound.
let source_ty = rcx.resolve_node_type(expr.id);
type_must_outlive(rcx, infer::RelateObjectBound(expr.span),
source_ty, bounds.region_bound);
}
*/
_ => {}
}
}
@ -457,12 +614,11 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
match expr.node {
ast::ExprCall(ref callee, ref args) => {
if has_method_map {
constrain_call(rcx, None, expr, Some(*callee),
constrain_call(rcx, expr, Some(*callee),
args.as_slice(), false);
} else {
constrain_callee(rcx, callee.id, expr, &**callee);
constrain_call(rcx,
Some(callee.id),
expr,
None,
args.as_slice(),
@ -473,7 +629,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
}
ast::ExprMethodCall(_, _, ref args) => {
constrain_call(rcx, None, expr, Some(*args.get(0)),
constrain_call(rcx, expr, Some(*args.get(0)),
args.slice_from(1), false);
visit::walk_expr(rcx, expr, ());
@ -486,7 +642,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
if has_method_map {
constrain_call(rcx, None, expr, Some(lhs.clone()),
constrain_call(rcx, expr, Some(lhs.clone()),
[rhs.clone()], true);
}
@ -501,7 +657,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
// overloaded op. Note that we (sadly) currently use an
// implicit "by ref" sort of passing style here. This
// should be converted to an adjustment!
constrain_call(rcx, None, expr, Some(lhs.clone()),
constrain_call(rcx, expr, Some(lhs.clone()),
[rhs.clone()], true);
visit::walk_expr(rcx, expr, ());
@ -509,17 +665,25 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
ast::ExprUnary(_, ref lhs) if has_method_map => {
// As above.
constrain_call(rcx, None, expr, Some(lhs.clone()), [], true);
constrain_call(rcx, expr, Some(lhs.clone()), [], true);
visit::walk_expr(rcx, expr, ());
}
ast::ExprUnary(ast::UnBox, ref base) => {
// Managed data must not have borrowed pointers within it:
let base_ty = rcx.resolve_node_type(base.id);
type_must_outlive(rcx, infer::Managed(expr.span),
base_ty, ty::ReStatic);
visit::walk_expr(rcx, expr, ());
}
ast::ExprUnary(ast::UnDeref, ref base) => {
// For *a, the lifetime of a must enclose the deref
let method_call = MethodCall::expr(expr.id);
let base_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
Some(method) => {
constrain_call(rcx, None, expr, Some(base.clone()), [], true);
constrain_call(rcx, expr, Some(base.clone()), [], true);
ty::ty_fn_ret(method.ty)
}
None => rcx.resolve_node_type(base.id)
@ -547,34 +711,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
// Determine if we are casting `source` to a trait
// instance. If so, we have to be sure that the type of
// the source obeys the trait's region bound.
//
// Note: there is a subtle point here concerning type
// parameters. It is possible that the type of `source`
// contains type parameters, which in turn may contain
// regions that are not visible to us (only the caller
// knows about them). The kind checker is ultimately
// responsible for guaranteeing region safety in that
// particular case. There is an extensive comment on the
// function check_cast_for_escaping_regions() in kind.rs
// explaining how it goes about doing that.
let target_ty = rcx.resolve_node_type(expr.id);
match ty::get(target_ty).sty {
ty::ty_rptr(trait_region, ty::mt{ty, ..}) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
let source_ty = rcx.resolve_expr_type_adjusted(&**source);
constrain_regions_in_type(
rcx,
trait_region,
infer::RelateObjectBound(expr.span),
source_ty);
}
_ => {}
}
}
_ => ()
}
constrain_cast(rcx, expr, &**source);
visit::walk_expr(rcx, expr, ());
}
@ -589,8 +726,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
//
// FIXME(#6268) nested method calls requires that this rule change
let ty0 = rcx.resolve_node_type(expr.id);
constrain_regions_in_type(rcx, ty::ReScope(expr.id),
infer::AddrOf(expr.span), ty0);
type_must_outlive(rcx, infer::AddrOf(expr.span),
ty0, ty::ReScope(expr.id));
visit::walk_expr(rcx, expr, ());
}
@ -644,42 +781,108 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
}
}
fn constrain_cast(rcx: &mut Rcx,
cast_expr: &ast::Expr,
source_expr: &ast::Expr)
{
debug!("constrain_cast(cast_expr={}, source_expr={})",
cast_expr.repr(rcx.tcx()),
source_expr.repr(rcx.tcx()));
let source_ty = rcx.resolve_node_type(source_expr.id);
let target_ty = rcx.resolve_node_type(cast_expr.id);
walk_cast(rcx, cast_expr, source_ty, target_ty);
fn walk_cast(rcx: &mut Rcx,
cast_expr: &ast::Expr,
from_ty: ty::t,
to_ty: ty::t) {
debug!("walk_cast(from_ty={}, to_ty={})",
from_ty.repr(rcx.tcx()),
to_ty.repr(rcx.tcx()));
match (&ty::get(from_ty).sty, &ty::get(to_ty).sty) {
/*From:*/ (&ty::ty_rptr(from_r, ref from_mt),
/*To: */ &ty::ty_rptr(to_r, ref to_mt)) => {
// Target cannot outlive source, naturally.
rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), to_r, from_r);
walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty);
}
/*From:*/ (_,
/*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => {
// When T is existentially quantified as a trait
// `Foo+'to`, it must outlive the region bound `'to`.
type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span),
from_ty, bounds.region_bound);
}
/*From:*/ (&ty::ty_uniq(from_referent_ty),
/*To: */ &ty::ty_uniq(to_referent_ty)) => {
walk_cast(rcx, cast_expr, from_referent_ty, to_referent_ty);
}
_ => { }
}
}
}
fn check_expr_fn_block(rcx: &mut Rcx,
expr: &ast::Expr,
body: &ast::Block) {
let tcx = rcx.fcx.tcx();
let function_type = rcx.resolve_node_type(expr.id);
match ty::get(function_type).sty {
ty::ty_closure(box ty::ClosureTy {
store: ty::RegionTraitStore(region, _), ..}) => {
ty::ty_closure(box ty::ClosureTy{store: ty::RegionTraitStore(..),
bounds: ref bounds,
..}) => {
// For closure, ensure that the variables outlive region
// bound, since they are captured by reference.
freevars::with_freevars(tcx, expr.id, |freevars| {
if freevars.is_empty() {
// No free variables means that the environment
// will be NULL at runtime and hence the closure
// has static lifetime.
} else {
// Closure must not outlive the variables it closes over.
constrain_free_variables(rcx, region, expr, freevars);
// Variables being referenced must outlive closure.
constrain_free_variables_in_stack_closure(
rcx, bounds.region_bound, expr, freevars);
// Closure cannot outlive the appropriate temporary scope.
// Closure is stack allocated and hence cannot
// outlive the appropriate temporary scope.
let s = rcx.repeating_scope;
rcx.fcx.mk_subr(true, infer::InfStackClosure(expr.span),
region, ty::ReScope(s));
rcx.fcx.mk_subr(infer::InfStackClosure(expr.span),
bounds.region_bound, ty::ReScope(s));
}
});
}
ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
bounds: ref bounds,
..}) => {
// For proc, ensure that the *types* of the variables
// outlive region bound, since they are captured by value.
freevars::with_freevars(tcx, expr.id, |freevars| {
ensure_free_variable_types_outlive_closure_bound(
rcx, bounds.region_bound, expr, freevars);
});
}
ty::ty_unboxed_closure(_, region) => {
freevars::with_freevars(tcx, expr.id, |freevars| {
// No free variables means that there is no environment and
// hence the closure has static lifetime. Otherwise, the
// closure must not outlive the variables it closes over
// by-reference.
//
// NDM -- this seems wrong, discuss with pcwalton, should
// be straightforward enough.
if !freevars.is_empty() {
constrain_free_variables(rcx, region, expr, freevars);
ensure_free_variable_types_outlive_closure_bound(
rcx, region, expr, freevars);
}
})
}
_ => ()
_ => { }
}
let repeating_scope = rcx.set_repeating_scope(body.id);
@ -698,36 +901,74 @@ fn check_expr_fn_block(rcx: &mut Rcx,
_ => ()
}
fn constrain_free_variables(rcx: &mut Rcx,
region: ty::Region,
expr: &ast::Expr,
freevars: &[freevars::freevar_entry]) {
fn ensure_free_variable_types_outlive_closure_bound(
rcx: &mut Rcx,
region_bound: ty::Region,
expr: &ast::Expr,
freevars: &[freevars::freevar_entry])
{
/*!
* Make sure that all free variables referenced inside the closure
* outlive the closure itself. Also, create an entry in the
* upvar_borrows map with a region.
* Make sure that the type of all free variables referenced
* inside a closure/proc outlive the closure/proc's lifetime
* bound. This is just a special case of the usual rules about
* closed over values outliving the object's lifetime bound.
*/
let tcx = rcx.fcx.ccx.tcx;
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
region_bound.repr(tcx), expr.repr(tcx));
for freevar in freevars.iter() {
let var_node_id = {
let def_id = freevar.def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
def_id.node
};
let var_ty = rcx.resolve_node_type(var_node_id);
type_must_outlive(
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
var_ty, region_bound);
}
}
fn constrain_free_variables_in_stack_closure(
rcx: &mut Rcx,
region_bound: ty::Region,
expr: &ast::Expr,
freevars: &[freevars::freevar_entry])
{
/*!
* Make sure that all free variables referenced inside the
* closure outlive the closure's lifetime bound. Also, create
* an entry in the upvar_borrows map with a region.
*/
let tcx = rcx.fcx.ccx.tcx;
let infcx = rcx.fcx.infcx();
debug!("constrain_free_variables({}, {})",
region.repr(tcx), expr.repr(tcx));
region_bound.repr(tcx), expr.repr(tcx));
for freevar in freevars.iter() {
debug!("freevar def is {:?}", freevar.def);
// Identify the variable being closed over and its node-id.
let def = freevar.def;
let def_id = def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
let upvar_id = ty::UpvarId { var_id: def_id.node,
let var_node_id = {
let def_id = def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
def_id.node
};
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
// Create a region variable to represent this borrow. This borrow
// must outlive the region on the closure.
let origin = infer::UpvarRegion(upvar_id, expr.span);
let freevar_region = infcx.next_region_var(origin);
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
region, freevar_region);
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, freevar_region);
// Create a UpvarBorrow entry. Note that we begin with a
// const borrow_kind, but change it to either mut or
@ -738,10 +979,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
upvar_borrow);
// Guarantee that the closure does not outlive the variable itself.
let en_region = region_of_def(rcx.fcx, def);
debug!("en_region = {}", en_region.repr(tcx));
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span, def_id.node),
region, en_region);
let enclosing_region = region_of_def(rcx.fcx, def);
debug!("enclosing_region = {}", enclosing_region.repr(tcx));
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, enclosing_region);
}
}
@ -817,7 +1058,7 @@ fn constrain_callee(rcx: &mut Rcx,
}
ty::UniqTraitStore => ty::ReStatic
};
rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
rcx.fcx.mk_subr(infer::InvokeClosure(callee_expr.span),
call_region, region);
}
_ => {
@ -832,9 +1073,6 @@ fn constrain_callee(rcx: &mut Rcx,
}
fn constrain_call(rcx: &mut Rcx,
// might be expr_call, expr_method_call, or an overloaded
// operator
fn_expr_id: Option<ast::NodeId>,
call_expr: &ast::Expr,
receiver: Option<Gc<ast::Expr>>,
arg_exprs: &[Gc<ast::Expr>],
@ -853,16 +1091,6 @@ fn constrain_call(rcx: &mut Rcx,
receiver.repr(tcx),
arg_exprs.repr(tcx),
implicitly_ref_args);
let callee_ty = match fn_expr_id {
Some(id) => rcx.resolve_node_type(id),
None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
.expect("call should have been to a method")
};
if ty::type_is_error(callee_ty) {
// Bail, as function type is unknown
return;
}
let fn_sig = ty::ty_fn_sig(callee_ty);
// `callee_region` is the scope representing the time in which the
// call occurs.
@ -871,14 +1099,16 @@ fn constrain_call(rcx: &mut Rcx,
let callee_scope = call_expr.id;
let callee_region = ty::ReScope(callee_scope);
debug!("callee_region={}", callee_region.repr(tcx));
for arg_expr in arg_exprs.iter() {
debug!("Argument");
debug!("Argument: {}", arg_expr.repr(tcx));
// ensure that any regions appearing in the argument type are
// valid for at least the lifetime of the function:
constrain_regions_in_type_of_node(
rcx, arg_expr.id, callee_region,
infer::CallArg(arg_expr.span));
type_of_node_must_outlive(
rcx, infer::CallArg(arg_expr.span),
arg_expr.id, callee_region);
// unfortunately, there are two means of taking implicit
// references, and we need to propagate constraints as a
@ -891,19 +1121,14 @@ fn constrain_call(rcx: &mut Rcx,
// as loop above, but for receiver
for r in receiver.iter() {
debug!("Receiver");
constrain_regions_in_type_of_node(
rcx, r.id, callee_region, infer::CallRcvr(r.span));
debug!("receiver: {}", r.repr(tcx));
type_of_node_must_outlive(
rcx, infer::CallRcvr(r.span),
r.id, callee_region);
if implicitly_ref_args {
link_by_ref(rcx, &**r, callee_scope);
}
}
// constrain regions that may appear in the return type to be
// valid for the function call:
constrain_regions_in_type(
rcx, callee_region, infer::CallReturn(call_expr.span),
fn_sig.output);
}
fn constrain_autoderefs(rcx: &mut Rcx,
@ -942,12 +1167,10 @@ fn constrain_autoderefs(rcx: &mut Rcx,
}
// Specialized version of constrain_call.
constrain_regions_in_type(rcx, r_deref_expr,
infer::CallRcvr(deref_expr.span),
self_ty);
constrain_regions_in_type(rcx, r_deref_expr,
infer::CallReturn(deref_expr.span),
fn_sig.output);
type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
self_ty, r_deref_expr);
type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
fn_sig.output, r_deref_expr);
fn_sig.output
}
None => derefd_ty
@ -974,7 +1197,7 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
deref_span: Span,
minimum_lifetime: ty::Region,
maximum_lifetime: ty::Region) {
rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
rcx.fcx.mk_subr(infer::DerefPointer(deref_span),
minimum_lifetime, maximum_lifetime)
}
@ -996,7 +1219,7 @@ fn constrain_index(rcx: &mut Rcx,
match ty::get(indexed_ty).sty {
ty::ty_rptr(r_ptr, mt) => match ty::get(mt.ty).sty {
ty::ty_vec(_, None) | ty::ty_str => {
rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span),
r_index_expr, r_ptr);
}
_ => {}
@ -1006,14 +1229,17 @@ fn constrain_index(rcx: &mut Rcx,
}
}
fn constrain_regions_in_type_of_node(
fn type_of_node_must_outlive(
rcx: &mut Rcx,
origin: infer::SubregionOrigin,
id: ast::NodeId,
minimum_lifetime: ty::Region,
origin: infer::SubregionOrigin) {
//! Guarantees that any lifetimes which appear in the type of
//! the node `id` (after applying adjustments) are valid for at
//! least `minimum_lifetime`
minimum_lifetime: ty::Region)
{
/*!
* Guarantees that any lifetimes which appear in the type of
* the node `id` (after applying adjustments) are valid for at
* least `minimum_lifetime`
*/
let tcx = rcx.fcx.tcx();
@ -1028,54 +1254,7 @@ fn constrain_regions_in_type_of_node(
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
id, minimum_lifetime);
constrain_regions_in_type(rcx, minimum_lifetime, origin, ty);
}
fn constrain_regions_in_type(
rcx: &mut Rcx,
minimum_lifetime: ty::Region,
origin: infer::SubregionOrigin,
ty: ty::t) {
/*!
* Requires that any regions which appear in `ty` must be
* superregions of `minimum_lifetime`. Also enforces the constraint
* that given a pointer type `&'r T`, T must not contain regions
* that outlive 'r, as well as analogous constraints for other
* lifetime'd types.
*
* This check prevents regions from being used outside of the block in
* which they are valid. Recall that regions represent blocks of
* code or expressions: this requirement basically says "any place
* that uses or may use a region R must be within the block of
* code that R corresponds to."
*/
let tcx = rcx.fcx.ccx.tcx;
debug!("constrain_regions_in_type(minimum_lifetime={}, ty={})",
region_to_string(tcx, "", false, minimum_lifetime),
ty_to_string(tcx, ty));
relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
debug!("relate_nested_regions(r_sub={}, r_sup={})",
r_sub.repr(tcx),
r_sup.repr(tcx));
if r_sup.is_bound() || r_sub.is_bound() {
// a bound region is one which appears inside an fn type.
// (e.g., the `&` in `fn(&T)`). Such regions need not be
// constrained by `minimum_lifetime` as they are placeholders
// for regions that are as-yet-unknown.
} else if r_sub == minimum_lifetime {
rcx.fcx.mk_subr(
true, origin.clone(),
r_sub, r_sup);
} else {
rcx.fcx.mk_subr(
true, infer::ReferenceOutlivesReferent(ty, origin.span()),
r_sub, r_sup);
}
});
type_must_outlive(rcx, origin, ty, minimum_lifetime);
}
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
@ -1290,7 +1469,7 @@ fn link_region(rcx: &Rcx,
debug!("link_region: {} <= {}",
region_min.repr(rcx.tcx()),
r_borrowed.repr(rcx.tcx()));
rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
rcx.fcx.mk_subr(cause, region_min, r_borrowed);
if kind != ty::ImmBorrow {
// If this is a mutable borrow, then the thing
@ -1522,3 +1701,99 @@ fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,
}
}
}
fn type_must_outlive(rcx: &mut Rcx,
origin: infer::SubregionOrigin,
ty: ty::t,
region: ty::Region)
{
/*!
* Ensures that all borrowed data reachable via `ty` outlives `region`.
*/
debug!("type_must_outlive(ty={}, region={})",
ty.repr(rcx.tcx()),
region.repr(rcx.tcx()));
let constraints =
regionmanip::region_wf_constraints(
rcx.tcx(),
ty,
region);
for constraint in constraints.iter() {
debug!("constraint: {}", constraint.repr(rcx.tcx()));
match *constraint {
regionmanip::RegionSubRegionConstraint(None, r_a, r_b) => {
rcx.fcx.mk_subr(origin.clone(), r_a, r_b);
}
regionmanip::RegionSubRegionConstraint(Some(ty), r_a, r_b) => {
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
rcx.fcx.mk_subr(o1, r_a, r_b);
}
regionmanip::RegionSubParamConstraint(None, r_a, param_b) => {
param_must_outlive(rcx, origin.clone(), r_a, param_b);
}
regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => {
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
param_must_outlive(rcx, o1, r_a, param_b);
}
}
}
}
fn param_must_outlive(rcx: &Rcx,
origin: infer::SubregionOrigin,
region: ty::Region,
param_ty: ty::ParamTy) {
let param_env = &rcx.fcx.inh.param_env;
debug!("param_must_outlive(region={}, param_ty={})",
region.repr(rcx.tcx()),
param_ty.repr(rcx.tcx()));
// Collect all regions that `param_ty` is known to outlive into
// this vector:
let mut param_bounds;
// To start, collect bounds from user:
let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
param_bounds =
ty::required_region_bounds(rcx.tcx(),
param_bound.opt_region_bound.as_slice(),
param_bound.builtin_bounds,
param_bound.trait_bounds.as_slice());
// Collect default bound of fn body that applies to all in scope
// type parameters:
param_bounds.push(param_env.implicit_region_bound);
// Finally, collect regions we scraped from the well-formedness
// constraints in the fn signature. To do that, we walk the list
// of known relations from the fn ctxt.
//
// This is crucial because otherwise code like this fails:
//
// fn foo<'a, A>(x: &'a A) { x.bar() }
//
// The problem is that the type of `x` is `&'a A`. To be
// well-formed, then, A must be lower-bounded by `'a`, but we
// don't know that this holds from first principles.
for &(ref r, ref p) in rcx.region_param_pairs.iter() {
debug!("param_ty={}/{} p={}/{}",
param_ty.repr(rcx.tcx()),
param_ty.def_id,
p.repr(rcx.tcx()),
p.def_id);
if param_ty == *p {
param_bounds.push(*r);
}
}
// Inform region inference that this parameter type must be
// properly bounded.
infer::verify_param_bound(rcx.fcx.infcx(),
origin,
param_ty,
region,
param_bounds);
}

View File

@ -10,13 +10,15 @@
// #![warn(deprecated_mode)]
use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use syntax::ast;
use std::collections::HashMap;
use util::ppaux::Repr;
use util::ppaux;
// Helper functions related to manipulating region types.
@ -44,125 +46,363 @@ pub fn replace_late_bound_regions_in_fn_sig(
(map, fn_sig)
}
pub fn relate_nested_regions(tcx: &ty::ctxt,
opt_region: Option<ty::Region>,
ty: ty::t,
relate_op: |ty::Region, ty::Region|) {
pub enum WfConstraint {
RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
}
struct Wf<'a> {
tcx: &'a ty::ctxt,
stack: Vec<(ty::Region, Option<ty::t>)>,
out: Vec<WfConstraint>,
}
pub fn region_wf_constraints(
tcx: &ty::ctxt,
ty: ty::t,
outer_region: ty::Region)
-> Vec<WfConstraint>
{
/*!
* This rather specialized function walks each region `r` that appear
* in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
* here is the region of any enclosing `&'r T` pointer. If there is
* no enclosing pointer, and `opt_region` is Some, then `opt_region.get()`
* is used instead. Otherwise, no callback occurs at all).
*
* Here are some examples to give you an intution:
*
* - `relate_nested_regions(Some('r1), &'r2 uint)` invokes
* - `relate_op('r1, 'r2)`
* - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes
* - `relate_op('r1, 'r2)`
* - `relate_op('r2, 'r3)`
* - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes
* - `relate_op('r2, 'r3)`
* - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes
* - `relate_op('r2, 'r3)`
* - `relate_op('r2, 'r4)`
* - `relate_op('r3, 'r4)`
*
* This function is used in various pieces of code because we enforce the
* constraint that a region pointer cannot outlive the things it points at.
* Hence, in the second example above, `'r2` must be a subregion of `'r3`.
* This routine computes the well-formedness constraints that must
* hold for the type `ty` to appear in a context with lifetime
* `outer_region`
*/
let mut rr = RegionRelator { tcx: tcx,
stack: Vec::new(),
relate_op: relate_op };
match opt_region {
Some(o_r) => { rr.stack.push(o_r); }
None => {}
}
rr.fold_ty(ty);
let mut stack = Vec::new();
stack.push((outer_region, None));
let mut wf = Wf { tcx: tcx,
stack: stack,
out: Vec::new() };
wf.accumulate_from_ty(ty);
wf.out
}
struct RegionRelator<'a> {
tcx: &'a ty::ctxt,
stack: Vec<ty::Region>,
relate_op: |ty::Region, ty::Region|: 'a,
}
impl<'a> Wf<'a> {
fn accumulate_from_ty(&mut self, ty: ty::t) {
debug!("Wf::accumulate_from_ty(ty={})",
ty.repr(self.tcx));
// FIXME(#10151) -- Define more precisely when a region is
// considered "nested". Consider taking variance into account as
// well.
match ty::get(ty).sty {
ty::ty_nil |
ty::ty_bot |
ty::ty_bool |
ty::ty_char |
ty::ty_int(..) |
ty::ty_uint(..) |
ty::ty_float(..) |
ty::ty_bare_fn(..) |
ty::ty_err |
ty::ty_str => {
// No borrowed content reachable here.
}
impl<'a> TypeFolder for RegionRelator<'a> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
self.tcx
ty::ty_closure(box ref c) => {
self.accumulate_from_closure_ty(ty, c);
}
ty::ty_unboxed_closure(_, region) => {
// An "unboxed closure type" is basically
// modeled here as equivalent to a struct like
//
// struct TheClosure<'b> {
// ...
// }
//
// where the `'b` is the lifetime bound of the
// contents (i.e., all contents must outlive 'b).
self.push_region_constraint_from_top(region);
}
ty::ty_trait(ref t) => {
self.accumulate_from_object_ty(ty, &t.bounds)
}
ty::ty_enum(def_id, ref substs) |
ty::ty_struct(def_id, ref substs) => {
self.accumulate_from_adt(ty, def_id, substs)
}
ty::ty_vec(t, _) |
ty::ty_ptr(ty::mt { ty: t, .. }) |
ty::ty_box(t) |
ty::ty_uniq(t) => {
self.accumulate_from_ty(t)
}
ty::ty_rptr(r_b, mt) => {
self.accumulate_from_rptr(ty, r_b, mt.ty);
}
ty::ty_param(p) => {
self.push_param_constraint_from_top(p);
}
ty::ty_tup(ref tuptys) => {
for &tupty in tuptys.iter() {
self.accumulate_from_ty(tupty);
}
}
ty::ty_infer(_) => {
// This should not happen, BUT:
//
// Currently we uncover region relationships on
// entering the fn check. We should do this after
// the fn check, then we can call this case a bug().
}
ty::ty_open(_) => {
self.tcx.sess.bug(
format!("Unexpected type encountered while doing wf check: {}",
ty.repr(self.tcx)).as_slice());
}
}
}
fn fold_ty(&mut self, ty: ty::t) -> ty::t {
match ty::get(ty).sty {
ty::ty_rptr(r, ty::mt {ty, ..}) => {
self.relate(r);
self.stack.push(r);
ty_fold::super_fold_ty(self, ty);
fn accumulate_from_rptr(&mut self,
ty: ty::t,
r_b: ty::Region,
ty_b: ty::t) {
// We are walking down a type like this, and current
// position is indicated by caret:
//
// &'a &'b ty_b
// ^
//
// At this point, top of stack will be `'a`. We must
// require that `'a <= 'b`.
self.push_region_constraint_from_top(r_b);
// Now we push `'b` onto the stack, because it must
// constrain any borrowed content we find within `T`.
self.stack.push((r_b, Some(ty)));
self.accumulate_from_ty(ty_b);
self.stack.pop().unwrap();
}
fn push_region_constraint_from_top(&mut self,
r_b: ty::Region) {
/*!
* Pushes a constraint that `r_b` must outlive the
* top region on the stack.
*/
// Indicates that we have found borrowed content with a lifetime
// of at least `r_b`. This adds a constraint that `r_b` must
// outlive the region `r_a` on top of the stack.
//
// As an example, imagine walking a type like:
//
// &'a &'b T
// ^
//
// when we hit the inner pointer (indicated by caret), `'a` will
// be on top of stack and `'b` will be the lifetime of the content
// we just found. So we add constraint that `'a <= 'b`.
let &(r_a, opt_ty) = self.stack.last().unwrap();
self.push_sub_region_constraint(opt_ty, r_a, r_b);
}
fn push_sub_region_constraint(&mut self,
opt_ty: Option<ty::t>,
r_a: ty::Region,
r_b: ty::Region) {
/*! Pushes a constraint that `r_a <= r_b`, due to `opt_ty` */
self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
}
fn push_param_constraint_from_top(&mut self,
param_ty: ty::ParamTy) {
/*!
* Pushes a constraint that `param_ty` must outlive the
* top region on the stack.
*/
let &(region, opt_ty) = self.stack.last().unwrap();
self.push_param_constraint(region, opt_ty, param_ty);
}
fn push_param_constraint(&mut self,
region: ty::Region,
opt_ty: Option<ty::t>,
param_ty: ty::ParamTy) {
/*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */
self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
}
fn accumulate_from_adt(&mut self,
ty: ty::t,
def_id: ast::DefId,
substs: &Substs)
{
// The generic declarations from the type, appropriately
// substituted for the actual substitutions.
let generics =
ty::lookup_item_type(self.tcx, def_id)
.generics
.subst(self.tcx, substs);
// Variance of each type/region parameter.
let variances = ty::item_variances(self.tcx, def_id);
for &space in ParamSpace::all().iter() {
let region_params = substs.regions().get_slice(space);
let region_variances = variances.regions.get_slice(space);
let region_param_defs = generics.regions.get_slice(space);
assert_eq!(region_params.len(), region_variances.len());
for (&region_param, (&region_variance, region_param_def)) in
region_params.iter().zip(
region_variances.iter().zip(
region_param_defs.iter()))
{
match region_variance {
ty::Covariant | ty::Bivariant => {
// Ignore covariant or bivariant region
// parameters. To understand why, consider a
// struct `Foo<'a>`. If `Foo` contains any
// references with lifetime `'a`, then `'a` must
// be at least contravariant (and possibly
// invariant). The only way to have a covariant
// result is if `Foo` contains only a field with a
// type like `fn() -> &'a T`; i.e., a bare
// function that can produce a reference of
// lifetime `'a`. In this case, there is no
// *actual data* with lifetime `'a` that is
// reachable. (Presumably this bare function is
// really returning static data.)
}
ty::Contravariant | ty::Invariant => {
// If the parameter is contravariant or
// invariant, there may indeed be reachable
// data with this lifetime. See other case for
// more details.
self.push_region_constraint_from_top(region_param);
}
}
for &region_bound in region_param_def.bounds.iter() {
// The type declared a constraint like
//
// 'b : 'a
//
// which means that `'a <= 'b` (after
// substitution). So take the region we
// substituted for `'a` (`region_bound`) and make
// it a subregion of the region we substituted
// `'b` (`region_param`).
self.push_sub_region_constraint(
Some(ty), region_bound, region_param);
}
}
let types = substs.types.get_slice(space);
let type_variances = variances.types.get_slice(space);
let type_param_defs = generics.types.get_slice(space);
assert_eq!(types.len(), type_variances.len());
for (&type_param_ty, (&variance, type_param_def)) in
types.iter().zip(
type_variances.iter().zip(
type_param_defs.iter()))
{
debug!("type_param_ty={} variance={}",
type_param_ty.repr(self.tcx),
variance.repr(self.tcx));
match variance {
ty::Contravariant | ty::Bivariant => {
// As above, except that in this it is a
// *contravariant* reference that indices that no
// actual data of type T is reachable.
}
ty::Covariant | ty::Invariant => {
self.accumulate_from_ty(type_param_ty);
}
}
// Inspect bounds on this type parameter for any
// region bounds.
for &r in type_param_def.bounds.opt_region_bound.iter() {
self.stack.push((r, Some(ty)));
self.accumulate_from_ty(type_param_ty);
self.stack.pop().unwrap();
}
_ => {
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");
}

View File

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

View File

@ -42,47 +42,31 @@ use middle::ty::{Polytype};
use middle::ty;
use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::{AstConv, ty_of_arg};
use middle::typeck::astconv::{ast_ty_to_ty};
use middle::typeck::astconv::{ast_ty_to_ty, ast_region_to_region};
use middle::typeck::astconv;
use middle::typeck::infer;
use middle::typeck::rscope::*;
use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
use middle::typeck;
use util::ppaux;
use util::ppaux::Repr;
use util::ppaux::{Repr,UserString};
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::gc::Gc;
use syntax::abi;
use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound};
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod};
use syntax::codemap::Span;
use syntax::codemap;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::special_idents;
use syntax::parse::token::{special_idents};
use syntax::parse::token;
use syntax::print::pprust::{path_to_string};
use syntax::visit;
struct CollectItemTypesVisitor<'a> {
ccx: &'a CrateCtxt<'a>
}
impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
convert(self.ccx, i);
visit::walk_item(self, i, ());
}
fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
convert_foreign(self.ccx, i);
visit::walk_foreign_item(self, i, ());
}
}
///////////////////////////////////////////////////////////////////////////
// Main entry point
pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
fn collect_intrinsic_type(ccx: &CrateCtxt,
@ -99,10 +83,57 @@ pub fn collect_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
}
let mut visitor = CollectTraitDefVisitor{ ccx: ccx };
visit::walk_crate(&mut visitor, krate, ());
let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
visit::walk_crate(&mut visitor, krate, ());
}
///////////////////////////////////////////////////////////////////////////
// First phase: just collect *trait definitions* -- basically, the set
// of type parameters and supertraits. This is information we need to
// know later when parsing field defs.
struct CollectTraitDefVisitor<'a> {
ccx: &'a CrateCtxt<'a>
}
impl<'a> visit::Visitor<()> for CollectTraitDefVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
match i.node {
ast::ItemTrait(..) => {
// computing the trait def also fills in the table
let _ = trait_def_of_item(self.ccx, i);
}
_ => { }
}
visit::walk_item(self, i, ());
}
}
///////////////////////////////////////////////////////////////////////////
// Second phase: collection proper.
struct CollectItemTypesVisitor<'a> {
ccx: &'a CrateCtxt<'a>
}
impl<'a> visit::Visitor<()> for CollectItemTypesVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
convert(self.ccx, i);
visit::walk_item(self, i, ());
}
fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
convert_foreign(self.ccx, i);
visit::walk_foreign_item(self, i, ());
}
}
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
pub trait ToTy {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> ty::t;
}
@ -193,9 +224,9 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
}
}
pub fn ensure_trait_methods(ccx: &CrateCtxt,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef) {
fn collect_trait_methods(ccx: &CrateCtxt,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef) {
let tcx = ccx.tcx;
match tcx.map.get(trait_id) {
ast_map::NodeItem(item) => {
@ -360,7 +391,13 @@ fn convert_methods(ccx: &CrateCtxt,
ms: &[Gc<ast::Method>],
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility) {
rcvr_visibility: ast::Visibility)
{
debug!("convert_methods(untransformed_rcvr_ty={}, \
rcvr_ty_generics={})",
untransformed_rcvr_ty.repr(ccx.tcx),
rcvr_ty_generics.repr(ccx.tcx));
let tcx = ccx.tcx;
let mut seen_methods = HashSet::new();
for m in ms.iter() {
@ -388,6 +425,9 @@ fn convert_methods(ccx: &CrateCtxt,
write_ty_to_tcx(tcx, m.id, fty);
debug!("writing method type: def_id={} mty={}",
mty.def_id, mty.repr(ccx.tcx));
tcx.impl_or_trait_items
.borrow_mut()
.insert(mty.def_id, ty::MethodTraitItem(mty));
@ -448,9 +488,20 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
generics: &ast::Generics,
thing: &'static str) {
for ty_param in generics.ty_params.iter() {
if ty_param.bounds.len() > 0 {
span_err!(ccx.tcx.sess, span, E0122,
"trait bounds are not allowed in {} definitions", thing);
for bound in ty_param.bounds.iter() {
match *bound {
ast::TraitTyParamBound(..) | ast::UnboxedFnTyParamBound(..) => {
// According to accepted RFC #XXX, we should
// eventually accept these, but it will not be
// part of this PR. Still, convert to warning to
// make bootstrapping easier.
span_warn!(ccx.tcx.sess, span, E0122,
"trait bounds are not (yet) enforced \
in {} definitions",
thing);
}
ast::RegionTyParamBound(..) => { }
}
}
}
}
@ -520,6 +571,10 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
ast::ItemTrait(_, _, _, ref trait_methods) => {
let trait_def = trait_def_of_item(ccx, it);
debug!("trait_def: ident={} trait_def={}",
it.ident.repr(ccx.tcx),
trait_def.repr(ccx.tcx()));
for trait_method in trait_methods.iter() {
let self_type = ty::mk_param(ccx.tcx,
subst::SelfSpace,
@ -556,7 +611,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
// We need to do this *after* converting methods, since
// convert_methods produces a tcache entry that is wrong for
// static trait methods. This is somewhat unfortunate.
ensure_trait_methods(ccx, it.id, &*trait_def);
collect_trait_methods(ccx, it.id, &*trait_def);
},
ast::ItemStruct(struct_def, _) => {
// Write the class type.
@ -739,6 +794,19 @@ pub fn instantiate_trait_ref(ccx: &CrateCtxt,
}
}
pub fn instantiate_unboxed_fn_ty(ccx: &CrateCtxt,
unboxed_function: &ast::UnboxedFnTy,
param_ty: ty::ParamTy)
-> Rc<ty::TraitRef>
{
let rscope = ExplicitRscope;
let param_ty = param_ty.to_ty(ccx.tcx);
Rc::new(astconv::trait_ref_for_unboxed_function(ccx,
&rscope,
unboxed_function,
Some(param_ty)))
}
fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
if trait_id.krate != ast::LOCAL_CRATE {
return ty::lookup_trait_def(ccx.tcx, trait_id)
@ -761,9 +829,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
_ => {}
}
let (generics, unbound, supertraits) = match it.node {
ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => {
(generics, unbound, supertraits)
let (generics, unbound, bounds) = match it.node {
ast::ItemTrait(ref generics, ref unbound, ref bounds, _) => {
(generics, unbound, bounds)
}
ref s => {
tcx.sess.span_bug(
@ -779,13 +847,16 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
&substs,
generics);
let builtin_bounds =
ensure_supertraits(ccx, it.id, it.span, supertraits, unbound);
let self_param_ty = ty::ParamTy::for_self(def_id);
let bounds = compute_bounds(ccx, token::SELF_KEYWORD_NAME, self_param_ty,
bounds.as_slice(), unbound, it.span,
&generics.where_clause);
let substs = mk_item_substs(ccx, &ty_generics);
let trait_def = Rc::new(ty::TraitDef {
generics: ty_generics,
bounds: builtin_bounds,
bounds: bounds,
trait_ref: Rc::new(ty::TraitRef {
def_id: def_id,
substs: substs
@ -824,55 +895,6 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
subst::Substs::new_trait(types, regions, self_ty)
}
fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::NodeId,
sp: codemap::Span,
ast_trait_refs: &Vec<ast::TraitRef>,
unbound: &Option<ast::TyParamBound>)
-> ty::BuiltinBounds
{
let tcx = ccx.tcx;
// Called only the first time trait_def_of_item is called.
// Supertraits are ensured at the same time.
assert!(!tcx.supertraits.borrow().contains_key(&local_def(id)));
let self_ty = ty::mk_self_type(ccx.tcx, local_def(id));
let mut ty_trait_refs: Vec<Rc<ty::TraitRef>> = Vec::new();
let mut bounds = ty::empty_builtin_bounds();
for ast_trait_ref in ast_trait_refs.iter() {
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, ast_trait_ref);
// FIXME(#8559): Need to instantiate the trait_ref whether
// or not it's a builtin trait, so that the trait's node
// id appears in the tcx trait_ref map. This is only
// needed for metadata; see the similar fixme in
// encoder.rs.
let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, self_ty);
if !ty::try_add_builtin_trait(ccx.tcx, trait_def_id, &mut bounds) {
// FIXME(#5527) Could have same trait multiple times
if ty_trait_refs.iter().any(
|other_trait| other_trait.def_id == trait_ref.def_id)
{
// This means a trait inherited from the same
// supertrait more than once.
span_err!(tcx.sess, sp, E0127,
"duplicate supertrait in trait declaration");
break;
} else {
ty_trait_refs.push(trait_ref);
}
}
}
add_unsized_bound(ccx, unbound, &mut bounds, "trait", sp);
tcx.supertraits.borrow_mut().insert(local_def(id),
Rc::new(ty_trait_refs));
bounds
}
}
pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
@ -984,11 +1006,12 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
fn ty_generics_for_type(ccx: &CrateCtxt,
generics: &ast::Generics)
-> ty::Generics {
-> ty::Generics
{
ty_generics(ccx,
subst::TypeSpace,
&generics.lifetimes,
&generics.ty_params,
generics.lifetimes.as_slice(),
generics.ty_params.as_slice(),
ty::Generics::empty(),
&generics.where_clause)
}
@ -1000,8 +1023,8 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
-> ty::Generics {
let mut generics = ty_generics(ccx,
subst::TypeSpace,
&generics.lifetimes,
&generics.ty_params,
generics.lifetimes.as_slice(),
generics.ty_params.as_slice(),
ty::Generics::empty(),
&generics.where_clause);
@ -1018,10 +1041,11 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
index: 0,
ident: special_idents::type_self,
def_id: local_def(param_id),
bounds: Rc::new(ty::ParamBounds {
bounds: ty::ParamBounds {
opt_region_bound: None,
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: vec!(self_trait_ref),
}),
},
default: None
};
@ -1039,8 +1063,8 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
ty_generics(ccx,
subst::FnSpace,
&early_lifetimes,
&generics.ty_params,
early_lifetimes.as_slice(),
generics.ty_params.as_slice(),
base_generics,
&generics.where_clause)
}
@ -1053,7 +1077,7 @@ fn add_unsized_bound(ccx: &CrateCtxt,
span: Span) {
let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
match unbound {
&Some(TraitTyParamBound(ref tpb)) => {
&Some(ast::TraitTyParamBound(ref tpb)) => {
// #FIXME(8559) currently requires the unbound to be built-in.
let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
match kind_id {
@ -1084,18 +1108,23 @@ fn add_unsized_bound(ccx: &CrateCtxt,
fn ty_generics(ccx: &CrateCtxt,
space: subst::ParamSpace,
lifetimes: &Vec<ast::LifetimeDef>,
types: &OwnedSlice<ast::TyParam>,
lifetime_defs: &[ast::LifetimeDef],
types: &[ast::TyParam],
base_generics: ty::Generics,
where_clause: &ast::WhereClause)
-> ty::Generics {
-> ty::Generics
{
let mut result = base_generics;
for (i, l) in lifetimes.iter().enumerate() {
for (i, l) in lifetime_defs.iter().enumerate() {
let bounds = l.bounds.iter()
.map(|l| ast_region_to_region(ccx.tcx, l))
.collect();
let def = ty::RegionParameterDef { name: l.lifetime.name,
space: space,
index: i,
def_id: local_def(l.lifetime.id) };
def_id: local_def(l.lifetime.id),
bounds: bounds };
debug!("ty_generics: def for region param: {}", def);
result.regions.push(space, def);
}
@ -1123,19 +1152,17 @@ fn ty_generics(ccx: &CrateCtxt,
None => { }
}
let param_ty = ty::ParamTy {space: space,
idx: index,
def_id: local_def(param.id)};
let bounds = Rc::new(compute_bounds(ccx,
param_ty,
&param.bounds,
&param.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(),
&param.unbound,
param.span,
where_clause);
let default = param.default.map(|path| {
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
let cur_idx = param_ty.idx;
let cur_idx = index;
ty::walk_ty(ty, |t| {
match ty::get(t).sty {
@ -1164,130 +1191,139 @@ fn ty_generics(ccx: &CrateCtxt,
def
}
}
fn compute_bounds(ccx: &CrateCtxt,
param_ty: ty::ParamTy,
ast_bounds: &OwnedSlice<ast::TyParamBound>,
unbound: &Option<ast::TyParamBound>,
ident: ast::Ident,
span: Span,
where_clause: &ast::WhereClause)
-> ty::ParamBounds {
/*!
* Translate the AST's notion of ty param bounds (which are an
* enum consisting of a newtyped Ty or a region) to ty's
* notion of ty param bounds, which can either be user-defined
* traits, or the built-in trait (formerly known as kind): Send.
*/
fn compute_bounds(
ccx: &CrateCtxt,
name_of_bounded_thing: ast::Name,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TyParamBound>,
span: Span,
where_clause: &ast::WhereClause)
-> ty::ParamBounds
{
/*!
* Translate the AST's notion of ty param bounds (which are an
* enum consisting of a newtyped Ty or a region) to ty's
* notion of ty param bounds, which can either be user-defined
* traits, or the built-in trait (formerly known as kind): Send.
*/
let mut param_bounds = ty::ParamBounds {
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: Vec::new()
};
for ast_bound in ast_bounds.iter() {
compute_bound(ccx, &mut param_bounds, param_ty, ast_bound);
}
for predicate in where_clause.predicates.iter() {
let predicate_param_id = ccx.tcx
.def_map
.borrow()
.find(&predicate.id)
.expect("compute_bounds(): resolve \
didn't resolve the type \
parameter identifier in a \
`where` clause")
.def_id();
if param_ty.def_id != predicate_param_id {
continue
}
for bound in predicate.bounds.iter() {
compute_bound(ccx, &mut param_bounds, param_ty, bound);
}
}
let mut param_bounds = conv_param_bounds(ccx,
span,
param_ty,
ast_bounds,
where_clause);
add_unsized_bound(ccx,
unbound,
&mut param_bounds.builtin_bounds,
"type parameter",
span);
check_bounds_compatible(ccx.tcx, &param_bounds, ident, span);
add_unsized_bound(ccx,
unbound,
&mut param_bounds.builtin_bounds,
"type parameter",
span);
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
check_bounds_compatible(ccx.tcx, name_of_bounded_thing,
&param_bounds, span);
param_bounds
}
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
/// Translates the AST's notion of a type parameter bound to
/// typechecking's notion of the same, and pushes the resulting bound onto
/// the appropriate section of `param_bounds`.
fn compute_bound(ccx: &CrateCtxt,
param_bounds: &mut ty::ParamBounds,
param_ty: ty::ParamTy,
ast_bound: &ast::TyParamBound) {
match *ast_bound {
TraitTyParamBound(ref b) => {
let ty = ty::mk_param(ccx.tcx, param_ty.space,
param_ty.idx, param_ty.def_id);
let trait_ref = instantiate_trait_ref(ccx, b, ty);
if !ty::try_add_builtin_trait(
ccx.tcx, trait_ref.def_id,
&mut param_bounds.builtin_bounds) {
// Must be a user-defined trait
param_bounds.trait_bounds.push(trait_ref);
}
}
param_bounds
}
StaticRegionTyParamBound => {
param_bounds.builtin_bounds.add(ty::BoundStatic);
}
UnboxedFnTyParamBound(ref unboxed_function) => {
let rscope = ExplicitRscope;
let self_ty = ty::mk_param(ccx.tcx,
param_ty.space,
param_ty.idx,
param_ty.def_id);
let trait_ref =
astconv::trait_ref_for_unboxed_function(ccx,
&rscope,
unboxed_function,
Some(self_ty));
param_bounds.trait_bounds.push(Rc::new(trait_ref));
}
OtherRegionTyParamBound(span) => {
if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
ccx.tcx.sess.span_err(
span,
"only the 'static lifetime is accepted here.");
}
}
}
}
fn check_bounds_compatible(tcx: &ty::ctxt,
param_bounds: &ty::ParamBounds,
ident: ast::Ident,
span: Span) {
// Currently the only bound which is incompatible with other bounds is
// Sized/Unsized.
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
ty::each_bound_trait_and_supertraits(tcx,
param_bounds.trait_bounds.as_slice(),
|trait_ref| {
fn check_bounds_compatible(tcx: &ty::ctxt,
name_of_bounded_thing: ast::Name,
param_bounds: &ty::ParamBounds,
span: Span) {
// Currently the only bound which is incompatible with other bounds is
// Sized/Unsized.
if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
ty::each_bound_trait_and_supertraits(
tcx,
param_bounds.trait_bounds.as_slice(),
|trait_ref| {
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
if trait_def.bounds.contains_elem(ty::BoundSized) {
if trait_def.bounds.builtin_bounds.contains_elem(ty::BoundSized) {
span_err!(tcx.sess, span, E0129,
"incompatible bounds on type parameter {}, \
bound {} does not allow unsized type",
token::get_ident(ident),
"incompatible bounds on type parameter `{}`, \
bound `{}` does not allow unsized type",
name_of_bounded_thing.user_string(tcx),
ppaux::trait_ref_to_string(tcx, &*trait_ref));
}
true
});
}
}
fn conv_param_bounds(ccx: &CrateCtxt,
span: Span,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
-> ty::ParamBounds
{
let all_bounds =
merge_param_bounds(ccx, param_ty, ast_bounds, where_clause);
let astconv::PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds,
unboxed_fn_ty_bounds } =
astconv::partition_bounds(ccx.tcx, span, all_bounds.as_slice());
let unboxed_fn_ty_bounds =
unboxed_fn_ty_bounds.move_iter()
.map(|b| instantiate_unboxed_fn_ty(ccx, b, param_ty));
let trait_bounds: Vec<Rc<ty::TraitRef>> =
trait_bounds.move_iter()
.map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
.chain(unboxed_fn_ty_bounds)
.collect();
let opt_region_bound =
astconv::compute_opt_region_bound(
ccx.tcx, span, builtin_bounds, region_bounds.as_slice(),
trait_bounds.as_slice());
ty::ParamBounds {
opt_region_bound: opt_region_bound,
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
}
}
fn merge_param_bounds<'a>(ccx: &CrateCtxt,
param_ty: ty::ParamTy,
ast_bounds: &'a [ast::TyParamBound],
where_clause: &'a ast::WhereClause)
-> Vec<&'a ast::TyParamBound>
{
/*!
* Merges the bounds declared on a type parameter with those
* found from where clauses into a single list.
*/
let mut result = Vec::new();
for ast_bound in ast_bounds.iter() {
result.push(ast_bound);
}
for predicate in where_clause.predicates.iter() {
let predicate_param_id = ccx.tcx
.def_map
.borrow()
.find(&predicate.id)
.expect("compute_bounds(): resolve \
didn't resolve the type \
parameter identifier in a \
`where` clause")
.def_id();
if param_ty.def_id != predicate_param_id {
continue
}
for bound in predicate.bounds.iter() {
result.push(bound);
}
}
result
}
pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,

View File

@ -221,7 +221,7 @@ pub trait Combine {
};
let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
let bounds = if_ok!(self.existential_bounds(a.bounds, b.bounds));
let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
let abi = if_ok!(self.abi(a.abi, b.abi));
Ok(ty::ClosureTy {
@ -251,9 +251,26 @@ pub trait Combine {
}
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>;
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>;
fn existential_bounds(&self,
a: ty::ExistentialBounds,
b: ty::ExistentialBounds)
-> cres<ty::ExistentialBounds>
{
let r = try!(self.contraregions(a.region_bound, b.region_bound));
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
Ok(ty::ExistentialBounds { region_bound: r,
builtin_bounds: nb })
}
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<ty::BuiltinBounds>;
fn contraregions(&self, a: ty::Region, b: ty::Region)
-> cres<ty::Region>;
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>;
fn trait_stores(&self,
@ -479,7 +496,7 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
if a_.def_id == b_.def_id => {
debug!("Trying to match traits {:?} and {:?}", a, b);
let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
let bounds = if_ok!(this.bounds(a_.bounds, b_.bounds));
let bounds = if_ok!(this.existential_bounds(a_.bounds, b_.bounds));
Ok(ty::mk_trait(tcx,
a_.def_id,
substs.clone(),

View File

@ -75,6 +75,7 @@ use middle::typeck::infer::region_inference::RegionResolutionError;
use middle::typeck::infer::region_inference::ConcreteFailure;
use middle::typeck::infer::region_inference::SubSupConflict;
use middle::typeck::infer::region_inference::SupSupConflict;
use middle::typeck::infer::region_inference::ParamBoundFailure;
use middle::typeck::infer::region_inference::ProcessedErrors;
use middle::typeck::infer::region_inference::SameRegions;
use std::cell::{Cell, RefCell};
@ -89,10 +90,13 @@ use syntax::owned_slice::OwnedSlice;
use syntax::codemap;
use syntax::parse::token;
use syntax::print::pprust;
use util::ppaux::UserString;
use util::ppaux::bound_region_to_string;
use util::ppaux::note_and_explain_region;
// Note: only import UserString, not Repr, since user-facing error
// messages shouldn't include debug serializations.
use util::ppaux::UserString;
pub trait ErrorReporting {
fn report_region_errors(&self,
errors: &Vec<RegionResolutionError>);
@ -118,6 +122,12 @@ pub trait ErrorReporting {
sub: Region,
sup: Region);
fn report_param_bound_failure(&self,
origin: SubregionOrigin,
param_ty: ty::ParamTy,
sub: Region,
sups: Vec<Region>);
fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
sub_origin: SubregionOrigin,
@ -145,7 +155,7 @@ trait ErrorReportingHelpers {
var_origin: RegionVariableOrigin);
fn note_region_origin(&self,
origin: SubregionOrigin);
origin: &SubregionOrigin);
fn give_expl_lifetime_param(&self,
decl: &ast::FnDecl,
@ -167,6 +177,10 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
self.report_concrete_failure(origin, sub, sup);
}
ParamBoundFailure(origin, param_ty, sub, sups) => {
self.report_param_bound_failure(origin, param_ty, sub, sups);
}
SubSupConflict(var_origin,
sub_origin, sub_r,
sup_origin, sup_r) => {
@ -410,6 +424,62 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
found.user_string(self.tcx)))
}
fn report_param_bound_failure(&self,
origin: SubregionOrigin,
param_ty: ty::ParamTy,
sub: Region,
_sups: Vec<Region>) {
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily
// accessible.
match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough; \
consider adding an explicit lifetime bound `{}:{}`...",
param_ty.user_string(self.tcx),
param_ty.user_string(self.tcx),
sub.user_string(self.tcx)).as_slice());
}
ty::ReStatic => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough; \
consider adding an explicit lifetime bound `{}:'static`...",
param_ty.user_string(self.tcx),
param_ty.user_string(self.tcx)).as_slice());
}
_ => {
// If not, be less specific.
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough; \
consider adding an explicit lifetime bound to `{}`",
param_ty.user_string(self.tcx),
param_ty.user_string(self.tcx)).as_slice());
note_and_explain_region(
self.tcx,
format!("the parameter type `{}` must be valid for ",
param_ty.user_string(self.tcx)).as_slice(),
sub,
"...");
}
}
self.note_region_origin(&origin);
}
fn report_concrete_failure(&self,
origin: SubregionOrigin,
sub: Region,
@ -538,6 +608,67 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
sup,
"");
}
infer::RelateProcBound(span, var_node_id, ty) => {
self.tcx.sess.span_err(
span,
format!(
"the type `{}` of captured variable `{}` \
outlives the `proc()` it \
is captured in",
self.ty_to_string(ty),
ty::local_var_name_str(self.tcx,
var_node_id)).as_slice());
note_and_explain_region(
self.tcx,
"`proc()` is valid for ",
sub,
"");
note_and_explain_region(
self.tcx,
format!("the type `{}` is only valid for ",
self.ty_to_string(ty)).as_slice(),
sup,
"");
}
infer::RelateParamBound(span, param_ty, ty) => {
self.tcx.sess.span_err(
span,
format!("the type `{}` (provided as the value of \
the parameter `{}`) does not fulfill the \
required lifetime",
self.ty_to_string(ty),
param_ty.user_string(self.tcx)).as_slice());
note_and_explain_region(self.tcx,
"type must outlive ",
sub,
"");
}
infer::RelateRegionParamBound(span) => {
self.tcx.sess.span_err(
span,
"declared lifetime bound not satisfied");
note_and_explain_region(
self.tcx,
"lifetime parameter instantiated with ",
sup,
"");
note_and_explain_region(
self.tcx,
"but lifetime parameter must outlive ",
sub,
"");
}
infer::RelateDefaultParamBound(span, ty) => {
self.tcx.sess.span_err(
span,
format!("the type `{}` (provided as the value of \
a type parameter) is not valid at this point",
self.ty_to_string(ty)).as_slice());
note_and_explain_region(self.tcx,
"type must outlive ",
sub,
"");
}
infer::CallRcvr(span) => {
self.tcx.sess.span_err(
span,
@ -593,6 +724,18 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
sup,
"");
}
infer::ExprTypeIsNotInScope(t, span) => {
self.tcx.sess.span_err(
span,
format!("type of expression contains references \
that are not valid during the expression: `{}`",
self.ty_to_string(t)).as_slice());
note_and_explain_region(
self.tcx,
"type is only valid for ",
sup,
"");
}
infer::BindingTypeIsNotValidAtDecl(span) => {
self.tcx.sess.span_err(
span,
@ -606,9 +749,9 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
infer::ReferenceOutlivesReferent(ty, span) => {
self.tcx.sess.span_err(
span,
format!("in type `{}`, pointer has a longer lifetime than \
the data it references",
ty.user_string(self.tcx)).as_slice());
format!("in type `{}`, reference has a longer lifetime \
than the data it references",
self.ty_to_string(ty)).as_slice());
note_and_explain_region(
self.tcx,
"the pointer is valid for ",
@ -620,6 +763,11 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
sup,
"");
}
infer::Managed(span) => {
self.tcx.sess.span_err(
span,
format!("cannot put borrowed references into managed memory").as_slice());
}
}
}
@ -637,7 +785,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
sup_region,
"...");
self.note_region_origin(sup_origin);
self.note_region_origin(&sup_origin);
note_and_explain_region(
self.tcx,
@ -645,7 +793,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
sub_region,
"...");
self.note_region_origin(sub_origin);
self.note_region_origin(&sub_origin);
}
fn report_sup_sup_conflict(&self,
@ -662,7 +810,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
region1,
"...");
self.note_region_origin(origin1);
self.note_region_origin(&origin1);
note_and_explain_region(
self.tcx,
@ -670,7 +818,7 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
region2,
"...");
self.note_region_origin(origin2);
self.note_region_origin(&origin2);
}
fn report_processed_errors(&self,
@ -920,8 +1068,12 @@ impl<'a> Rebuilder<'a> {
-> OwnedSlice<ast::TyParamBound> {
ty_param_bounds.map(|tpb| {
match tpb {
&ast::StaticRegionTyParamBound => ast::StaticRegionTyParamBound,
&ast::OtherRegionTyParamBound(s) => ast::OtherRegionTyParamBound(s),
&ast::RegionTyParamBound(lt) => {
// FIXME -- it's unclear whether I'm supposed to
// substitute lifetime here. I suspect we need to
// be passing down a map.
ast::RegionTyParamBound(lt)
}
&ast::UnboxedFnTyParamBound(unboxed_function_type) => {
ast::UnboxedFnTyParamBound(unboxed_function_type)
}
@ -1291,8 +1443,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
var_description).as_slice());
}
fn note_region_origin(&self, origin: SubregionOrigin) {
match origin {
fn note_region_origin(&self, origin: &SubregionOrigin) {
match *origin {
infer::Subtype(ref trace) => {
let desc = match trace.origin {
infer::Misc(_) => {
@ -1384,8 +1536,16 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
infer::RelateObjectBound(span) => {
self.tcx.sess.span_note(
span,
"...so that source pointer does not outlive \
lifetime bound of the object type");
"...so that it can be closed over into an object");
}
infer::RelateProcBound(span, var_node_id, _ty) => {
self.tcx.sess.span_err(
span,
format!(
"...so that the variable `{}` can be captured \
into a proc",
ty::local_var_name_str(self.tcx,
var_node_id)).as_slice());
}
infer::CallRcvr(span) => {
self.tcx.sess.span_note(
@ -1414,16 +1574,52 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
"...so that reference is valid \
at the time of implicit borrow");
}
infer::ExprTypeIsNotInScope(t, span) => {
self.tcx.sess.span_note(
span,
format!("...so type `{}` of expression is valid during the \
expression",
self.ty_to_string(t)).as_slice());
}
infer::BindingTypeIsNotValidAtDecl(span) => {
self.tcx.sess.span_note(
span,
"...so that variable is valid at time of its declaration");
}
infer::ReferenceOutlivesReferent(_, span) => {
infer::ReferenceOutlivesReferent(ty, span) => {
self.tcx.sess.span_note(
span,
"...so that the pointer does not outlive the \
data it points at");
format!("...so that the reference type `{}` \
does not outlive the data it points at",
self.ty_to_string(ty)).as_slice());
}
infer::Managed(span) => {
self.tcx.sess.span_note(
span,
"...so that the value can be stored in managed memory.");
}
infer::RelateParamBound(span, param_ty, t) => {
self.tcx.sess.span_note(
span,
format!("...so that the parameter `{}`, \
when instantiated with `{}`, \
will meet its declared lifetime bounds.",
param_ty.user_string(self.tcx),
self.ty_to_string(t)).as_slice());
}
infer::RelateDefaultParamBound(span, t) => {
self.tcx.sess.span_note(
span,
format!("...so that type parameter \
instantiated with `{}`, \
will meet its declared lifetime bounds.",
self.ty_to_string(t)).as_slice());
}
infer::RelateRegionParamBound(span) => {
self.tcx.sess.span_note(
span,
format!("...so that the declared lifetime parameter bounds \
are satisfied").as_slice());
}
}
}

View File

@ -96,7 +96,10 @@ impl<'f> Combine for Glb<'f> {
}
}
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<ty::BuiltinBounds> {
// More bounds is a subtype of fewer bounds, so
// the GLB (mutual subtype) is the union.
Ok(a.union(b))

View File

@ -90,7 +90,10 @@ impl<'f> Combine for Lub<'f> {
}
}
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<ty::BuiltinBounds> {
// More bounds is a subtype of fewer bounds, so
// the LUB (mutual supertype) is the intersection.
Ok(a.intersection(b))

View File

@ -168,6 +168,22 @@ pub enum SubregionOrigin {
// relating `'a` to `'b`
RelateObjectBound(Span),
// When closing over a variable in a closure/proc, ensure that the
// type of the variable outlives the lifetime bound.
RelateProcBound(Span, ast::NodeId, ty::t),
// The given type parameter was instantiated with the given type,
// and that type must outlive some region.
RelateParamBound(Span, ty::ParamTy, ty::t),
// The given region parameter was instantiated with a region
// that must outlive some other region.
RelateRegionParamBound(Span),
// A bound placed on type parameters that states that must outlive
// the moment of their instantiation.
RelateDefaultParamBound(Span, ty::t),
// Creating a pointer `b` to contents of another reference
Reborrow(Span),
@ -177,6 +193,9 @@ pub enum SubregionOrigin {
// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(ty::t, Span),
// The type T of an expression E must outlive the lifetime for E.
ExprTypeIsNotInScope(ty::t, Span),
// A `ref b` whose region does not enclose the decl site
BindingTypeIsNotValidAtDecl(Span),
@ -194,6 +213,9 @@ pub enum SubregionOrigin {
// An auto-borrow that does not enclose the expr where it occurs
AutoBorrow(Span),
// Managed data cannot contain borrowed pointers.
Managed(Span),
}
/// Reasons to create a region inference variable
@ -336,7 +358,6 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures {
}
pub fn mk_subr(cx: &InferCtxt,
_a_is_expected: bool,
origin: SubregionOrigin,
a: ty::Region,
b: ty::Region) {
@ -346,6 +367,18 @@ pub fn mk_subr(cx: &InferCtxt,
cx.region_vars.commit(snapshot);
}
pub fn verify_param_bound(cx: &InferCtxt,
origin: SubregionOrigin,
param_ty: ty::ParamTy,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_param_bound({}, {} <: {})",
param_ty.repr(cx.tcx),
a.repr(cx.tcx),
bs.repr(cx.tcx));
cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
}
pub fn mk_eqty(cx: &InferCtxt,
a_is_expected: bool,
origin: TypeOrigin,
@ -589,6 +622,13 @@ impl<'a> InferCtxt<'a> {
self.rollback_to(snapshot);
r
}
pub fn add_given(&self,
sub: ty::FreeRegion,
sup: ty::RegionVid)
{
self.region_vars.add_given(sub, sup);
}
}
impl<'a> InferCtxt<'a> {
@ -687,14 +727,13 @@ impl<'a> InferCtxt<'a> {
}
pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
trait_ref:
&ty::TraitRef)
trait_ref: &ty::TraitRef)
-> ty::TraitRef {
// make up a dummy type just to reuse/abuse the resolve machinery
let dummy0 = ty::mk_trait(self.tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
ty::empty_builtin_bounds());
ty::region_existential_bound(ty::ReStatic));
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
match ty::get(dummy1).sty {
ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => {
@ -896,15 +935,21 @@ impl SubregionOrigin {
FreeVariable(a, _) => a,
IndexSlice(a) => a,
RelateObjectBound(a) => a,
RelateProcBound(a, _, _) => a,
RelateParamBound(a, _, _) => a,
RelateRegionParamBound(a) => a,
RelateDefaultParamBound(a, _) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
ReferenceOutlivesReferent(_, a) => a,
ExprTypeIsNotInScope(_, a) => a,
BindingTypeIsNotValidAtDecl(a) => a,
CallRcvr(a) => a,
CallArg(a) => a,
CallReturn(a) => a,
AddrOf(a) => a,
AutoBorrow(a) => a,
Managed(a) => a,
}
}
}
@ -933,6 +978,27 @@ impl Repr for SubregionOrigin {
RelateObjectBound(a) => {
format!("RelateObjectBound({})", a.repr(tcx))
}
RelateProcBound(a, b, c) => {
format!("RelateProcBound({},{},{})",
a.repr(tcx),
b,
c.repr(tcx))
}
RelateParamBound(a, b, c) => {
format!("RelateParamBound({},{},{})",
a.repr(tcx),
b.repr(tcx),
c.repr(tcx))
}
RelateRegionParamBound(a) => {
format!("RelateRegionParamBound({})",
a.repr(tcx))
}
RelateDefaultParamBound(a, b) => {
format!("RelateDefaultParamBound({},{})",
a.repr(tcx),
b.repr(tcx))
}
Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
ReborrowUpvar(a, b) => {
format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
@ -940,6 +1006,11 @@ impl Repr for SubregionOrigin {
ReferenceOutlivesReferent(_, a) => {
format!("ReferenceOutlivesReferent({})", a.repr(tcx))
}
ExprTypeIsNotInScope(a, b) => {
format!("ExprTypeIsNotInScope({}, {})",
a.repr(tcx),
b.repr(tcx))
}
BindingTypeIsNotValidAtDecl(a) => {
format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
}
@ -948,6 +1019,7 @@ impl Repr for SubregionOrigin {
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
Managed(a) => format!("Managed({})", a.repr(tcx)),
}
}
}

View File

@ -30,12 +30,32 @@ use syntax::ast;
mod doc;
// A constraint that influences the inference process.
#[deriving(PartialEq, Eq, Hash)]
pub enum Constraint {
// One region variable is subregion of another
ConstrainVarSubVar(RegionVid, RegionVid),
// Concrete region is subregion of region variable
ConstrainRegSubVar(Region, RegionVid),
// Region variable is subregion of concrete region
ConstrainVarSubReg(RegionVid, Region),
ConstrainRegSubReg(Region, Region),
}
// Something we have to verify after region inference is done, but
// which does not directly influence the inference process
pub enum Verify {
// VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor
// `b` are inference variables.
VerifyRegSubReg(SubregionOrigin, Region, Region),
// VerifyParamBound(T, _, R, RS): The parameter type `T` must
// outlive the region `R`. `T` is known to outlive `RS`. Therefore
// verify that `R <= RS[i]` for some `i`. Inference variables may
// be involved (but this verification step doesn't influence
// inference).
VerifyParamBound(ty::ParamTy, SubregionOrigin, Region, Vec<Region>),
}
#[deriving(PartialEq, Eq, Hash)]
@ -51,6 +71,8 @@ pub enum UndoLogEntry {
Mark,
AddVar(RegionVid),
AddConstraint(Constraint),
AddVerify(uint),
AddGiven(ty::FreeRegion, ty::RegionVid),
AddCombination(CombineMapType, TwoRegions)
}
@ -66,6 +88,13 @@ pub enum RegionResolutionError {
/// `o` requires that `a <= b`, but this does not hold
ConcreteFailure(SubregionOrigin, Region, Region),
/// `ParamBoundFailure(p, s, a, bs)
///
/// The parameter type `p` must be known to outlive the lifetime
/// `a`, but it is only known to outlive `bs` (and none of the
/// regions in `bs` outlive `a`).
ParamBoundFailure(SubregionOrigin, ty::ParamTy, Region, Vec<Region>),
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
///
/// Could not infer a value for `v` because `sub_r <= v` (due to
@ -125,7 +154,38 @@ pub type CombineMap = HashMap<TwoRegions, RegionVid>;
pub struct RegionVarBindings<'a> {
tcx: &'a ty::ctxt,
var_origins: RefCell<Vec<RegionVariableOrigin>>,
// Constraints of the form `A <= B` introduced by the region
// checker. Here at least one of `A` and `B` must be a region
// variable.
constraints: RefCell<HashMap<Constraint, SubregionOrigin>>,
// A "verify" is something that we need to verify after inference is
// done, but which does not directly affect inference in any way.
//
// An example is a `A <= B` where neither `A` nor `B` are
// inference variables.
verifys: RefCell<Vec<Verify>>,
// A "given" is a relationship that is known to hold. In particular,
// we often know from closure fn signatures that a particular free
// region must be a subregion of a region variable:
//
// foo.iter().filter(<'a> |x: &'a &'b T| ...)
//
// In situations like this, `'b` is in fact a region variable
// introduced by the call to `iter()`, and `'a` is a bound region
// on the closure (as indicated by the `<'a>` prefix). If we are
// naive, we wind up inferring that `'b` must be `'static`,
// because we require that it be greater than `'a` and we do not
// know what `'a` is precisely.
//
// This hashmap is used to avoid that naive scenario. Basically we
// record the fact that `'a <= 'b` is implied by the fn signature,
// and then ignore the constraint when solving equations. This is
// a bit of a hack but seems to work.
givens: RefCell<HashSet<(ty::FreeRegion, ty::RegionVid)>>,
lubs: RefCell<CombineMap>,
glbs: RefCell<CombineMap>,
skolemization_count: Cell<uint>,
@ -164,6 +224,8 @@ impl<'a> RegionVarBindings<'a> {
var_origins: RefCell::new(Vec::new()),
values: RefCell::new(None),
constraints: RefCell::new(HashMap::new()),
verifys: RefCell::new(Vec::new()),
givens: RefCell::new(HashSet::new()),
lubs: RefCell::new(HashMap::new()),
glbs: RefCell::new(HashMap::new()),
skolemization_count: Cell::new(0),
@ -216,12 +278,19 @@ impl<'a> RegionVarBindings<'a> {
Mark | CommitedSnapshot => { }
AddVar(vid) => {
let mut var_origins = self.var_origins.borrow_mut();
assert_eq!(var_origins.len(), vid.index + 1);
var_origins.pop().unwrap();
assert_eq!(var_origins.len(), vid.index);
}
AddConstraint(ref constraint) => {
self.constraints.borrow_mut().remove(constraint);
}
AddVerify(index) => {
self.verifys.borrow_mut().pop();
assert_eq!(self.verifys.borrow().len(), index);
}
AddGiven(sub, sup) => {
self.givens.borrow_mut().remove(&(sub, sup));
}
AddCombination(Glb, ref regions) => {
self.glbs.borrow_mut().remove(regions);
}
@ -289,13 +358,14 @@ impl<'a> RegionVarBindings<'a> {
self.values.borrow().is_none()
}
pub fn add_constraint(&self,
constraint: Constraint,
origin: SubregionOrigin) {
fn add_constraint(&self,
constraint: Constraint,
origin: SubregionOrigin) {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: add_constraint({:?})", constraint);
debug!("RegionVarBindings: add_constraint({})",
constraint.repr(self.tcx));
if self.constraints.borrow_mut().insert(constraint, origin) {
if self.in_snapshot() {
@ -304,6 +374,38 @@ impl<'a> RegionVarBindings<'a> {
}
}
fn add_verify(&self,
verify: Verify) {
// cannot add verifys once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: add_verify({})",
verify.repr(self.tcx));
let mut verifys = self.verifys.borrow_mut();
let index = verifys.len();
verifys.push(verify);
if self.in_snapshot() {
self.undo_log.borrow_mut().push(AddVerify(index));
}
}
pub fn add_given(&self,
sub: ty::FreeRegion,
sup: ty::RegionVid) {
// cannot add givens once regions are resolved
assert!(self.values_are_none());
let mut givens = self.givens.borrow_mut();
if givens.insert((sub, sup)) {
debug!("add_given({} <= {})",
sub.repr(self.tcx),
sup);
self.undo_log.borrow_mut().push(AddGiven(sub, sup));
}
}
pub fn make_subregion(&self,
origin: SubregionOrigin,
sub: Region,
@ -320,7 +422,9 @@ impl<'a> RegionVarBindings<'a> {
(ReEarlyBound(..), ReEarlyBound(..)) => {
// This case is used only to make sure that explicitly-specified
// `Self` types match the real self type in implementations.
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
//
// FIXME(NDM) -- we really shouldn't be comparing bound things
self.add_verify(VerifyRegSubReg(origin, sub, sup));
}
(ReEarlyBound(..), _) |
(ReLateBound(..), _) |
@ -345,11 +449,19 @@ impl<'a> RegionVarBindings<'a> {
self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
}
_ => {
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
self.add_verify(VerifyRegSubReg(origin, sub, sup));
}
}
}
pub fn verify_param_bound(&self,
origin: SubregionOrigin,
param_ty: ty::ParamTy,
sub: Region,
sups: Vec<Region>) {
self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
}
pub fn lub_regions(&self,
origin: SubregionOrigin,
a: Region,
@ -358,7 +470,9 @@ impl<'a> RegionVarBindings<'a> {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
debug!("RegionVarBindings: lub_regions({}, {})",
a.repr(self.tcx),
b.repr(self.tcx));
match (a, b) {
(ReStatic, _) | (_, ReStatic) => {
ReStatic // nothing lives longer than static
@ -381,7 +495,9 @@ impl<'a> RegionVarBindings<'a> {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
debug!("RegionVarBindings: glb_regions({}, {})",
a.repr(self.tcx),
b.repr(self.tcx));
match (a, b) {
(ReStatic, r) | (r, ReStatic) => {
// static lives longer than everything else
@ -397,30 +513,29 @@ impl<'a> RegionVarBindings<'a> {
}
}
pub fn max_regions(&self,
a: Region,
b: Region)
-> Option<Region>
{
match self.glb_concrete_regions(a, b) {
Ok(r) => Some(r),
Err(_) => None
}
}
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
let v = match *self.values.borrow() {
match *self.values.borrow() {
None => {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(rid.index).span(),
"attempt to resolve region variable before values have \
been computed!")
}
Some(ref values) => *values.get(rid.index)
};
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
rid, rid.index, v);
match v {
Value(r) => r,
NoValue => {
// No constraints, return ty::ReEmpty
ReEmpty
}
ErrorValue => {
// An error that has previously been reported.
ReStatic
Some(ref values) => {
let r = lookup(values, rid);
debug!("resolve_var({}) = {}", rid, r.repr(self.tcx));
r
}
}
}
@ -456,7 +571,7 @@ impl<'a> RegionVarBindings<'a> {
}
relate(self, a, ReInfer(ReVar(c)));
relate(self, b, ReInfer(ReVar(c)));
debug!("combine_vars() c={:?}", c);
debug!("combine_vars() c={}", c);
ReInfer(ReVar(c))
}
@ -493,40 +608,53 @@ impl<'a> RegionVarBindings<'a> {
while result_index < result_set.len() {
// nb: can't use uint::range() here because result_set grows
let r = *result_set.get(result_index);
debug!("result_index={}, r={:?}", result_index, r);
debug!("result_index={}, r={}", result_index, r);
for undo_entry in
self.undo_log.borrow().slice_from(mark.length).iter()
{
let regs = match undo_entry {
&AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
match undo_entry {
&AddConstraint(ConstrainVarSubVar(a, b)) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
ReInfer(ReVar(a)), ReInfer(ReVar(b)));
}
&AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
Some((*a, ReInfer(ReVar(*b))))
&AddConstraint(ConstrainRegSubVar(a, b)) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
a, ReInfer(ReVar(b)));
}
&AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
Some((ReInfer(ReVar(*a)), *b))
&AddConstraint(ConstrainVarSubReg(a, b)) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
ReInfer(ReVar(a)), b);
}
&AddConstraint(ConstrainRegSubReg(a, b)) => {
Some((a, b))
&AddGiven(a, b) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
ReFree(a), ReInfer(ReVar(b)));
}
&AddVerify(i) => {
match self.verifys.borrow().get(i) {
&VerifyRegSubReg(_, a, b) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
a, b);
}
&VerifyParamBound(_, _, a, ref bs) => {
for &b in bs.iter() {
consider_adding_bidirectional_edges(
&mut result_set, r,
a, b);
}
}
}
}
&AddCombination(..) |
&Mark |
&AddVar(..) |
&OpenSnapshot |
&CommitedSnapshot => {
None
}
};
match regs {
None => {}
Some((r1, r2)) => {
result_set =
consider_adding_edge(result_set, r, r1, r2);
result_set =
consider_adding_edge(result_set, r, r2, r1);
}
}
}
@ -536,17 +664,24 @@ impl<'a> RegionVarBindings<'a> {
return result_set;
fn consider_adding_edge(result_set: Vec<Region> ,
r: Region,
r1: Region,
r2: Region) -> Vec<Region> {
let mut result_set = result_set;
if r == r1 { // Clearly, this is potentially inefficient.
fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
r: Region,
r1: Region,
r2: Region) {
consider_adding_directed_edge(result_set, r, r1, r2);
consider_adding_directed_edge(result_set, r, r2, r1);
}
fn consider_adding_directed_edge(result_set: &mut Vec<Region>,
r: Region,
r1: Region,
r2: Region) {
if r == r1 {
// Clearly, this is potentially inefficient.
if !result_set.iter().any(|x| *x == r2) {
result_set.push(r2);
}
}
return result_set;
}
}
@ -595,7 +730,7 @@ impl<'a> RegionVarBindings<'a> {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(v_id.index).span(),
format!("lub_concrete_regions invoked with \
non-concrete regions: {:?}, {:?}",
non-concrete regions: {}, {}",
a,
b).as_slice());
}
@ -675,7 +810,7 @@ impl<'a> RegionVarBindings<'a> {
a: Region,
b: Region)
-> cres<Region> {
debug!("glb_concrete_regions({:?}, {:?})", a, b);
debug!("glb_concrete_regions({}, {})", a, b);
match (a, b) {
(ReLateBound(..), _) |
(_, ReLateBound(..)) |
@ -702,7 +837,7 @@ impl<'a> RegionVarBindings<'a> {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(v_id.index).span(),
format!("glb_concrete_regions invoked with \
non-concrete regions: {:?}, {:?}",
non-concrete regions: {}, {}",
a,
b).as_slice());
}
@ -783,7 +918,7 @@ impl<'a> RegionVarBindings<'a> {
// scopes or two free regions. So, if one of
// these scopes is a subscope of the other, return
// it. Otherwise fail.
debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})",
scope_a, scope_b, region_a, region_b);
match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
@ -815,12 +950,16 @@ type RegionGraph = graph::Graph<(), Constraint>;
impl<'a> RegionVarBindings<'a> {
fn infer_variable_values(&self,
errors: &mut Vec<RegionResolutionError>)
-> Vec<VarValue> {
-> Vec<VarValue>
{
let mut var_data = self.construct_var_data();
self.expansion(var_data.as_mut_slice());
self.contraction(var_data.as_mut_slice());
self.collect_concrete_region_errors(&mut *errors);
self.extract_values_and_collect_conflicts(var_data.as_slice(), errors)
let values =
self.extract_values_and_collect_conflicts(var_data.as_slice(),
errors);
self.collect_concrete_region_errors(&values, errors);
values
}
fn construct_var_data(&self) -> Vec<VarData> {
@ -838,6 +977,12 @@ impl<'a> RegionVarBindings<'a> {
fn expansion(&self, var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Expansion", |constraint| {
debug!("expansion: constraint={} origin={}",
constraint.repr(self.tcx),
self.constraints.borrow()
.find(constraint)
.unwrap()
.repr(self.tcx));
match *constraint {
ConstrainRegSubVar(a_region, b_vid) => {
let b_data = &mut var_data[b_vid.index];
@ -856,10 +1001,6 @@ impl<'a> RegionVarBindings<'a> {
// This is a contraction constraint. Ignore it.
false
}
ConstrainRegSubReg(..) => {
// No region variables involved. Ignore.
false
}
}
})
}
@ -868,14 +1009,29 @@ impl<'a> RegionVarBindings<'a> {
a_region: Region,
b_vid: RegionVid,
b_data: &mut VarData)
-> bool {
debug!("expand_node({:?}, {:?} == {:?})",
a_region, b_vid, b_data.value);
-> bool
{
debug!("expand_node({}, {} == {})",
a_region.repr(self.tcx),
b_vid,
b_data.value.repr(self.tcx));
// Check if this relationship is implied by a given.
match a_region {
ty::ReFree(fr) => {
if self.givens.borrow().contains(&(fr, b_vid)) {
debug!("given");
return false;
}
}
_ => { }
}
b_data.classification = Expanding;
match b_data.value {
NoValue => {
debug!("Setting initial value of {:?} to {:?}", b_vid, a_region);
debug!("Setting initial value of {} to {}",
b_vid, a_region.repr(self.tcx));
b_data.value = Value(a_region);
return true;
@ -887,8 +1043,10 @@ impl<'a> RegionVarBindings<'a> {
return false;
}
debug!("Expanding value of {:?} from {:?} to {:?}",
b_vid, cur_region, lub);
debug!("Expanding value of {} from {} to {}",
b_vid,
cur_region.repr(self.tcx),
lub.repr(self.tcx));
b_data.value = Value(lub);
return true;
@ -903,6 +1061,12 @@ impl<'a> RegionVarBindings<'a> {
fn contraction(&self,
var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Contraction", |constraint| {
debug!("contraction: constraint={} origin={}",
constraint.repr(self.tcx),
self.constraints.borrow()
.find(constraint)
.unwrap()
.repr(self.tcx));
match *constraint {
ConstrainRegSubVar(..) => {
// This is an expansion constraint. Ignore.
@ -921,10 +1085,6 @@ impl<'a> RegionVarBindings<'a> {
let a_data = &mut var_data[a_vid.index];
self.contract_node(a_vid, a_data, b_region)
}
ConstrainRegSubReg(..) => {
// No region variables involved. Ignore.
false
}
}
})
}
@ -934,8 +1094,9 @@ impl<'a> RegionVarBindings<'a> {
a_data: &mut VarData,
b_region: Region)
-> bool {
debug!("contract_node({:?} == {:?}/{:?}, {:?})",
a_vid, a_data.value, a_data.classification, b_region);
debug!("contract_node({} == {}/{}, {})",
a_vid, a_data.value.repr(self.tcx),
a_data.classification, b_region.repr(self.tcx));
return match a_data.value {
NoValue => {
@ -967,8 +1128,10 @@ impl<'a> RegionVarBindings<'a> {
b_region: Region)
-> bool {
if !this.is_subregion_of(a_region, b_region) {
debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
a_vid, a_region, b_region);
debug!("Setting {} to ErrorValue: {} not subregion of {}",
a_vid,
a_region.repr(this.tcx),
b_region.repr(this.tcx));
a_data.value = ErrorValue;
}
false
@ -985,15 +1148,19 @@ impl<'a> RegionVarBindings<'a> {
if glb == a_region {
false
} else {
debug!("Contracting value of {:?} from {:?} to {:?}",
a_vid, a_region, glb);
debug!("Contracting value of {} from {} to {}",
a_vid,
a_region.repr(this.tcx),
glb.repr(this.tcx));
a_data.value = Value(glb);
true
}
}
Err(_) => {
debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
a_vid, a_region, b_region);
debug!("Setting {} to ErrorValue: no glb of {}, {}",
a_vid,
a_region.repr(this.tcx),
b_region.repr(this.tcx));
a_data.value = ErrorValue;
false
}
@ -1001,30 +1168,44 @@ impl<'a> RegionVarBindings<'a> {
}
}
fn collect_concrete_region_errors(
&self,
errors: &mut Vec<RegionResolutionError>)
fn collect_concrete_region_errors(&self,
values: &Vec<VarValue>,
errors: &mut Vec<RegionResolutionError>)
{
for (constraint, _) in self.constraints.borrow().iter() {
let (sub, sup) = match *constraint {
ConstrainVarSubVar(..) |
ConstrainRegSubVar(..) |
ConstrainVarSubReg(..) => {
continue;
}
ConstrainRegSubReg(sub, sup) => {
(sub, sup)
}
};
let mut reg_reg_dups = HashSet::new();
for verify in self.verifys.borrow().iter() {
match *verify {
VerifyRegSubReg(ref origin, sub, sup) => {
if self.is_subregion_of(sub, sup) {
continue;
}
if self.is_subregion_of(sub, sup) {
continue;
if !reg_reg_dups.insert((sub, sup)) {
continue;
}
debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
sub.repr(self.tcx),
sup.repr(self.tcx));
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
}
VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => {
let sub = normalize(values, sub);
if sups.iter()
.map(|&sup| normalize(values, sup))
.any(|sup| self.is_subregion_of(sub, sup))
{
continue;
}
let sups = sups.iter().map(|&sup| normalize(values, sup))
.collect();
errors.push(
ParamBoundFailure(
(*origin).clone(), *param_ty, sub, sups));
}
}
debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
sub, sup);
let origin = self.constraints.borrow().get_copy(constraint);
errors.push(ConcreteFailure(origin, sub, sup));
}
}
@ -1032,7 +1213,8 @@ impl<'a> RegionVarBindings<'a> {
&self,
var_data: &[VarData],
errors: &mut Vec<RegionResolutionError>)
-> Vec<VarValue> {
-> Vec<VarValue>
{
debug!("extract_values_and_collect_conflicts()");
// This is the best way that I have found to suppress
@ -1141,10 +1323,6 @@ impl<'a> RegionVarBindings<'a> {
dummy_idx,
*constraint);
}
ConstrainRegSubReg(..) => {
// Relations between two concrete regions do not
// require an edge in the graph.
}
}
}
@ -1206,16 +1384,10 @@ impl<'a> RegionVarBindings<'a> {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(node_idx.index).span(),
format!("collect_error_for_expanding_node() could not find error \
for var {:?}, lower_bounds={}, upper_bounds={}",
node_idx,
lower_bounds.iter()
.map(|x| x.region)
.collect::<Vec<ty::Region>>()
.repr(self.tcx),
upper_bounds.iter()
.map(|x| x.region)
.collect::<Vec<ty::Region>>()
.repr(self.tcx)).as_slice());
for var {}, lower_bounds={}, upper_bounds={}",
node_idx,
lower_bounds.repr(self.tcx),
upper_bounds.repr(self.tcx)).as_slice());
}
fn collect_error_for_contracting_node(
@ -1257,12 +1429,9 @@ impl<'a> RegionVarBindings<'a> {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(node_idx.index).span(),
format!("collect_error_for_contracting_node() could not find error \
for var {:?}, upper_bounds={}",
node_idx,
upper_bounds.iter()
.map(|x| x.region)
.collect::<Vec<ty::Region>>()
.repr(self.tcx)).as_slice());
for var {}, upper_bounds={}",
node_idx,
upper_bounds.repr(self.tcx)).as_slice());
}
fn collect_concrete_regions(&self,
@ -1301,8 +1470,8 @@ impl<'a> RegionVarBindings<'a> {
state.dup_found = true;
}
debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
classification={:?})",
debug!("collect_concrete_regions(orig_node_idx={}, node_idx={}, \
classification={})",
orig_node_idx, node_idx, classification);
// figure out the direction from which this node takes its
@ -1323,7 +1492,7 @@ impl<'a> RegionVarBindings<'a> {
graph: &RegionGraph,
source_vid: RegionVid,
dir: Direction) {
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
debug!("process_edges(source_vid={}, dir={})", source_vid, dir);
let source_node_index = NodeIndex(source_vid.index);
graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
@ -1343,8 +1512,6 @@ impl<'a> RegionVarBindings<'a> {
origin: this.constraints.borrow().get_copy(&edge.data)
});
}
ConstrainRegSubReg(..) => {}
}
true
});
@ -1386,9 +1553,53 @@ impl Repr for Constraint {
ConstrainVarSubReg(a, b) => {
format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
ConstrainRegSubReg(a, b) => {
format!("ConstrainRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
}
}
impl Repr for Verify {
fn repr(&self, tcx: &ty::ctxt) -> String {
match *self {
VerifyRegSubReg(_, ref a, ref b) => {
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
VerifyParamBound(_, ref p, ref a, ref bs) => {
format!("VerifyParamBound({}, {}, {})",
p.repr(tcx), a.repr(tcx), bs.repr(tcx))
}
}
}
}
fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
match r {
ty::ReInfer(ReVar(rid)) => lookup(values, rid),
_ => r
}
}
fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
match *values.get(rid.index) {
Value(r) => r,
NoValue => ReEmpty, // No constraints, return ty::ReEmpty
ErrorValue => ReStatic, // Previously reported error.
}
}
impl Repr for VarValue {
fn repr(&self, tcx: &ty::ctxt) -> String {
match *self {
NoValue => format!("NoValue"),
Value(r) => format!("Value({})", r.repr(tcx)),
ErrorValue => format!("ErrorValue"),
}
}
}
impl Repr for RegionAndOrigin {
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("RegionAndOrigin({},{})",
self.region.repr(tcx),
self.origin.repr(tcx))
}
}

View File

@ -102,7 +102,8 @@ impl<'f> Combine for Sub<'f> {
})
}
fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
-> cres<BuiltinBounds> {
// More bounds is a subtype of fewer bounds.
//
// e.g., fn:Copy() <: fn(), because the former is a function

View File

@ -555,3 +555,12 @@ impl SimplyUnifiable for ast::FloatTy {
return ty::terr_float_mismatch(err);
}
}
impl<K:Repr,V:Repr> Repr for VarValue<K,V> {
fn repr(&self, tcx: &ty::ctxt) -> String {
match *self {
Redirect(ref k) => format!("Redirect({})", k.repr(tcx)),
Root(ref v, r) => format!("Root({}, {})", v.repr(tcx), r)
}
}
}

View File

@ -30,12 +30,19 @@ pub trait RegionScope {
span: Span,
count: uint)
-> Result<Vec<ty::Region> , ()>;
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
}
// A scope in which all regions must be explicitly named
// A scope in which all regions must be explicitly named. This is used
// for types that appear in structs and so on.
pub struct ExplicitRscope;
impl RegionScope for ExplicitRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
None
}
fn anon_regions(&self,
_span: Span,
_count: uint)
@ -44,6 +51,33 @@ impl RegionScope for ExplicitRscope {
}
}
// A scope in which any omitted region defaults to `default`. This is
// used after the `->` in function signatures, but also for backwards
// compatibility with object types. The latter use may go away.
pub struct SpecificRscope {
default: ty::Region
}
impl SpecificRscope {
pub fn new(r: ty::Region) -> SpecificRscope {
SpecificRscope { default: r }
}
}
impl RegionScope for SpecificRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
Some(self.default)
}
fn anon_regions(&self,
_span: Span,
count: uint)
-> Result<Vec<ty::Region> , ()>
{
Ok(Vec::from_elem(count, self.default))
}
}
/// A scope in which we generate anonymous, late-bound regions for
/// omitted regions. This occurs in function signatures.
pub struct BindingRscope {
@ -58,30 +92,26 @@ impl BindingRscope {
anon_bindings: Cell::new(0),
}
}
fn next_region(&self) -> ty::Region {
let idx = self.anon_bindings.get();
self.anon_bindings.set(idx + 1);
ty::ReLateBound(self.binder_id, ty::BrAnon(idx))
}
}
impl RegionScope for BindingRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
{
Some(self.next_region())
}
fn anon_regions(&self,
_: Span,
count: uint)
-> Result<Vec<ty::Region>, ()> {
let idx = self.anon_bindings.get();
self.anon_bindings.set(idx + count);
Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
ty::BrAnon(idx + i))))
}
}
/// A scope in which we generate one specific region. This occurs after the
/// `->` (i.e. in the return type) of function signatures.
pub struct ImpliedSingleRscope {
pub region: ty::Region,
}
impl RegionScope for ImpliedSingleRscope {
fn anon_regions(&self, _: Span, count: uint)
-> Result<Vec<ty::Region>,()> {
Ok(Vec::from_elem(count, self.region.clone()))
-> Result<Vec<ty::Region> , ()>
{
Ok(Vec::from_fn(count, |_| self.next_region()))
}
}

View File

@ -10,6 +10,8 @@
#![allow(non_camel_case_types)]
use std::hash::{Hash, Hasher};
use std::collections::HashMap;
use syntax::ast;
use syntax::visit;
use syntax::visit::Visitor;
@ -105,3 +107,51 @@ pub fn block_query(b: ast::P<ast::Block>, p: |&ast::Expr| -> bool) -> bool {
visit::walk_block(&mut v, &*b, ());
return v.flag;
}
// K: Eq + Hash<S>, V, S, H: Hasher<S>
pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>(
edges_map: &HashMap<T,Vec<T>,H>,
source: T,
destination: T)
-> bool
{
/*!
* Determines whether there exists a path from `source` to
* `destination`. The graph is defined by the `edges_map`, which
* maps from a node `S` to a list of its adjacent nodes `T`.
*
* Efficiency note: This is implemented in an inefficient way
* because it is typically invoked on very small graphs. If the graphs
* become larger, a more efficient graph representation and algorithm
* would probably be advised.
*/
if source == destination {
return true;
}
// Do a little breadth-first-search here. The `queue` list
// doubles as a way to detect if we've seen a particular FR
// before. Note that we expect this graph to be an *extremely
// shallow* tree.
let mut queue = vec!(source);
let mut i = 0;
while i < queue.len() {
match edges_map.find(queue.get(i)) {
Some(edges) => {
for target in edges.iter() {
if *target == destination {
return true;
}
if !queue.iter().any(|x| x == target) {
queue.push((*target).clone());
}
}
}
None => {}
}
i += 1;
}
return false;
}

View File

@ -23,11 +23,9 @@ use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
use middle::ty::{ty_unboxed_closure};
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty;
use middle::typeck::infer::region_inference;
use middle::typeck::infer::unify::VarValue as VV;
use middle::typeck::infer::unify;
use middle::typeck::infer;
use middle::typeck;
use middle::typeck::check::regionmanip;
use middle::typeck::infer;
use std::gc::Gc;
use std::rc::Rc;
@ -66,6 +64,22 @@ pub fn note_and_explain_region(cx: &ctxt,
}
}
fn item_scope_tag(item: &ast::Item) -> &'static str {
/*!
* When a free region is associated with `item`, how should we describe
* the item in the error message.
*/
match item.node {
ast::ItemImpl(..) => "impl",
ast::ItemStruct(..) => "struct",
ast::ItemEnum(..) => "enum",
ast::ItemTrait(..) => "trait",
ast::ItemFn(..) => "function body",
_ => "item"
}
}
pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
-> (String, Option<Span>) {
return match region {
@ -87,9 +101,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
Some(ast_map::NodeStmt(stmt)) => {
explain_span(cx, "statement", stmt.span)
}
Some(ast_map::NodeItem(it)) if (match it.node {
ast::ItemFn(..) => true, _ => false}) => {
explain_span(cx, "function body", it.span)
Some(ast_map::NodeItem(it)) => {
let tag = item_scope_tag(&*it);
explain_span(cx, tag, it.span)
}
Some(_) | None => {
// this really should not happen
@ -112,17 +126,17 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
match cx.map.find(fr.scope_id) {
Some(ast_map::NodeBlock(ref blk)) => {
let (msg, opt_span) = explain_span(cx, "block", blk.span);
(format!("{} {}", prefix, msg), opt_span)
let (msg, opt_span) = explain_span(cx, "block", blk.span);
(format!("{} {}", prefix, msg), opt_span)
}
Some(ast_map::NodeItem(it)) if match it.node {
ast::ItemImpl(..) => true, _ => false} => {
let (msg, opt_span) = explain_span(cx, "impl", it.span);
(format!("{} {}", prefix, msg), opt_span)
Some(ast_map::NodeItem(it)) => {
let tag = item_scope_tag(&*it);
let (msg, opt_span) = explain_span(cx, tag, it.span);
(format!("{} {}", prefix, msg), opt_span)
}
Some(_) | None => {
// this really should not happen
(format!("{} node {}", prefix, fr.scope_id), None)
// this really should not happen
(format!("{} node {}", prefix, fr.scope_id), None)
}
}
}
@ -143,7 +157,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
};
fn explain_span(cx: &ctxt, heading: &str, span: Span)
-> (String, Option<Span>) {
-> (String, Option<Span>) {
let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_uint()),
Some(span))
@ -273,7 +287,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
_ => { }
}
push_sig_to_string(cx, &mut s, '(', ')', sig);
push_sig_to_string(cx, &mut s, '(', ')', sig, "");
s
}
@ -296,34 +310,34 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
}
};
let bounds_str = cty.bounds.user_string(cx);
match cty.store {
ty::UniqTraitStore => {
assert_eq!(cty.onceness, ast::Once);
s.push_str("proc");
push_sig_to_string(cx, &mut s, '(', ')', &cty.sig);
push_sig_to_string(cx, &mut s, '(', ')', &cty.sig,
bounds_str.as_slice());
}
ty::RegionTraitStore(..) => {
match cty.onceness {
ast::Many => {}
ast::Once => s.push_str("once ")
}
push_sig_to_string(cx, &mut s, '|', '|', &cty.sig);
push_sig_to_string(cx, &mut s, '|', '|', &cty.sig,
bounds_str.as_slice());
}
}
if !cty.bounds.is_empty() {
s.push_str(":");
s.push_str(cty.bounds.repr(cx).as_slice());
}
s
s.into_owned()
}
fn push_sig_to_string(cx: &ctxt,
s: &mut String,
bra: char,
ket: char,
sig: &ty::FnSig) {
sig: &ty::FnSig,
bounds: &str) {
s.push_char(bra);
let strs: Vec<String> = sig.inputs.iter().map(|a| fn_input_to_string(cx, *a)).collect();
s.push_str(strs.connect(", ").as_slice());
@ -332,6 +346,11 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
}
s.push_char(ket);
if !bounds.is_empty() {
s.push_str(":");
s.push_str(bounds);
}
if ty::get(sig.output).sty != ty_nil {
s.push_str(" -> ");
if ty::type_is_bot(sig.output) {
@ -383,18 +402,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
}
ty_infer(infer_ty) => infer_ty.to_string(),
ty_err => "[type error]".to_string(),
ty_param(ParamTy {idx: id, def_id: did, ..}) => {
let ident = match cx.ty_param_defs.borrow().find(&did.node) {
Some(def) => token::get_ident(def.ident).get().to_string(),
// This can only happen when a type mismatch error happens and
// the actual type has more type parameters than the expected one.
None => format!("<generic #{}>", id),
};
if !cx.sess.verbose() {
ident
} else {
format!("{}:{:?}", ident, did)
}
ty_param(ref param_ty) => {
param_ty.repr(cx)
}
ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
let base = ty::item_path_str(cx, did);
@ -408,8 +417,8 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
let trait_def = ty::lookup_trait_def(cx, did);
let ty = parameterized(cx, base.as_slice(),
substs, &trait_def.generics);
let bound_sep = if bounds.is_empty() { "" } else { "+" };
let bound_str = bounds.repr(cx);
let bound_str = bounds.user_string(cx);
let bound_sep = if bound_str.is_empty() { "" } else { "+" };
format!("{}{}{}",
ty,
bound_sep,
@ -573,6 +582,14 @@ impl<T:Repr> Repr for Vec<T> {
}
}
impl<T:UserString> UserString for Vec<T> {
fn user_string(&self, tcx: &ctxt) -> String {
let strs: Vec<String> =
self.iter().map(|t| t.user_string(tcx)).collect();
strs.connect(", ")
}
}
impl Repr for def::Def {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
@ -581,16 +598,18 @@ impl Repr for def::Def {
impl Repr for ty::TypeParameterDef {
fn repr(&self, tcx: &ctxt) -> String {
format!("TypeParameterDef({:?}, {})", self.def_id,
format!("TypeParameterDef({}, {})",
self.def_id.repr(tcx),
self.bounds.repr(tcx))
}
}
impl Repr for ty::RegionParameterDef {
fn repr(&self, _tcx: &ctxt) -> String {
format!("RegionParameterDef({}, {:?})",
fn repr(&self, tcx: &ctxt) -> String {
format!("RegionParameterDef(name={}, def_id={}, bounds={})",
token::get_name(self.name),
self.def_id)
self.def_id.repr(tcx),
self.bounds.repr(tcx))
}
}
@ -638,18 +657,31 @@ impl Repr for subst::RegionSubsts {
}
}
impl Repr for ty::BuiltinBounds {
fn repr(&self, _tcx: &ctxt) -> String {
let mut res = Vec::new();
for b in self.iter() {
res.push(match b {
ty::BoundSend => "Send".to_owned(),
ty::BoundSized => "Sized".to_owned(),
ty::BoundCopy => "Copy".to_owned(),
ty::BoundSync => "Sync".to_owned(),
});
}
res.connect("+")
}
}
impl Repr for ty::ExistentialBounds {
fn repr(&self, tcx: &ctxt) -> String {
self.user_string(tcx)
}
}
impl Repr for ty::ParamBounds {
fn repr(&self, tcx: &ctxt) -> String {
let mut res = Vec::new();
for b in self.builtin_bounds.iter() {
res.push(match b {
ty::BoundStatic => "'static".to_string(),
ty::BoundSend => "Send".to_string(),
ty::BoundSized => "Sized".to_string(),
ty::BoundCopy => "Copy".to_string(),
ty::BoundSync => "Sync".to_string(),
});
}
res.push(self.builtin_bounds.repr(tcx));
for t in self.trait_bounds.iter() {
res.push(t.repr(tcx));
}
@ -663,6 +695,15 @@ impl Repr for ty::TraitRef {
}
}
impl Repr for ty::TraitDef {
fn repr(&self, tcx: &ctxt) -> String {
format!("TraitDef(generics={}, bounds={}, trait_ref={})",
self.generics.repr(tcx),
self.bounds.repr(tcx),
self.trait_ref.repr(tcx))
}
}
impl Repr for ast::Expr {
fn repr(&self, _tcx: &ctxt) -> String {
format!("expr({}: {})", self.id, pprust::expr_to_string(self))
@ -675,12 +716,24 @@ impl Repr for ast::Path {
}
}
impl UserString for ast::Path {
fn user_string(&self, _tcx: &ctxt) -> String {
pprust::path_to_string(self)
}
}
impl Repr for ast::Item {
fn repr(&self, tcx: &ctxt) -> String {
format!("item({})", tcx.map.node_to_string(self.id))
}
}
impl Repr for ast::Lifetime {
fn repr(&self, _tcx: &ctxt) -> String {
format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
}
}
impl Repr for ast::Stmt {
fn repr(&self, _tcx: &ctxt) -> String {
format!("stmt({}: {})",
@ -724,11 +777,7 @@ impl Repr for ty::Region {
bound_region.repr(tcx))
}
ty::ReFree(ref fr) => {
format!("ReFree({}, {})",
fr.scope_id,
fr.bound_region.repr(tcx))
}
ty::ReFree(ref fr) => fr.repr(tcx),
ty::ReScope(id) => {
format!("ReScope({})", id)
@ -753,6 +802,20 @@ impl Repr for ty::Region {
}
}
impl UserString for ty::Region {
fn user_string(&self, tcx: &ctxt) -> String {
region_to_string(tcx, "", false, *self)
}
}
impl Repr for ty::FreeRegion {
fn repr(&self, tcx: &ctxt) -> String {
format!("ReFree({}, {})",
self.scope_id,
self.bound_region.repr(tcx))
}
}
impl Repr for ast::DefId {
fn repr(&self, tcx: &ctxt) -> String {
// Unfortunately, there seems to be no way to attempt to print
@ -833,6 +896,12 @@ impl Repr for ast::Name {
}
}
impl UserString for ast::Name {
fn user_string(&self, _tcx: &ctxt) -> String {
token::get_name(*self).get().to_string()
}
}
impl Repr for ast::Ident {
fn repr(&self, _tcx: &ctxt) -> String {
token::get_ident(*self).get().to_string()
@ -928,21 +997,14 @@ impl Repr for ty::BuiltinBound {
impl UserString for ty::BuiltinBound {
fn user_string(&self, _tcx: &ctxt) -> String {
match *self {
ty::BoundStatic => "'static".to_string(),
ty::BoundSend => "Send".to_string(),
ty::BoundSized => "Sized".to_string(),
ty::BoundCopy => "Copy".to_string(),
ty::BoundSync => "Sync".to_string(),
ty::BoundSend => "Send".to_owned(),
ty::BoundSized => "Sized".to_owned(),
ty::BoundCopy => "Copy".to_owned(),
ty::BoundSync => "Sync".to_owned(),
}
}
}
impl Repr for ty::BuiltinBounds {
fn repr(&self, tcx: &ctxt) -> String {
self.user_string(tcx)
}
}
impl Repr for Span {
fn repr(&self, tcx: &ctxt) -> String {
tcx.sess.codemap().span_to_string(*self).to_string()
@ -956,6 +1018,43 @@ impl<A:UserString> UserString for Rc<A> {
}
}
impl UserString for ty::ParamBounds {
fn user_string(&self, tcx: &ctxt) -> String {
let mut result = Vec::new();
let s = self.builtin_bounds.user_string(tcx);
if !s.is_empty() {
result.push(s);
}
for n in self.trait_bounds.iter() {
result.push(n.user_string(tcx));
}
result.connect("+")
}
}
impl UserString for ty::ExistentialBounds {
fn user_string(&self, tcx: &ctxt) -> String {
if self.builtin_bounds.contains_elem(ty::BoundSend) &&
self.region_bound == ty::ReStatic
{ // Region bound is implied by builtin bounds:
return self.builtin_bounds.repr(tcx);
}
let mut res = Vec::new();
let region_str = self.region_bound.user_string(tcx);
if !region_str.is_empty() {
res.push(region_str);
}
for bound in self.builtin_bounds.iter() {
res.push(bound.user_string(tcx));
}
res.connect("+")
}
}
impl UserString for ty::BuiltinBounds {
fn user_string(&self, tcx: &ctxt) -> String {
self.iter()
@ -1083,33 +1182,55 @@ impl<T:Repr> Repr for infer::Bounds<T> {
}
}
impl<K:Repr,V:Repr> Repr for VV<K,V> {
fn repr(&self, tcx: &ctxt) -> String {
match *self {
unify::Redirect(ref k) =>
format!("Redirect({})", k.repr(tcx)),
unify::Root(ref v, r) =>
format!("Root({}, {})", v.repr(tcx), r)
}
}
}
impl Repr for region_inference::VarValue {
fn repr(&self, tcx: &ctxt) -> String {
match *self {
infer::region_inference::NoValue =>
format!("NoValue"),
infer::region_inference::Value(r) =>
format!("Value({})", r.repr(tcx)),
infer::region_inference::ErrorValue =>
format!("ErrorValue"),
}
}
}
impl Repr for ty::ExplicitSelfCategory {
fn repr(&self, _: &ctxt) -> String {
explicit_self_category_to_str(self).to_string()
}
}
impl Repr for regionmanip::WfConstraint {
fn repr(&self, tcx: &ctxt) -> String {
match *self {
regionmanip::RegionSubRegionConstraint(_, r_a, r_b) => {
format!("RegionSubRegionConstraint({}, {})",
r_a.repr(tcx),
r_b.repr(tcx))
}
regionmanip::RegionSubParamConstraint(_, r, p) => {
format!("RegionSubParamConstraint({}, {})",
r.repr(tcx),
p.repr(tcx))
}
}
}
}
impl UserString for ParamTy {
fn user_string(&self, tcx: &ctxt) -> String {
let id = self.idx;
let did = self.def_id;
let ident = match tcx.ty_param_defs.borrow().find(&did.node) {
Some(def) => token::get_ident(def.ident).get().to_string(),
// This can only happen when a type mismatch error happens and
// the actual type has more type parameters than the expected one.
None => format!("<generic #{}>", id),
};
ident
}
}
impl Repr for ParamTy {
fn repr(&self, tcx: &ctxt) -> String {
self.user_string(tcx)
}
}
impl<A:Repr,B:Repr> Repr for (A,B) {
fn repr(&self, tcx: &ctxt) -> String {
let &(ref a, ref b) = self;
format!("({},{})", a.repr(tcx), b.repr(tcx))
}
}

View File

@ -192,7 +192,7 @@ impl AttrHelper for SpecialAttribute {
}
pub struct AttrBuilder {
attrs: Vec<(uint, Box<AttrHelper>)>
attrs: Vec<(uint, Box<AttrHelper+'static>)>
}
impl AttrBuilder {
@ -203,12 +203,12 @@ impl AttrBuilder {
}
pub fn arg<'a, T: AttrHelper + 'static>(&'a mut self, idx: uint, a: T) -> &'a mut AttrBuilder {
self.attrs.push((idx, box a as Box<AttrHelper>));
self.attrs.push((idx, box a as Box<AttrHelper+'static>));
self
}
pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder {
self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper>));
self.attrs.push((ReturnIndex as uint, box a as Box<AttrHelper+'static>));
self
}

View File

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

View File

@ -481,15 +481,14 @@ impl Clean<TyParam> for ty::TypeParameterDef {
#[deriving(Clone, Encodable, Decodable, PartialEq)]
pub enum TyParamBound {
RegionBound,
RegionBound, // FIXME(#16518) -- need to include name of actual region
TraitBound(Type)
}
impl Clean<TyParamBound> for ast::TyParamBound {
fn clean(&self) -> TyParamBound {
match *self {
ast::StaticRegionTyParamBound => RegionBound,
ast::OtherRegionTyParamBound(_) => RegionBound,
ast::RegionTyParamBound(_) => RegionBound,
ast::UnboxedFnTyParamBound(_) => {
// FIXME(pcwalton): Wrong.
RegionBound
@ -499,6 +498,16 @@ impl Clean<TyParamBound> for ast::TyParamBound {
}
}
impl Clean<Vec<TyParamBound>> for ty::ExistentialBounds {
fn clean(&self) -> Vec<TyParamBound> {
let mut vec = vec!(RegionBound);
for bb in self.builtin_bounds.iter() {
vec.push(bb.clean());
}
vec
}
}
fn external_path(name: &str, substs: &subst::Substs) -> Path {
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
.iter()
@ -525,7 +534,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
};
let empty = subst::Substs::empty();
let (did, path) = match *self {
ty::BoundStatic => return RegionBound,
ty::BoundSend =>
(tcx.lang_items.send_trait().unwrap(),
external_path("Send", &empty)),
@ -810,10 +818,7 @@ impl Clean<ClosureDecl> for ast::ClosureTy {
decl: self.decl.clean(),
onceness: self.onceness,
fn_style: self.fn_style,
bounds: match self.bounds {
Some(ref x) => x.clean(),
None => Vec::new()
},
bounds: self.bounds.clean()
}
}
}
@ -909,7 +914,7 @@ impl Clean<RetStyle> for ast::RetStyle {
pub struct Trait {
pub items: Vec<TraitItem>,
pub generics: Generics,
pub parents: Vec<Type>,
pub bounds: Vec<TyParamBound>,
}
impl Clean<Item> for doctree::Trait {
@ -924,7 +929,7 @@ impl Clean<Item> for doctree::Trait {
inner: TraitItem(Trait {
items: self.items.clean(),
generics: self.generics.clean(),
parents: self.parents.clean(),
bounds: self.bounds.clean(),
}),
}
}
@ -1060,7 +1065,7 @@ pub enum Type {
Self(ast::DefId),
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(Primitive),
Closure(Box<ClosureDecl>, Option<Lifetime>),
Closure(Box<ClosureDecl>),
Proc(Box<ClosureDecl>),
/// extern "ABI" fn
BareFunction(Box<BareFunctionDecl>),
@ -1208,7 +1213,7 @@ impl Clean<Type> for ast::Ty {
tpbs.clean().map(|x| x),
id)
}
TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
TyClosure(ref c) => Closure(box c.clean()),
TyProc(ref c) => Proc(box c.clean()),
TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
TyParen(ref ty) => ty.clean(),
@ -1273,11 +1278,11 @@ impl Clean<Type> for ty::t {
decl: (ast_util::local_def(0), &fty.sig).clean(),
onceness: fty.onceness,
fn_style: fty.fn_style,
bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
bounds: fty.bounds.clean(),
};
match fty.store {
ty::UniqTraitStore => Proc(decl),
ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
ty::RegionTraitStore(..) => Closure(decl),
}
}
ty::ty_struct(did, ref substs) |

View File

@ -156,7 +156,7 @@ pub struct Trait {
pub name: Ident,
pub items: Vec<ast::TraitItem>, //should be TraitItem
pub generics: ast::Generics,
pub parents: Vec<ast::TraitRef>,
pub bounds: Vec<ast::TyParamBound>,
pub attrs: Vec<ast::Attribute>,
pub id: ast::NodeId,
pub whence: Span,

View File

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

View File

@ -1610,12 +1610,12 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
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 {

View File

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

View File

@ -26,7 +26,8 @@ pub struct Exclusive<T> {
data: UnsafeCell<T>,
}
/// An RAII guard returned via `lock`
/// stage0 only
#[cfg(stage0)]
pub struct ExclusiveGuard<'a, T> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
@ -34,6 +35,15 @@ pub struct ExclusiveGuard<'a, T> {
_guard: mutex::LockGuard<'a>,
}
/// An RAII guard returned via `lock`
#[cfg(not(stage0))]
pub struct ExclusiveGuard<'a, T:'a> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_data: &'a mut T,
_guard: mutex::LockGuard<'a>,
}
impl<T: Send> Exclusive<T> {
/// Creates a new `Exclusive` which will protect the data provided.
pub fn new(user_data: T) -> Exclusive<T> {

View File

@ -19,6 +19,7 @@
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
#![feature(import_shadowing)]
#![feature(issue_5723_bootstrap)]
#![no_std]
#![experimental]
@ -98,7 +99,7 @@ pub trait Runtime {
fn can_block(&self) -> bool;
// FIXME: This is a serious code smell and this should not exist at all.
fn wrap(self: Box<Self>) -> Box<Any>;
fn wrap(self: Box<Self>) -> Box<Any+'static>;
}
/// The default error code of the rust runtime if the main task fails instead

View File

@ -144,6 +144,16 @@ unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
///
/// The task-local data can be accessed through this value, and when this
/// structure is dropped it will return the borrow on the data.
#[cfg(not(stage0))]
pub struct Ref<T:'static> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_inner: &'static TLDValueBox<T>,
_marker: marker::NoSend
}
/// stage0 only
#[cfg(stage0)]
pub struct Ref<T> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref

View File

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

View File

@ -103,7 +103,7 @@ pub struct Task {
pub name: Option<SendStr>,
state: TaskState,
imp: Option<Box<Runtime + Send>>,
imp: Option<Box<Runtime + Send + 'static>>,
}
// Once a task has entered the `Armed` state it must be destroyed via `drop`,
@ -353,14 +353,14 @@ impl Task {
/// Inserts a runtime object into this task, transferring ownership to the
/// task. It is illegal to replace a previous runtime object in this task
/// with this argument.
pub fn put_runtime(&mut self, ops: Box<Runtime + Send>) {
pub fn put_runtime(&mut self, ops: Box<Runtime + Send + 'static>) {
assert!(self.imp.is_none());
self.imp = Some(ops);
}
/// Removes the runtime from this task, transferring ownership to the
/// caller.
pub fn take_runtime(&mut self) -> Box<Runtime + Send> {
pub fn take_runtime(&mut self) -> Box<Runtime + Send + 'static> {
assert!(self.imp.is_some());
self.imp.take().unwrap()
}
@ -390,7 +390,7 @@ impl Task {
Ok(t) => Some(t),
Err(t) => {
let data = mem::transmute::<_, raw::TraitObject>(t).data;
let obj: Box<Runtime + Send> =
let obj: Box<Runtime + Send + 'static> =
mem::transmute(raw::TraitObject {
vtable: vtable,
data: data,

View File

@ -26,11 +26,18 @@ pub struct Access<T> {
inner: Arc<UnsafeCell<Inner<T>>>,
}
#[cfg(stage0)]
pub struct Guard<'a, T> {
access: &'a mut Access<T>,
missile: Option<HomingMissile>,
}
#[cfg(not(stage0))]
pub struct Guard<'a, T:'static> {
access: &'a mut Access<T>,
missile: Option<HomingMissile>,
}
struct Inner<T> {
queue: Vec<(BlockedTask, uint)>,
held: bool,

View File

@ -28,12 +28,20 @@ pub struct AccessTimeout<T> {
pub access: access::Access<T>,
}
#[cfg(stage0)]
pub struct Guard<'a, T> {
state: &'a mut TimeoutState,
pub access: access::Guard<'a, T>,
pub can_timeout: bool,
}
#[cfg(not(stage0))]
pub struct Guard<'a, T:'static> {
state: &'a mut TimeoutState,
pub access: access::Guard<'a, T>,
pub can_timeout: bool,
}
#[deriving(PartialEq)]
enum TimeoutState {
NoTimeout,

View File

@ -382,7 +382,7 @@ fn fmt_number_or_null(v: f64) -> String {
/// A structure for implementing serialization to JSON.
pub struct Encoder<'a> {
writer: &'a mut io::Writer,
writer: &'a mut io::Writer+'a,
}
impl<'a> Encoder<'a> {
@ -594,7 +594,7 @@ impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
/// Another encoder for JSON, but prints out human-readable JSON instead of
/// compact data
pub struct PrettyEncoder<'a> {
writer: &'a mut io::Writer,
writer: &'a mut io::Writer+'a,
curr_indent: uint,
indent: uint,
}

View File

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

View File

@ -409,20 +409,38 @@ mod table {
assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
}
/// Iterator over shared references to entries in a table.
/// Note: stage0-specific version that lacks bound.
#[cfg(stage0)]
pub struct Entries<'a, K, V> {
table: &'a RawTable<K, V>,
idx: uint,
elems_seen: uint,
}
/// Iterator over mutable references to entries in a table.
/// Iterator over shared references to entries in a table.
#[cfg(not(stage0))]
pub struct Entries<'a, K:'a, V:'a> {
table: &'a RawTable<K, V>,
idx: uint,
elems_seen: uint,
}
/// Note: stage0-specific version that lacks bound.
#[cfg(stage0)]
pub struct MutEntries<'a, K, V> {
table: &'a mut RawTable<K, V>,
idx: uint,
elems_seen: uint,
}
/// Iterator over mutable references to entries in a table.
#[cfg(not(stage0))]
pub struct MutEntries<'a, K:'a, V:'a> {
table: &'a mut RawTable<K, V>,
idx: uint,
elems_seen: uint,
}
/// Iterator over the entries in a table, consuming the table.
pub struct MoveEntries<K, V> {
table: RawTable<K, V>,

View File

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

View File

@ -945,11 +945,11 @@ pub trait Reader {
}
}
impl Reader for Box<Reader> {
impl Reader for Box<Reader+'static> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
}
impl<'a> Reader for &'a mut Reader {
impl<'a> Reader for &'a mut Reader+'a {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
}
@ -976,6 +976,13 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
})
}
/// Note: stage0-specific version that lacks bound.
#[cfg(stage0)]
pub struct RefReader<'a, R> {
/// The underlying reader which this is referencing
inner: &'a mut R
}
/// A `RefReader` is a struct implementing `Reader` which contains a reference
/// to another reader. This is often useful when composing streams.
///
@ -1000,7 +1007,8 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
///
/// # }
/// ```
pub struct RefReader<'a, R> {
#[cfg(not(stage0))]
pub struct RefReader<'a, R:'a> {
/// The underlying reader which this is referencing
inner: &'a mut R
}
@ -1058,12 +1066,21 @@ pub trait Writer {
///
/// This function will return any I/O error reported while formatting.
fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
// Create a shim which translates a Writer to a FormatWriter and saves
// off I/O errors. instead of discarding them
// Note: stage0-specific version that lacks bound.
#[cfg(stage0)]
struct Adaptor<'a, T> {
inner: &'a mut T,
error: IoResult<()>,
}
// Create a shim which translates a Writer to a FormatWriter and saves
// off I/O errors. instead of discarding them
#[cfg(not(stage0))]
struct Adaptor<'a, T:'a> {
inner: &'a mut T,
error: IoResult<()>,
}
impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
fn write(&mut self, bytes: &[u8]) -> fmt::Result {
match self.inner.write(bytes) {
@ -1278,7 +1295,7 @@ pub trait Writer {
}
}
impl Writer for Box<Writer> {
impl Writer for Box<Writer+'static> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
@ -1286,7 +1303,7 @@ impl Writer for Box<Writer> {
fn flush(&mut self) -> IoResult<()> { self.flush() }
}
impl<'a> Writer for &'a mut Writer {
impl<'a> Writer for &'a mut Writer+'a {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
@ -1318,11 +1335,42 @@ impl<'a> Writer for &'a mut Writer {
/// println!("input processed: {}", output.unwrap());
/// # }
/// ```
#[cfg(stage0)]
pub struct RefWriter<'a, W> {
/// The underlying writer which this is referencing
inner: &'a mut W
}
/// A `RefWriter` is a struct implementing `Writer` which contains a reference
/// to another writer. This is often useful when composing streams.
///
/// # Example
///
/// ```
/// # fn main() {}
/// # fn process_input<R: Reader>(r: R) {}
/// # fn foo () {
/// use std::io::util::TeeReader;
/// use std::io::{stdin, MemWriter};
///
/// let mut output = MemWriter::new();
///
/// {
/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a
/// // handle to it in the outer scope
/// let mut tee = TeeReader::new(stdin(), output.by_ref());
/// process_input(tee);
/// }
///
/// println!("input processed: {}", output.unwrap());
/// # }
/// ```
#[cfg(not(stage0))]
pub struct RefWriter<'a, W:'a> {
/// The underlying writer which this is referencing
inner: &'a mut W
}
impl<'a, W: Writer> Writer for RefWriter<'a, W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
@ -1351,10 +1399,29 @@ impl<T: Reader + Writer> Stream for T {}
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
#[cfg(stage0)]
pub struct Lines<'r, T> {
buffer: &'r mut T,
}
/// An iterator that reads a line on each iteration,
/// until `.read_line()` encounters `EndOfFile`.
///
/// # Notes about the Iteration Protocol
///
/// The `Lines` may yield `None` and thus terminate
/// an iteration, but continue to yield elements if iteration
/// is attempted again.
///
/// # Error
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
#[cfg(not(stage0))]
pub struct Lines<'r, T:'r> {
buffer: &'r mut T,
}
impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
fn next(&mut self) -> Option<IoResult<String>> {
match self.buffer.read_line() {
@ -1378,10 +1445,29 @@ impl<'r, T: Buffer> Iterator<IoResult<String>> for Lines<'r, T> {
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
#[cfg(stage0)]
pub struct Chars<'r, T> {
buffer: &'r mut T
}
/// An iterator that reads a utf8-encoded character on each iteration,
/// until `.read_char()` encounters `EndOfFile`.
///
/// # Notes about the Iteration Protocol
///
/// The `Chars` may yield `None` and thus terminate
/// an iteration, but continue to yield elements if iteration
/// is attempted again.
///
/// # Error
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
#[cfg(not(stage0))]
pub struct Chars<'r, T:'r> {
buffer: &'r mut T
}
impl<'r, T: Buffer> Iterator<IoResult<char>> for Chars<'r, T> {
fn next(&mut self) -> Option<IoResult<char>> {
match self.buffer.read_char() {
@ -1611,6 +1697,12 @@ pub trait Acceptor<T> {
}
}
/// Note: stage0-specific version that lacks bound on A.
#[cfg(stage0)]
pub struct IncomingConnections<'a, A> {
inc: &'a mut A,
}
/// An infinite iterator over incoming connection attempts.
/// Calling `next` will block the task until a connection is attempted.
///
@ -1618,7 +1710,8 @@ pub trait Acceptor<T> {
/// `Some`. The `Some` contains the `IoResult` representing whether the
/// connection attempt was successful. A successful connection will be wrapped
/// in `Ok`. A failed connection is represented as an `Err`.
pub struct IncomingConnections<'a, A> {
#[cfg(not(stage0))]
pub struct IncomingConnections<'a, A:'a> {
inc: &'a mut A,
}

View File

@ -126,12 +126,12 @@ impl Buffer for NullReader {
/// The `Writer`s are delegated to in order. If any `Writer` returns an error,
/// that error is returned immediately and remaining `Writer`s are not called.
pub struct MultiWriter {
writers: Vec<Box<Writer>>
writers: Vec<Box<Writer+'static>>
}
impl MultiWriter {
/// Creates a new `MultiWriter`
pub fn new(writers: Vec<Box<Writer>>) -> MultiWriter {
pub fn new(writers: Vec<Box<Writer+'static>>) -> MultiWriter {
MultiWriter { writers: writers }
}
}

View File

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

View File

@ -825,12 +825,20 @@ pub trait GenericPathUnsafe {
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
}
/// Helper struct for printing paths with format!()
/// Note: stage0-specific version that lacks bound.
#[cfg(stage0)]
pub struct Display<'a, P> {
path: &'a P,
filename: bool
}
/// Helper struct for printing paths with format!()
#[cfg(not(stage0))]
pub struct Display<'a, P:'a> {
path: &'a P,
filename: bool
}
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.as_maybe_owned().as_slice().fmt(f)

View File

@ -291,7 +291,7 @@ mod imp {
struct Context<'a> {
idx: int,
writer: &'a mut Writer,
writer: &'a mut Writer+'a,
last_error: Option<IoError>,
}

View File

@ -386,6 +386,14 @@ pub struct Receiver<T> {
/// whenever `next` is called, waiting for a new message, and `None` will be
/// returned when the corresponding channel has hung up.
#[unstable]
#[cfg(not(stage0))]
pub struct Messages<'a, T:'a> {
rx: &'a Receiver<T>
}
/// Stage0 only
#[cfg(stage0)]
#[unstable]
pub struct Messages<'a, T> {
rx: &'a Receiver<T>
}

Some files were not shown because too many files have changed in this diff Show More