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,9 +144,12 @@ 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| {
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",
"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 `{}`",
@ -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};
@ -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() {
// 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();
// 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 where_clause.predicates.iter() {
for predicate in generics.where_clause.predicates.iter() {
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds, ());
}
return collector.names;
struct FreeLifetimeCollector {
names: Vec<ast::Name>,
}
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,7 +1741,7 @@ pub fn mk_ctor_fn(cx: &ctxt,
pub fn mk_trait(cx: &ctxt,
did: ast::DefId,
substs: Substs,
bounds: BuiltinBounds)
bounds: ExistentialBounds)
-> t {
// take a copy of substs so that we own the vectors inside
let inner = box TyTrait {
@ -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,7 +2521,8 @@ 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,
kind_bounds_to_contents(
cx,
tp_def.bounds.builtin_bounds,
tp_def.bounds.trait_bounds.as_slice())
}
@ -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,
ty::ClosureTy {fn_style: b.fn_style,
onceness: ast::Many,
store: store,
bounds: ty::all_builtin_bounds(),
bounds: bounds,
sig: b.sig.clone(),
abi: b.abi,
})
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,
pub fn try_add_builtin_trait(
tcx: &ctxt,
trait_def_id: ast::DefId,
builtin_bounds: &mut BuiltinBounds) -> bool {
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,
mk_rptr(tcx, ptr_region,
mt {mutbl: ast::MutMutable,
ty: mk_trait(tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
empty_builtin_bounds()) })))
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
@ -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 = conv_builtin_bounds(this.tcx(),
let bounds = match *opt_bounds {
None => {
conv_existential_bounds(this,
rscope,
path.span,
bounds,
static_region);
[result.clone()].as_slice(),
[].as_slice())
}
Some(ref bounds) => {
conv_existential_bounds(this,
rscope,
path.span,
[result.clone()].as_slice(),
bounds.as_slice())
}
};
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(),
let bounds = conv_existential_bounds(this,
rscope,
ast_ty.span,
&f.bounds,
bound_region == ty::ReStatic);
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
[].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(),
let bounds = conv_existential_bounds(this, rscope,
ast_ty.span,
&f.bounds,
false);
[].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
};
@ -810,10 +826,16 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
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);
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(),
@ -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,
pub fn conv_existential_bounds<AC:AstConv, RS:RegionScope>(
this: &AC,
rscope: &RS,
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:>".
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.
*/
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.
*/
match ast_bounds {
&Some(ref bound_vec) => {
let mut builtin_bounds = ty::empty_builtin_bounds();
for ast_bound in bound_vec.iter() {
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) => {
if ty::try_add_builtin_trait(tcx, 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
}
}
_ => { }
}
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.");
_ => {
// 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);
}
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
ast::UnboxedFnTyParamBound(ref unboxed_function) => {
unboxed_fn_ty_bounds.push(unboxed_function);
}
&None => ty::empty_builtin_bounds(),
}
}
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,15 +615,17 @@ 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,
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, &m);
tcx, span, did, &rcvr_substs, bounds, &m);
Some(Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
@ -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,9 +703,11 @@ 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,
fn push_inherent_candidates_from_bounds_inner(
&mut self,
bounds: &[Rc<TraitRef>],
mk_cand: |tr: Rc<TraitRef>,
mk_cand: |this: &mut LookupContext,
tr: Rc<TraitRef>,
m: Rc<ty::Method>,
method_num: uint,
bound_num: uint|
@ -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,

View File

@ -102,7 +102,6 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
use middle::typeck::check::method::{DontAutoderefReceiver};
use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::relate_free_regions;
use middle::typeck::check::vtable::VtableContext;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
@ -173,6 +172,43 @@ pub struct Inherited<'a> {
vtable_map: vtable_map,
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
unboxed_closures: RefCell<DefIdMap<ty::UnboxedClosure>>,
// A mapping from each fn's id to its signature, with all bound
// regions replaced with free ones. Unlike the other tables, this
// one is never copied into the tcx: it is only used by regionck.
fn_sig_map: RefCell<NodeMap<Vec<ty::t>>>,
// A set of constraints that regionck must validate. Each
// constraint has the form `T:'a`, meaning "some type `T` must
// outlive the lifetime 'a". These constraints derive from
// instantiated type parameters. So if you had a struct defined
// like
//
// struct Foo<T:'static> { ... }
//
// then in some expression `let x = Foo { ... }` it will
// instantiate the type parameter `T` with a fresh type `$0`. At
// the same time, it will record a region obligation of
// `$0:'static`. This will get checked later by regionck. (We
// can't generally check these things right away because we have
// to wait until types are resolved.)
//
// These are stored in a map keyed to the id of the innermost
// enclosing fn body / static initializer expression. This is
// because the location where the obligation was incurred can be
// relevant with respect to which sublifetime assumptions are in
// place. The reason that we store under the fn-id, and not
// something more fine-grained, is so that it is easier for
// regionck to be sure that it has found *all* the region
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: RefCell<NodeMap<Vec<RegionObligation>>>,
}
struct RegionObligation {
sub_region: ty::Region,
sup_type: ty::t,
origin: infer::SubregionOrigin,
}
/// When type-checking an expression, we propagate downward
@ -232,6 +268,8 @@ enum IsBinopAssignment{
#[deriving(Clone)]
pub struct FnCtxt<'a> {
body_id: ast::NodeId,
// This flag is set to true if, during the writeback phase, we encounter
// a type error in this function.
writeback_errors: Cell<bool>,
@ -243,22 +281,8 @@ pub struct FnCtxt<'a> {
err_count_on_creation: uint,
ret_ty: ty::t,
ps: RefCell<FnStyleState>,
// Sometimes we generate region pointers where the precise region
// to use is not known. For example, an expression like `&x.f`
// where `x` is of type `@T`: in this case, we will be rooting
// `x` onto the stack frame, and we could choose to root it until
// the end of (almost) any enclosing block or expression. We
// want to pick the narrowest block that encompasses all uses.
//
// What we do in such cases is to generate a region variable with
// `region_lb` as a lower bound. The regionck pass then adds
// other constraints based on how the variable is used and region
// inference selects the ultimate value. Finally, borrowck is
// charged with guaranteeing that the value whose address was taken
// can actually be made to live as long as it needs to live.
region_lb: Cell<ast::NodeId>,
ps: RefCell<FnStyleState>,
inh: &'a Inherited<'a>,
@ -313,6 +337,8 @@ impl<'a> Inherited<'a> {
vtable_map: RefCell::new(FnvHashMap::new()),
upvar_borrow_map: RefCell::new(HashMap::new()),
unboxed_closures: RefCell::new(DefIdMap::new()),
fn_sig_map: RefCell::new(NodeMap::new()),
region_obligations: RefCell::new(NodeMap::new()),
}
}
}
@ -322,25 +348,26 @@ pub fn blank_fn_ctxt<'a>(
ccx: &'a CrateCtxt<'a>,
inh: &'a Inherited<'a>,
rty: ty::t,
region_bnd: ast::NodeId)
body_id: ast::NodeId)
-> FnCtxt<'a> {
FnCtxt {
body_id: body_id,
writeback_errors: Cell::new(false),
err_count_on_creation: ccx.tcx.sess.err_count(),
ret_ty: rty,
ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
region_lb: Cell::new(region_bnd),
inh: inh,
ccx: ccx
}
}
fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
fn static_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
// It's kind of a kludge to manufacture a fake function context
// and statement context, but we might as well do write the code only once
let param_env = ty::ParameterEnvironment {
free_substs: subst::Substs::empty(),
bounds: subst::VecPerParamSpace::empty()
bounds: subst::VecPerParamSpace::empty(),
implicit_region_bound: ty::ReStatic,
};
Inherited::new(ccx.tcx, param_env)
}
@ -355,6 +382,15 @@ impl<'a> ExprTyProvider for FnCtxt<'a> {
}
}
struct CheckTypeWellFormedVisitor<'a> { ccx: &'a CrateCtxt<'a> }
impl<'a> Visitor<()> for CheckTypeWellFormedVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
check_type_well_formed(self.ccx, i);
visit::walk_item(self, i, ());
}
}
struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
@ -374,6 +410,13 @@ impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
}
pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
let mut visit = CheckTypeWellFormedVisitor { ccx: ccx };
visit::walk_crate(&mut visit, krate, ());
// If types are not well-formed, it leads to all manner of errors
// downstream, so stop reporting errors at this point.
ccx.tcx.sess.abort_if_errors();
let mut visit = CheckItemTypesVisitor { ccx: ccx };
visit::walk_crate(&mut visit, krate, ());
@ -396,11 +439,11 @@ fn check_bare_fn(ccx: &CrateCtxt,
match ty::get(fty).sty {
ty::ty_bare_fn(ref fn_ty) => {
let inh = Inherited::new(ccx.tcx, param_env);
let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig,
decl, id, body, &inh);
vtable::resolve_in_block(&fcx, body);
regionck::regionck_fn(&fcx, body);
regionck::regionck_fn(&fcx, id, body);
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
}
_ => ccx.tcx.sess.impossible_case(body.span,
@ -465,7 +508,7 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
// non-obvious: the `blk` variable maps to region lb, so
// we have to keep this up-to-date. This
// is... unfortunate. It'd be nice to not need this.
self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
visit::walk_block(self, b, ());
}
// Since an expr occurs as part of the type fixed size arrays we
@ -487,13 +530,16 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
}
fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
fn check_fn<'a>(
ccx: &'a CrateCtxt<'a>,
fn_style: ast::FnStyle,
fn_style_id: ast::NodeId,
fn_sig: &ty::FnSig,
decl: &ast::FnDecl,
id: ast::NodeId,
fn_id: ast::NodeId,
body: &ast::Block,
inherited: &'a Inherited<'a>) -> FnCtxt<'a>
inherited: &'a Inherited<'a>)
-> FnCtxt<'a>
{
/*!
* Helper used by check_bare_fn and check_expr_fn. Does the
@ -514,30 +560,42 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
});
relate_free_regions(tcx, &fn_sig);
let arg_tys = fn_sig.inputs.as_slice();
let ret_ty = fn_sig.output;
debug!("check_fn(arg_tys={}, ret_ty={})",
debug!("check_fn(arg_tys={}, ret_ty={}, fn_id={})",
arg_tys.repr(tcx),
ret_ty.repr(tcx));
ret_ty.repr(tcx),
fn_id);
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let fcx = FnCtxt {
body_id: body.id,
writeback_errors: Cell::new(false),
err_count_on_creation: err_count_on_creation,
ret_ty: ret_ty,
ps: RefCell::new(FnStyleState::function(fn_style, id)),
region_lb: Cell::new(body.id),
ps: RefCell::new(FnStyleState::function(fn_style, fn_style_id)),
inh: inherited,
ccx: ccx
};
{
// Remember return type so that regionck can access it later.
let fn_sig_tys: Vec<ty::t> =
arg_tys.iter()
.chain([ret_ty].iter())
.map(|&ty| ty)
.collect();
debug!("fn-sig-map: fn_id={} fn_sig_tys={}",
fn_id,
fn_sig_tys.repr(tcx));
inherited.fn_sig_map
.borrow_mut()
.insert(fn_id, fn_sig_tys);
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
// Create type variables for each argument.
@ -662,6 +720,71 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
}
}
fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) {
/*!
* Checks that the field types (in a struct def'n) or
* argument types (in an enum def'n) are well-formed,
* meaning that they do not require any constraints not
* declared in the struct definition itself.
* For example, this definition would be illegal:
*
* struct Ref<'a, T> { x: &'a T }
*
* because the type did not declare that `T:'a`.
*
* We do this check as a pre-pass before checking fn bodies
* because if these constraints are not included it frequently
* leads to confusing errors in fn bodies. So it's better to check
* the types first.
*/
debug!("check_type_well_formed(it.id={}, it.ident={})",
item.id,
ty::item_path_str(ccx.tcx, local_def(item.id)));
match item.node {
ast::ItemStruct(..) => {
check_type_defn(ccx, item, |fcx| {
ty::struct_fields(ccx.tcx, local_def(item.id),
&fcx.inh.param_env.free_substs)
.iter()
.map(|f| f.mt.ty)
.collect()
});
}
ast::ItemEnum(..) => {
check_type_defn(ccx, item, |fcx| {
ty::substd_enum_variants(ccx.tcx, local_def(item.id),
&fcx.inh.param_env.free_substs)
.iter()
.flat_map(|variant| {
variant.args
.iter()
.map(|&arg_ty| arg_ty)
})
.collect()
});
}
_ => {}
}
fn check_type_defn(ccx: &CrateCtxt,
item: &ast::Item,
lookup_fields: |&FnCtxt| -> Vec<ty::t>)
{
let item_def_id = local_def(item.id);
let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
let param_env =
ty::construct_parameter_environment(ccx.tcx,
&polytype.generics,
item.id);
let inh = Inherited::new(ccx.tcx, param_env);
let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
let field_tys = lookup_fields(&fcx);
regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice());
}
}
pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
debug!("check_item(it.id={}, it.ident={})",
it.id,
@ -977,9 +1100,6 @@ fn compare_impl_method(tcx: &ty::ctxt,
return;
}
let it = trait_m.generics.types.get_slice(subst::FnSpace).iter()
.zip(impl_m.generics.types.get_slice(subst::FnSpace).iter());
// This code is best explained by example. Consider a trait:
//
// trait Trait<T> {
@ -1041,20 +1161,27 @@ fn compare_impl_method(tcx: &ty::ctxt,
let impl_to_skol_substs =
subst::Substs::new(skol_tps.clone(), skol_regions.clone());
// Compute skolemized form of impl method ty.
let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
// Compute skolemized form of trait method ty.
// Create mapping from trait to skolemized.
let trait_to_skol_substs =
trait_to_impl_substs
.subst(tcx, &impl_to_skol_substs)
.with_method(Vec::from_slice(skol_tps.get_slice(subst::FnSpace)),
Vec::from_slice(skol_regions.get_slice(subst::FnSpace)));
let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
// Check region bounds.
if !check_region_bounds_on_impl_method(tcx,
impl_m_span,
impl_m,
&trait_m.generics,
&impl_m.generics,
&trait_to_skol_substs,
&impl_to_skol_substs) {
return;
}
// Check bounds.
let it = trait_m.generics.types.get_slice(subst::FnSpace).iter()
.zip(impl_m.generics.types.get_slice(subst::FnSpace).iter());
for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
// Check that the impl does not require any builtin-bounds
// that the trait does not guarantee:
@ -1110,6 +1237,12 @@ fn compare_impl_method(tcx: &ty::ctxt,
}
}
// Compute skolemized form of impl and trait method tys.
let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
// Check the impl method type IM is a subtype of the trait method
// type TM. To see why this makes sense, think of a vtable. The
// expected type of the function pointers in the vtable is the
@ -1134,6 +1267,152 @@ fn compare_impl_method(tcx: &ty::ctxt,
// Finally, resolve all regions. This catches wily misuses of lifetime
// parameters.
infcx.resolve_regions_and_report_errors();
fn check_region_bounds_on_impl_method(tcx: &ty::ctxt,
span: Span,
impl_m: &ty::Method,
trait_generics: &ty::Generics,
impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs,
impl_to_skol_substs: &Substs)
-> bool
{
/*!
Check that region bounds on impl method are the same as those
on the trait. In principle, it could be ok for there to be
fewer region bounds on the impl method, but this leads to an
annoying corner case that is painful to handle (described
below), so for now we can just forbid it.
Example (see
`src/test/compile-fail/regions-bound-missing-bound-in-impl.rs`):
trait Foo<'a> {
fn method1<'b>();
fn method2<'b:'a>();
}
impl<'a> Foo<'a> for ... {
fn method1<'b:'a>() { .. case 1, definitely bad .. }
fn method2<'b>() { .. case 2, could be ok .. }
}
The "definitely bad" case is case #1. Here, the impl adds an
extra constraint not present in the trait.
The "maybe bad" case is case #2. Here, the impl adds an extra
constraint not present in the trait. We could in principle
allow this, but it interacts in a complex way with early/late
bound resolution of lifetimes. Basically the presence or
absence of a lifetime bound affects whether the lifetime is
early/late bound, and right now the code breaks if the trait
has an early bound lifetime parameter and the method does not.
*/
let trait_params = trait_generics.regions.get_slice(subst::FnSpace);
let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
debug!("check_region_bounds_on_impl_method: \
trait_generics={} \
impl_generics={}",
trait_generics.repr(tcx),
impl_generics.repr(tcx));
// Must have same number of early-bound lifetime parameters.
// Unfortunately, if the user screws up the bounds, then this
// will change classification between early and late. E.g.,
// if in trait we have `<'a,'b:'a>`, and in impl we just have
// `<'a,'b>`, then we have 2 early-bound lifetime parameters
// in trait but 0 in the impl. But if we report "expected 2
// but found 0" it's confusing, because it looks like there
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
tcx.sess.span_err(
span,
format!("lifetime parameters or bounds on method `{}` do \
not match the trait declaration",
token::get_ident(impl_m.ident)).as_slice());
return false;
}
// Each parameter `'a:'b+'c+'d` in trait should have the same
// set of bounds in the impl, after subst.
for (trait_param, impl_param) in
trait_params.iter().zip(
impl_params.iter())
{
let trait_bounds =
trait_param.bounds.subst(tcx, trait_to_skol_substs);
let impl_bounds =
impl_param.bounds.subst(tcx, impl_to_skol_substs);
debug!("check_region_bounds_on_impl_method: \
trait_param={} \
impl_param={} \
trait_bounds={} \
impl_bounds={}",
trait_param.repr(tcx),
impl_param.repr(tcx),
trait_bounds.repr(tcx),
impl_bounds.repr(tcx));
// Collect the set of bounds present in trait but not in
// impl.
let missing: Vec<ty::Region> =
trait_bounds.iter()
.filter(|&b| !impl_bounds.contains(b))
.map(|&b| b)
.collect();
// Collect set present in impl but not in trait.
let extra: Vec<ty::Region> =
impl_bounds.iter()
.filter(|&b| !trait_bounds.contains(b))
.map(|&b| b)
.collect();
debug!("missing={} extra={}",
missing.repr(tcx), extra.repr(tcx));
let err = if missing.len() != 0 || extra.len() != 0 {
tcx.sess.span_err(
span,
format!(
"the lifetime parameter `{}` declared in the impl \
has a distinct set of bounds \
from its counterpart `{}` \
declared in the trait",
impl_param.name.user_string(tcx),
trait_param.name.user_string(tcx)).as_slice());
true
} else {
false
};
if missing.len() != 0 {
tcx.sess.span_note(
span,
format!("the impl is missing the following bounds: `{}`",
missing.user_string(tcx)).as_slice());
}
if extra.len() != 0 {
tcx.sess.span_note(
span,
format!("the impl has the following extra bounds: `{}`",
extra.user_string(tcx)).as_slice());
}
if err {
return false;
}
}
return true;
}
}
fn check_cast(fcx: &FnCtxt,
@ -1163,6 +1442,7 @@ fn check_cast(fcx: &FnCtxt,
fcx.write_error(id);
return
}
if ty::type_is_bot(t_e) {
fcx.write_bot(id);
return
@ -1301,6 +1581,8 @@ impl<'a> AstConv for FnCtxt<'a> {
}
impl<'a> FnCtxt<'a> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
&self.inh.infcx
}
@ -1319,6 +1601,10 @@ impl<'a> FnCtxt<'a> {
}
impl<'a> RegionScope for infer::InferCtxt<'a> {
fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
Some(self.next_region_var(infer::MiscVariable(span)))
}
fn anon_regions(&self, span: Span, count: uint)
-> Result<Vec<ty::Region> , ()> {
Ok(Vec::from_fn(count, |_| {
@ -1494,19 +1780,10 @@ impl<'a> FnCtxt<'a> {
}
pub fn mk_subr(&self,
a_is_expected: bool,
origin: infer::SubregionOrigin,
sub: ty::Region,
sup: ty::Region) {
infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
}
pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
let old_region_lb = self.region_lb.get();
self.region_lb.set(lb);
let v = f();
self.region_lb.set(old_region_lb);
v
infer::mk_subr(self.infcx(), origin, sub, sup)
}
pub fn type_error_message(&self,
@ -1536,6 +1813,112 @@ impl<'a> FnCtxt<'a> {
err: &ty::type_err) {
self.infcx().report_mismatched_types(sp, e, a, err)
}
pub fn register_region_obligation(&self,
origin: infer::SubregionOrigin,
ty: ty::t,
r: ty::Region)
{
/*!
* Registers an obligation for checking later, during
* regionck, that the type `ty` must outlive the region `r`.
*/
let mut region_obligations = self.inh.region_obligations.borrow_mut();
let v = region_obligations.find_or_insert_with(self.body_id,
|_| Vec::new());
v.push(RegionObligation { sub_region: r,
sup_type: ty,
origin: origin });
}
pub fn add_region_obligations_for_parameters(&self,
span: Span,
substs: &Substs,
generics: &ty::Generics)
{
/*!
* Given a set of generic parameter definitions (`generics`)
* and the values provided for each of them (`substs`),
* creates and registers suitable region obligations.
*
* For example, if there is a function:
*
* fn foo<'a,T:'a>(...)
*
* and a reference:
*
* let f = foo;
*
* Then we will create a fresh region variable `'$0` and a
* fresh type variable `$1` for `'a` and `T`. This routine
* will add a region obligation `$1:'$0` and register it
* locally.
*/
debug!("add_region_obligations_for_parameters(substs={}, generics={})",
substs.repr(self.tcx()),
generics.repr(self.tcx()));
assert_eq!(generics.types.iter().len(),
substs.types.iter().len());
for (type_def, &type_param) in
generics.types.iter().zip(
substs.types.iter())
{
let param_ty = ty::ParamTy { space: type_def.space,
idx: type_def.index,
def_id: type_def.def_id };
let bounds = type_def.bounds.subst(self.tcx(), substs);
add_region_obligations_for_type_parameter(
self, span, param_ty, &bounds, type_param);
}
assert_eq!(generics.regions.iter().len(),
substs.regions().iter().len());
for (region_def, &region_param) in
generics.regions.iter().zip(
substs.regions().iter())
{
let bounds = region_def.bounds.subst(self.tcx(), substs);
add_region_obligations_for_region_parameter(
self, span, bounds.as_slice(), region_param);
}
fn add_region_obligations_for_type_parameter(
fcx: &FnCtxt,
span: Span,
param_ty: ty::ParamTy,
param_bound: &ty::ParamBounds,
ty: ty::t)
{
// For each declared region bound `T:r`, `T` must outlive `r`.
let region_bounds =
ty::required_region_bounds(
fcx.tcx(),
param_bound.opt_region_bound.as_slice(),
param_bound.builtin_bounds,
param_bound.trait_bounds.as_slice());
for &r in region_bounds.iter() {
let origin = infer::RelateParamBound(span, param_ty, ty);
fcx.register_region_obligation(origin, ty, r);
}
}
fn add_region_obligations_for_region_parameter(
fcx: &FnCtxt,
span: Span,
region_bounds: &[ty::Region],
region_param: ty::Region)
{
for &b in region_bounds.iter() {
// For each bound `region:b`, `b <= region` must hold
// (i.e., `region` must outlive `b`).
let origin = infer::RelateRegionParamBound(span);
fcx.mk_subr(origin, b, region_param);
}
}
}
}
pub enum LvaluePreference {
@ -2269,7 +2652,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
lvalue_pref: LvaluePreference,
unifier: ||)
{
debug!(">> typechecking");
debug!(">> typechecking: expr={} expected={}",
expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
// A generic function for doing all of the checking for call expressions
fn check_call(fcx: &FnCtxt,
@ -2674,17 +3058,19 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
kind: ast::UnboxedClosureKind,
decl: &ast::FnDecl,
body: ast::P<ast::Block>) {
// The `RegionTraitStore` is a lie, but we ignore it so it doesn't
// matter.
//
// FIXME(pcwalton): Refactor this API.
let mut fn_ty = astconv::ty_of_closure(
fcx,
expr.id,
ast::NormalFn,
ast::Many,
ty::empty_builtin_bounds(),
// The `RegionTraitStore` and region_existential_bounds
// are lies, but we ignore them so it doesn't matter.
//
// FIXME(pcwalton): Refactor this API.
ty::region_existential_bound(ty::ReStatic),
ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
decl,
abi::RustCall,
None);
@ -2703,6 +3089,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
check_fn(fcx.ccx,
ast::NormalFn,
expr.id,
&fn_ty.sig,
decl,
expr.id,
@ -2776,13 +3163,17 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}
_ => {
// Not an error! Means we're inferring the closure type
let mut bounds = ty::empty_builtin_bounds();
let onceness = match expr.node {
let (bounds, onceness) = match expr.node {
ast::ExprProc(..) => {
bounds.add(ty::BoundSend);
ast::Once
let mut bounds = ty::region_existential_bound(ty::ReStatic);
bounds.builtin_bounds.add(ty::BoundSend); // FIXME
(bounds, ast::Once)
}
_ => {
let region = fcx.infcx().next_region_var(
infer::AddrOfRegion(expr.span));
(ty::region_existential_bound(region), ast::Many)
}
_ => ast::Many
};
(None, onceness, bounds)
}
@ -2808,7 +3199,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
// If the closure is a stack closure and hasn't had some non-standard
// style inferred for it, then check it under its parent's style.
// Otherwise, use its own
let (inherited_style, id) = match store {
let (inherited_style, inherited_style_id) = match store {
ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
fcx.ps.borrow().def),
ty::UniqTraitStore => (ast::NormalFn, expr.id)
@ -2816,9 +3207,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
check_fn(fcx.ccx,
inherited_style,
inherited_style_id,
&fty_sig,
decl,
id,
&*decl,
expr.id,
&*body,
fcx.inh);
}
@ -3080,13 +3472,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
// places: the exchange heap and the managed heap.
let definition = lookup_def(fcx, path.span, place.id);
let def_id = definition.def_id();
let referent_ty = fcx.expr_ty(&**subexpr);
if tcx.lang_items.exchange_heap() == Some(def_id) {
fcx.write_ty(id, ty::mk_uniq(tcx,
fcx.expr_ty(&**subexpr)));
fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty));
checked = true
} else if tcx.lang_items.managed_heap() == Some(def_id) {
fcx.write_ty(id, ty::mk_box(tcx,
fcx.expr_ty(&**subexpr)));
fcx.register_region_obligation(infer::Managed(expr.span),
referent_ty,
ty::ReStatic);
fcx.write_ty(id, ty::mk_box(tcx, referent_ty));
checked = true
}
}
@ -3270,7 +3664,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
//ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd),
// Empty slices live in static memory.
ast::ExprVec(ref elements) if elements.len() == 0 => {
ty::mk_rptr(tcx, ty::ReStatic, tm)
// Note: we do not assign a lifetime of
// static. This is because the resulting type
// `&'static [T]` would require that T outlives
// `'static`!
let region = fcx.infcx().next_region_var(
infer::AddrOfSlice(expr.span));
ty::mk_rptr(tcx, region, tm)
}
_ => {
let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span));
@ -3284,6 +3684,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
let defn = lookup_def(fcx, pth.span, id);
let pty = polytype_for_def(fcx, expr.span, defn);
instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
// We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation.
constrain_path_type_parameters(fcx, expr);
}
ast::ExprInlineAsm(ref ia) => {
for &(_, ref input) in ia.inputs.iter() {
@ -3708,6 +4112,18 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
unifier();
}
fn constrain_path_type_parameters(fcx: &FnCtxt,
expr: &ast::Expr)
{
fcx.opt_node_ty_substs(expr.id, |item_substs| {
for &ty in item_substs.substs.types.iter() {
let default_bound = ty::ReScope(expr.id);
let origin = infer::RelateDefaultParamBound(expr.span, ty);
fcx.register_region_obligation(origin, ty, default_bound);
}
});
}
impl Expectation {
fn only_has_type(self) -> Expectation {
match self {
@ -3889,7 +4305,6 @@ fn check_block_with_expected(fcx: &FnCtxt,
replace(&mut *fcx_ps, fn_style_state)
};
fcx.with_region_lb(blk.id, || {
let mut warned = false;
let mut last_was_bot = false;
let mut any_bot = false;
@ -3962,7 +4377,6 @@ fn check_block_with_expected(fcx: &FnCtxt,
}
}
};
});
*fcx.ps.borrow_mut() = prev;
}
@ -3980,7 +4394,7 @@ pub fn check_const_in_type(tcx: &ty::ctxt,
trait_map: NodeMap::new(),
tcx: tcx,
};
let inh = blank_inherited_fields(&ccx);
let inh = static_inherited_fields(&ccx);
let fcx = blank_fn_ctxt(&ccx, &inh, expected_type, expr.id);
check_const_with_ty(&fcx, expr.span, expr, expected_type);
}
@ -3989,7 +4403,7 @@ pub fn check_const(ccx: &CrateCtxt,
sp: Span,
e: &ast::Expr,
id: ast::NodeId) {
let inh = blank_inherited_fields(ccx);
let inh = static_inherited_fields(ccx);
let rty = ty::node_id_to_type(ccx.tcx, id);
let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
@ -4184,7 +4598,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
Some(e) => {
debug!("disr expr, checking {}", pprust::expr_to_string(&*e));
let inh = blank_inherited_fields(ccx);
let inh = static_inherited_fields(ccx);
let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
let declty = match hint {
attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(),
@ -4495,6 +4909,9 @@ pub fn instantiate_path(fcx: &FnCtxt,
assert_eq!(substs.regions().len(space), region_defs.len(space));
}
fcx.add_region_obligations_for_parameters(
span, &substs, &polytype.generics);
fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts {
substs: substs,
});
@ -4888,8 +5305,10 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
Ok(t) => t,
Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); }
};
let region = ty::ReLateBound(it.id, ty::BrAnon(0));
let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
let region0 = ty::ReLateBound(it.id, ty::BrAnon(0));
let region1 = ty::ReLateBound(it.id, ty::BrAnon(1));
let visitor_object_ty =
match ty::visitor_object_ty(tcx, region0, region1) {
Ok((_, vot)) => vot,
Err(s) => { tcx.sess.span_fatal(it.span, s.as_slice()); }
};
@ -5097,3 +5516,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
}
}
impl Repr for RegionObligation {
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("RegionObligation(sub_region={}, sup_type={}, origin={})",
self.sub_region.repr(tcx),
self.sup_type.repr(tcx),
self.origin.repr(tcx))
}
}

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,26 +585,6 @@ 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.
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);
@ -443,13 +592,21 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
// 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));
}
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,
fn ensure_free_variable_types_outlive_closure_bound(
rcx: &mut Rcx,
region_bound: ty::Region,
expr: &ast::Expr,
freevars: &[freevars::freevar_entry]) {
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 var_node_id = {
let def_id = def.def_id();
assert!(def_id.krate == ast::LOCAL_CRATE);
let upvar_id = ty::UpvarId { var_id: def_id.node,
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>,
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,
relate_op: |ty::Region, ty::Region|) {
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);
struct RegionRelator<'a> {
tcx: &'a ty::ctxt,
stack: Vec<ty::Region>,
relate_op: |ty::Region, ty::Region|: 'a,
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
}
// FIXME(#10151) -- Define more precisely when a region is
// considered "nested". Consider taking variance into account as
// well.
impl<'a> Wf<'a> {
fn accumulate_from_ty(&mut self, ty: ty::t) {
debug!("Wf::accumulate_from_ty(ty={})",
ty.repr(self.tcx));
impl<'a> TypeFolder for RegionRelator<'a> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
self.tcx
}
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);
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.
}
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 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();
}
_ => {
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);
}
}
}
}
}
pub fn relate_free_regions(tcx: &ty::ctxt, fn_sig: &ty::FnSig) {
fn push_region_constraint_from_top(&mut self,
r_b: ty::Region) {
/*!
* 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`
* Pushes a constraint that `r_b` must outlive the
* top region on the stack.
*/
debug!("relate_free_regions >>");
// 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 mut all_tys = Vec::new();
for arg in fn_sig.inputs.iter() {
all_tys.push(*arg);
let &(r_a, opt_ty) = self.stack.last().unwrap();
self.push_sub_region_constraint(opt_ty, r_a, r_b);
}
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);
}
_ => {}
}
})
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));
}
debug!("<< relate_free_regions");
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();
}
}
}
}
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));
}
}
}

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,7 +224,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
}
}
pub fn ensure_trait_methods(ccx: &CrateCtxt,
fn collect_trait_methods(ccx: &CrateCtxt,
trait_id: ast::NodeId,
trait_def: &ty::TraitDef) {
let tcx = ccx.tcx;
@ -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,
let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
let bounds = compute_bounds(ccx,
param.ident.name,
param_ty,
&param.bounds,
param.bounds.as_slice(),
&param.unbound,
param.ident,
param.span,
where_clause));
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,15 +1191,18 @@ fn ty_generics(ccx: &CrateCtxt,
def
}
}
fn compute_bounds(ccx: &CrateCtxt,
fn compute_bounds(
ccx: &CrateCtxt,
name_of_bounded_thing: ast::Name,
param_ty: ty::ParamTy,
ast_bounds: &OwnedSlice<ast::TyParamBound>,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TyParamBound>,
ident: ast::Ident,
span: Span,
where_clause: &ast::WhereClause)
-> ty::ParamBounds {
-> 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
@ -1180,13 +1210,101 @@ fn ty_generics(ccx: &CrateCtxt,
* 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);
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, name_of_bounded_thing,
&param_bounds, span);
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
param_bounds
}
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.builtin_bounds.contains_elem(ty::BoundSized) {
span_err!(tcx.sess, span, E0129,
"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
@ -1201,93 +1319,11 @@ fn ty_generics(ccx: &CrateCtxt,
continue
}
for bound in predicate.bounds.iter() {
compute_bound(ccx, &mut param_bounds, param_ty, bound);
result.push(bound);
}
}
add_unsized_bound(ccx,
unbound,
&mut param_bounds.builtin_bounds,
"type parameter",
span);
check_bounds_compatible(ccx.tcx, &param_bounds, ident, span);
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
param_bounds
}
/// 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);
}
}
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| {
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
if trait_def.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),
ppaux::trait_ref_to_string(tcx, &*trait_ref));
}
true
});
}
}
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,
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(a, b)) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
a, ReInfer(ReVar(b)));
}
&AddConstraint(ConstrainVarSubReg(a, b)) => {
consider_adding_bidirectional_edges(
&mut result_set, r,
ReInfer(ReVar(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);
}
&AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
Some((*a, ReInfer(ReVar(*b))))
}
&AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
Some((ReInfer(ReVar(*a)), *b))
}
&AddConstraint(ConstrainRegSubReg(a, b)) => {
Some((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> ,
fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
r: Region,
r1: Region,
r2: Region) -> Vec<Region> {
let mut result_set = result_set;
if r == r1 { // Clearly, this is potentially inefficient.
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,
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;
}
debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
sub, sup);
let origin = self.constraints.borrow().get_copy(constraint);
errors.push(ConcreteFailure(origin, sub, sup));
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));
}
}
}
}
@ -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={}",
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());
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={}",
for var {}, upper_bounds={}",
node_idx,
upper_bounds.iter()
.map(|x| x.region)
.collect::<Vec<ty::Region>>()
.repr(self.tcx)).as_slice());
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
@ -115,9 +129,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
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);
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 => {
@ -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