Auto merge of #24619 - nrc:rc-coerce, r=nikomatsakis
r? @nikomatsakis (note a few TODOs left in the code where I wasn't sure about stuff).
This commit is contained in:
commit
fa43387527
@ -62,6 +62,11 @@ use core::ops::{Deref, DerefMut};
|
||||
use core::ptr::{Unique};
|
||||
use core::raw::{TraitObject};
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use core::marker::Unsize;
|
||||
#[cfg(not(stage0))]
|
||||
use core::ops::CoerceUnsized;
|
||||
|
||||
/// A value that represents the heap. This is the default place that the `box`
|
||||
/// keyword allocates into when no place is supplied.
|
||||
///
|
||||
@ -390,3 +395,6 @@ impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
|
||||
self.call_box(args)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
||||
|
@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{Hasher, Hash};
|
||||
use core::marker;
|
||||
use core::marker::{self, Sized};
|
||||
use core::mem::{self, min_align_of, size_of, forget};
|
||||
use core::nonzero::NonZero;
|
||||
use core::ops::{Deref, Drop};
|
||||
@ -170,17 +170,36 @@ use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
use core::intrinsics::assume;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use core::intrinsics::drop_in_place;
|
||||
#[cfg(not(stage0))]
|
||||
use core::marker::Unsize;
|
||||
#[cfg(not(stage0))]
|
||||
use core::mem::{min_align_of_val, size_of_val};
|
||||
#[cfg(not(stage0))]
|
||||
use core::ops::CoerceUnsized;
|
||||
|
||||
use heap::deallocate;
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct RcBox<T> {
|
||||
value: T,
|
||||
strong: Cell<usize>,
|
||||
weak: Cell<usize>
|
||||
weak: Cell<usize>,
|
||||
value: T,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
struct RcBox<T: ?Sized> {
|
||||
strong: Cell<usize>,
|
||||
weak: Cell<usize>,
|
||||
value: T,
|
||||
}
|
||||
|
||||
|
||||
/// A reference-counted pointer type over an immutable value.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more details.
|
||||
#[cfg(stage0)]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T> {
|
||||
@ -188,11 +207,30 @@ pub struct Rc<T> {
|
||||
// accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T: ?Sized> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with field
|
||||
// accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Send for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Send for Rc<T> {}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Sync for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Sync for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
|
||||
|
||||
impl<T> Rc<T> {
|
||||
/// Constructs a new `Rc<T>`.
|
||||
///
|
||||
@ -212,14 +250,39 @@ impl<T> Rc<T> {
|
||||
// the allocation while the strong destructor is running, even
|
||||
// if the weak pointer is stored inside the strong one.
|
||||
_ptr: NonZero::new(boxed::into_raw(box RcBox {
|
||||
value: value,
|
||||
strong: Cell::new(1),
|
||||
weak: Cell::new(1)
|
||||
weak: Cell::new(1),
|
||||
value: value
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module")]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> Rc<T> {
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
@ -241,14 +304,24 @@ impl<T> Rc<T> {
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn weak_count<T>(this: &Rc<T>) -> usize { this.weak() - 1 }
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn weak_count<T: ?Sized>(this: &Rc<T>) -> usize { this.weak() - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn strong_count<T>(this: &Rc<T>) -> usize { this.strong() }
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn strong_count<T: ?Sized>(this: &Rc<T>) -> usize { this.strong() }
|
||||
|
||||
/// Returns true if there are no other `Rc` or `Weak<T>` values that share the
|
||||
/// same inner value.
|
||||
@ -365,6 +438,7 @@ impl<T: Clone> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Deref for Rc<T> {
|
||||
type Target = T;
|
||||
@ -374,7 +448,18 @@ impl<T> Deref for Rc<T> {
|
||||
&self.inner().value
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for Rc<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &T {
|
||||
&self.inner().value
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
@ -425,6 +510,61 @@ impl<T> Drop for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
/// count becomes zero and the only other references are `Weak<T>` ones,
|
||||
/// `drop`s the inner value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explicit drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_strong();
|
||||
if self.strong() == 0 {
|
||||
// destroy the contained object
|
||||
drop_in_place(&mut (*ptr).value);
|
||||
|
||||
// remove the implicit "strong weak" pointer now that we've
|
||||
// destroyed the contents.
|
||||
self.dec_weak();
|
||||
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8,
|
||||
size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Clone for Rc<T> {
|
||||
|
||||
@ -449,6 +589,31 @@ impl<T> Clone for Rc<T> {
|
||||
Rc { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for Rc<T> {
|
||||
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
///
|
||||
/// When you clone an `Rc<T>`, it will create another pointer to the data and
|
||||
/// increase the strong reference counter.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
Rc { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Rc<T> {
|
||||
@ -610,27 +775,50 @@ impl<T: Ord> Ord for Rc<T> {
|
||||
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
|
||||
}
|
||||
|
||||
// FIXME (#18248) Make `T` `Sized?`
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Hash> Hash for Rc<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+Hash> Hash for Rc<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display> fmt::Display for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Display> fmt::Display for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Debug> fmt::Debug for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> fmt::Pointer for Rc<T> {
|
||||
@ -645,6 +833,7 @@ impl<T> fmt::Pointer for Rc<T> {
|
||||
/// dropped.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more.
|
||||
#[cfg(stage0)]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
@ -653,12 +842,28 @@ pub struct Weak<T> {
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Send for Weak<T> {}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Send for Weak<T> {}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Sync for Weak<T> {}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Sync for Weak<T> {}
|
||||
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Weak<T> {
|
||||
@ -691,7 +896,41 @@ impl<T> Weak<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was
|
||||
/// destroyed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
if self.strong() == 0 {
|
||||
None
|
||||
} else {
|
||||
self.inc_strong();
|
||||
Some(Rc { _ptr: self._ptr })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
@ -736,6 +975,53 @@ impl<T> Drop for Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explicit drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_weak();
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8, size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Clone for Weak<T> {
|
||||
@ -760,14 +1046,48 @@ impl<T> Clone for Weak<T> {
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: ?Sized> Clone for Weak<T> {
|
||||
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let weak_five = Rc::new(5).downgrade();
|
||||
///
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
trait RcBoxPtr<T> {
|
||||
fn inner(&self) -> &RcBox<T>;
|
||||
@ -790,7 +1110,31 @@ trait RcBoxPtr<T> {
|
||||
#[inline]
|
||||
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[doc(hidden)]
|
||||
trait RcBoxPtr<T: ?Sized> {
|
||||
fn inner(&self) -> &RcBox<T>;
|
||||
|
||||
#[inline]
|
||||
fn strong(&self) -> usize { self.inner().strong.get() }
|
||||
|
||||
#[inline]
|
||||
fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }
|
||||
|
||||
#[inline]
|
||||
fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
|
||||
|
||||
#[inline]
|
||||
fn weak(&self) -> usize { self.inner().weak.get() }
|
||||
|
||||
#[inline]
|
||||
fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }
|
||||
|
||||
#[inline]
|
||||
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> RcBoxPtr<T> for Rc<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
@ -799,12 +1143,27 @@ impl<T> RcBoxPtr<T> for Rc<T> {
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!self._ptr.is_null());
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
unsafe {
|
||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
@ -813,7 +1172,21 @@ impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!self._ptr.is_null());
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> RcBoxPtr<T> for Weak<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
unsafe {
|
||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
|
@ -707,5 +707,4 @@ impl<T: ?Sized> UnsafeCell<T> {
|
||||
#![allow(trivial_casts)]
|
||||
&self.value as *const T as *mut T
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -193,6 +193,13 @@ extern "rust-intrinsic" {
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn pref_align_of<T>() -> usize;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn size_of_val<T: ?Sized>(_: &T) -> usize;
|
||||
#[cfg(not(stage0))]
|
||||
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
|
||||
#[cfg(not(stage0))]
|
||||
pub fn drop_in_place<T: ?Sized>(_: *mut T);
|
||||
|
||||
/// Gets a static string slice containing the name of a type.
|
||||
pub fn type_name<T: ?Sized>() -> &'static str;
|
||||
|
||||
|
@ -53,6 +53,14 @@ pub trait Sized {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be "unsized" to a dynamically sized type.
|
||||
#[unstable(feature = "core")]
|
||||
#[cfg(not(stage0))]
|
||||
#[lang="unsize"]
|
||||
pub trait Unsize<T> {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||
///
|
||||
/// By default, variable bindings have 'move semantics.' In other
|
||||
|
@ -86,6 +86,22 @@ pub fn size_of<T>() -> usize {
|
||||
unsafe { intrinsics::size_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the size of the type that `val` points to in bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// assert_eq!(4, mem::size_of_val(&5i32));
|
||||
/// ```
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
unsafe { intrinsics::size_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the size of the type that `_val` points to in bytes.
|
||||
///
|
||||
/// # Examples
|
||||
@ -95,6 +111,7 @@ pub fn size_of<T>() -> usize {
|
||||
///
|
||||
/// assert_eq!(4, mem::size_of_val(&5i32));
|
||||
/// ```
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn size_of_val<T>(_val: &T) -> usize {
|
||||
@ -118,6 +135,22 @@ pub fn min_align_of<T>() -> usize {
|
||||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// assert_eq!(4, mem::min_align_of_val(&5i32));
|
||||
/// ```
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to
|
||||
///
|
||||
/// # Examples
|
||||
@ -127,6 +160,7 @@ pub fn min_align_of<T>() -> usize {
|
||||
///
|
||||
/// assert_eq!(4, mem::min_align_of_val(&5i32));
|
||||
/// ```
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn min_align_of_val<T>(_val: &T) -> usize {
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
use marker::Sized;
|
||||
use ops::Deref;
|
||||
#[cfg(not(stage0))]
|
||||
use ops::CoerceUnsized;
|
||||
|
||||
/// Unsafe trait to indicate what types are usable with the NonZero struct
|
||||
pub unsafe trait Zeroable {}
|
||||
@ -54,3 +56,6 @@ impl<T: Zeroable> Deref for NonZero<T> {
|
||||
inner
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: Zeroable+CoerceUnsized<U>, U: Zeroable> CoerceUnsized<NonZero<U>> for NonZero<T> {}
|
||||
|
@ -70,6 +70,9 @@
|
||||
use marker::Sized;
|
||||
use fmt;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use marker::Unsize;
|
||||
|
||||
/// The `Drop` trait is used to run some code when a value goes out of scope. This
|
||||
/// is sometimes called a 'destructor'.
|
||||
///
|
||||
@ -1207,3 +1210,43 @@ mod impls {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait that indicates that this is a pointer or a wrapper for one,
|
||||
/// where unsizing can be performed on the pointee.
|
||||
#[unstable(feature = "core")]
|
||||
#[cfg(not(stage0))]
|
||||
#[lang="coerce_unsized"]
|
||||
pub trait CoerceUnsized<T> {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
// &mut T -> &mut U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
|
||||
// &mut T -> &U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
|
||||
// &mut T -> *mut U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
|
||||
// &mut T -> *const U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
|
||||
|
||||
// &T -> &U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
|
||||
// &T -> *const U
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
|
||||
|
||||
// *mut T -> *mut U
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
|
||||
// *mut T -> *const U
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
|
||||
|
||||
// *const T -> *const U
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
|
||||
|
@ -172,14 +172,15 @@ fn unsafe_cell_unsized() {
|
||||
assert_eq!(unsafe { &mut *cell.get() }, comp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refcell_unsized() {
|
||||
let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
|
||||
{
|
||||
let b = &mut *cell.borrow_mut();
|
||||
b[0] = 4;
|
||||
b[2] = 5;
|
||||
}
|
||||
let comp: &mut [i32] = &mut [4, 2, 5];
|
||||
assert_eq!(&*cell.borrow(), comp);
|
||||
}
|
||||
// FIXME(#25351) needs deeply nested coercions of DST structs.
|
||||
// #[test]
|
||||
// fn refcell_unsized() {
|
||||
// let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
|
||||
// {
|
||||
// let b = &mut *cell.borrow_mut();
|
||||
// b[0] = 4;
|
||||
// b[2] = 5;
|
||||
// }
|
||||
// let comp: &mut [i32] = &mut [4, 2, 5];
|
||||
// assert_eq!(&*cell.borrow(), comp);
|
||||
// }
|
||||
|
@ -807,6 +807,7 @@ register_diagnostics! {
|
||||
E0017,
|
||||
E0019,
|
||||
E0022,
|
||||
E0038,
|
||||
E0109,
|
||||
E0110,
|
||||
E0134,
|
||||
|
@ -259,3 +259,5 @@ pub const tag_codemap_filemap: usize = 0xa2;
|
||||
pub const tag_item_super_predicates: usize = 0xa3;
|
||||
|
||||
pub const tag_defaulted_trait: usize = 0xa4;
|
||||
|
||||
pub const tag_impl_coerce_unsized_kind: usize = 0xa5;
|
||||
|
@ -279,6 +279,14 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
decoder::get_impl_polarity(&*cdata, def.node)
|
||||
}
|
||||
|
||||
pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
def: ast::DefId)
|
||||
-> Option<ty::CustomCoerceUnsized> {
|
||||
let cstore = &tcx.sess.cstore;
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
|
||||
}
|
||||
|
||||
// Given a def_id for an impl, return the trait it implements,
|
||||
// if there is one.
|
||||
pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
@ -489,6 +489,16 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd,
|
||||
id: ast::NodeId)
|
||||
-> Option<ty::CustomCoerceUnsized> {
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
|
||||
let mut decoder = reader::Decoder::new(kind_doc);
|
||||
Decodable::decode(&mut decoder).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_impl_trait<'tcx>(cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
tcx: &ty::ctxt<'tcx>)
|
||||
|
@ -1219,6 +1219,16 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_attributes(rbml_w, &item.attrs);
|
||||
encode_unsafety(rbml_w, unsafety);
|
||||
encode_polarity(rbml_w, polarity);
|
||||
|
||||
match tcx.custom_coerce_unsized_kinds.borrow().get(&local_def(item.id)) {
|
||||
Some(&kind) => {
|
||||
rbml_w.start_tag(tag_impl_coerce_unsized_kind);
|
||||
kind.encode(rbml_w);
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
match ty.node {
|
||||
ast::TyPath(None, ref path) if path.segments.len() == 1 => {
|
||||
let name = path.segments.last().unwrap().identifier.name;
|
||||
|
@ -890,10 +890,6 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
}
|
||||
};
|
||||
|
||||
debug!("walk_autoref: expr.id={} cmt_base={}",
|
||||
expr.id,
|
||||
cmt_base.repr(self.tcx()));
|
||||
|
||||
match *autoref {
|
||||
ty::AutoPtr(r, m) => {
|
||||
self.delegate.borrow(expr.id,
|
||||
|
@ -261,11 +261,14 @@ lets_do_this! {
|
||||
|
||||
SendTraitLangItem, "send", send_trait;
|
||||
SizedTraitLangItem, "sized", sized_trait;
|
||||
UnsizeTraitLangItem, "unsize", unsize_trait;
|
||||
CopyTraitLangItem, "copy", copy_trait;
|
||||
SyncTraitLangItem, "sync", sync_trait;
|
||||
|
||||
DropTraitLangItem, "drop", drop_trait;
|
||||
|
||||
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait;
|
||||
|
||||
AddTraitLangItem, "add", add_trait;
|
||||
SubTraitLangItem, "sub", sub_trait;
|
||||
MulTraitLangItem, "mul", mul_trait;
|
||||
|
@ -15,8 +15,12 @@ use super::{
|
||||
Obligation,
|
||||
ObligationCauseCode,
|
||||
OutputTypeParameterMismatch,
|
||||
TraitNotObjectSafe,
|
||||
PredicateObligation,
|
||||
SelectionError,
|
||||
ObjectSafetyViolation,
|
||||
MethodViolationCode,
|
||||
object_safety_violations,
|
||||
};
|
||||
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
@ -252,6 +256,54 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
TraitNotObjectSafe(did) => {
|
||||
span_err!(infcx.tcx.sess, obligation.cause.span, E0038,
|
||||
"cannot convert to a trait object because trait `{}` is not object-safe",
|
||||
ty::item_path_str(infcx.tcx, did));
|
||||
|
||||
for violation in object_safety_violations(infcx.tcx, did) {
|
||||
match violation {
|
||||
ObjectSafetyViolation::SizedSelf => {
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
"the trait cannot require that `Self : Sized`");
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::SupertraitSelf => {
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
"the trait cannot use `Self` as a type parameter \
|
||||
in the supertrait listing");
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::StaticMethod) => {
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
&format!("method `{}` has no receiver",
|
||||
method.name.user_string(infcx.tcx)));
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::ReferencesSelf) => {
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
&format!("method `{}` references the `Self` type \
|
||||
in its arguments or return type",
|
||||
method.name.user_string(infcx.tcx)));
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method,
|
||||
MethodViolationCode::Generic) => {
|
||||
infcx.tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
&format!("method `{}` has generic type parameters",
|
||||
method.name.user_string(infcx.tcx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,10 +455,6 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
"only the last field of a struct or enum variant \
|
||||
may have a dynamically sized type")
|
||||
}
|
||||
ObligationCauseCode::ObjectSized => {
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"only sized types can be made into objects");
|
||||
}
|
||||
ObligationCauseCode::SharedStatic => {
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"shared static variables must have a type that implements `Sync`");
|
||||
|
@ -28,6 +28,7 @@ use util::ppaux::Repr;
|
||||
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::error_reporting::report_overflow_error;
|
||||
pub use self::error_reporting::report_selection_error;
|
||||
pub use self::error_reporting::suggest_new_overflow_limit;
|
||||
pub use self::coherence::orphan_check;
|
||||
pub use self::coherence::overlapping_impls;
|
||||
@ -48,6 +49,7 @@ pub use self::select::{MethodMatchedData}; // intentionally don't export variant
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::get_vtable_index_of_object_method;
|
||||
pub use self::util::trait_ref_for_builtin_bound;
|
||||
pub use self::util::predicate_for_trait_def;
|
||||
pub use self::util::supertraits;
|
||||
pub use self::util::Supertraits;
|
||||
pub use self::util::supertrait_def_ids;
|
||||
@ -121,9 +123,6 @@ pub enum ObligationCauseCode<'tcx> {
|
||||
// Types of fields (other than the last) in a struct must be sized.
|
||||
FieldSized,
|
||||
|
||||
// Only Sized types can be made into objects
|
||||
ObjectSized,
|
||||
|
||||
// static items must have `Sync` type
|
||||
SharedStatic,
|
||||
|
||||
@ -159,6 +158,7 @@ pub enum SelectionError<'tcx> {
|
||||
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::type_err<'tcx>),
|
||||
TraitNotObjectSafe(ast::DefId),
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
@ -536,7 +536,9 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M {
|
||||
pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where
|
||||
F: FnMut(&N) -> M,
|
||||
{
|
||||
match *self {
|
||||
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
||||
VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)),
|
||||
|
@ -25,6 +25,8 @@ use super::{PredicateObligation, TraitObligation, ObligationCause};
|
||||
use super::report_overflow_error;
|
||||
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
|
||||
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
|
||||
use super::{ObjectCastObligation, Obligation};
|
||||
use super::TraitNotObjectSafe;
|
||||
use super::Selection;
|
||||
use super::SelectionResult;
|
||||
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
|
||||
@ -35,7 +37,7 @@ use super::util;
|
||||
|
||||
use middle::fast_reject;
|
||||
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
|
||||
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use middle::infer;
|
||||
use middle::infer::{InferCtxt, TypeFreshener};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
@ -207,6 +209,8 @@ enum SelectionCandidate<'tcx> {
|
||||
|
||||
BuiltinObjectCandidate,
|
||||
|
||||
BuiltinUnsizeCandidate,
|
||||
|
||||
ErrorCandidate,
|
||||
}
|
||||
|
||||
@ -904,6 +908,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
|
||||
}
|
||||
|
||||
None if self.tcx().lang_items.unsize_trait() ==
|
||||
Some(obligation.predicate.def_id()) => {
|
||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||
}
|
||||
|
||||
Some(ty::BoundSend) |
|
||||
Some(ty::BoundSync) |
|
||||
None => {
|
||||
@ -1356,6 +1365,84 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
/// Search for unsizing that might apply to `obligation`.
|
||||
fn assemble_candidates_for_unsizing(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>) {
|
||||
// We currently never consider higher-ranked obligations e.g.
|
||||
// `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not
|
||||
// because they are a priori invalid, and we could potentially add support
|
||||
// for them later, it's just that there isn't really a strong need for it.
|
||||
// A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>`
|
||||
// impl, and those are generally applied to concrete types.
|
||||
//
|
||||
// That said, one might try to write a fn with a where clause like
|
||||
// for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>>
|
||||
// where the `'a` is kind of orthogonal to the relevant part of the `Unsize`.
|
||||
// Still, you'd be more likely to write that where clause as
|
||||
// T: Trait
|
||||
// so it seems ok if we (conservatively) fail to accept that `Unsize`
|
||||
// obligation above. Should be possible to extend this in the future.
|
||||
let self_ty = match ty::no_late_bound_regions(self.tcx(), &obligation.self_ty()) {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
// Don't add any candidates if there are bound regions.
|
||||
return;
|
||||
}
|
||||
};
|
||||
let source = self.infcx.shallow_resolve(self_ty);
|
||||
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
|
||||
|
||||
debug!("assemble_candidates_for_unsizing(source={}, target={})",
|
||||
source.repr(self.tcx()), target.repr(self.tcx()));
|
||||
|
||||
let may_apply = match (&source.sty, &target.sty) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||
// Upcasts permit two things:
|
||||
//
|
||||
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
|
||||
//
|
||||
// Note that neither of these changes requires any
|
||||
// change at runtime. Eventually this will be
|
||||
// generalized.
|
||||
//
|
||||
// We always upcast when we can because of reason
|
||||
// #2 (region bounds).
|
||||
data_a.principal.def_id() == data_a.principal.def_id() &&
|
||||
data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds)
|
||||
}
|
||||
|
||||
// T -> Trait.
|
||||
(_, &ty::ty_trait(_)) => true,
|
||||
|
||||
// Ambiguous handling is below T -> Trait, because inference
|
||||
// variables can still implement Unsize<Trait> and nested
|
||||
// obligations will have the final say (likely deferred).
|
||||
(&ty::ty_infer(ty::TyVar(_)), _) |
|
||||
(_, &ty::ty_infer(ty::TyVar(_))) => {
|
||||
debug!("assemble_candidates_for_unsizing: ambiguous");
|
||||
candidates.ambiguous = true;
|
||||
false
|
||||
}
|
||||
|
||||
// [T; n] -> [T].
|
||||
(&ty::ty_vec(_, Some(_)), &ty::ty_vec(_, None)) => true,
|
||||
|
||||
// Struct<T> -> Struct<U>.
|
||||
(&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
|
||||
def_id_a == def_id_b
|
||||
}
|
||||
|
||||
_ => false
|
||||
};
|
||||
|
||||
if may_apply {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// WINNOW
|
||||
//
|
||||
@ -1427,6 +1514,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
&ClosureCandidate(..) |
|
||||
&FnPointerCandidate(..) |
|
||||
&BuiltinObjectCandidate(..) |
|
||||
&BuiltinUnsizeCandidate(..) |
|
||||
&DefaultImplObjectCandidate(..) |
|
||||
&BuiltinCandidate(..) => {
|
||||
// We have a where-clause so don't go around looking
|
||||
@ -1855,11 +1943,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation.recursion_depth + 1,
|
||||
&skol_ty);
|
||||
let skol_obligation =
|
||||
try!(util::predicate_for_trait_def(self.tcx(),
|
||||
derived_cause.clone(),
|
||||
trait_def_id,
|
||||
obligation.recursion_depth + 1,
|
||||
normalized_ty));
|
||||
util::predicate_for_trait_def(self.tcx(),
|
||||
derived_cause.clone(),
|
||||
trait_def_id,
|
||||
obligation.recursion_depth + 1,
|
||||
normalized_ty,
|
||||
vec![]);
|
||||
obligations.push(skol_obligation);
|
||||
Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations))
|
||||
})
|
||||
@ -1949,6 +2038,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.confirm_projection_candidate(obligation);
|
||||
Ok(VtableParam(Vec::new()))
|
||||
}
|
||||
|
||||
BuiltinUnsizeCandidate => {
|
||||
let data = try!(self.confirm_builtin_unsize_candidate(obligation));
|
||||
Ok(VtableBuiltin(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2322,6 +2416,161 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_builtin_unsize_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,)
|
||||
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
|
||||
SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// assemble_candidates_for_unsizing should ensure there are no late bound
|
||||
// regions here. See the comment there for more details.
|
||||
let source = self.infcx.shallow_resolve(
|
||||
ty::no_late_bound_regions(tcx, &obligation.self_ty()).unwrap());
|
||||
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
|
||||
|
||||
debug!("confirm_builtin_unsize_candidate(source={}, target={})",
|
||||
source.repr(tcx), target.repr(tcx));
|
||||
|
||||
let mut nested = vec![];
|
||||
match (&source.sty, &target.sty) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||
// See assemble_candidates_for_unsizing for more info.
|
||||
let bounds = ty::ExistentialBounds {
|
||||
region_bound: data_b.bounds.region_bound,
|
||||
builtin_bounds: data_b.bounds.builtin_bounds,
|
||||
projection_bounds: data_a.bounds.projection_bounds.clone(),
|
||||
};
|
||||
|
||||
let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds);
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
if self.infcx.sub_types(false, origin, new_trait, target).is_err() {
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
|
||||
// Register one obligation for 'a: 'b.
|
||||
let cause = ObligationCause::new(obligation.cause.span,
|
||||
obligation.cause.body_id,
|
||||
ObjectCastObligation(target));
|
||||
let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound,
|
||||
data_b.bounds.region_bound);
|
||||
nested.push(Obligation::with_depth(cause,
|
||||
obligation.recursion_depth + 1,
|
||||
ty::Binder(outlives).as_predicate()));
|
||||
}
|
||||
|
||||
// T -> Trait.
|
||||
(_, &ty::ty_trait(ref data)) => {
|
||||
let object_did = data.principal_def_id();
|
||||
if !object_safety::is_object_safe(tcx, object_did) {
|
||||
return Err(TraitNotObjectSafe(object_did));
|
||||
}
|
||||
|
||||
let cause = ObligationCause::new(obligation.cause.span,
|
||||
obligation.cause.body_id,
|
||||
ObjectCastObligation(target));
|
||||
let mut push = |predicate| {
|
||||
nested.push(Obligation::with_depth(cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
predicate));
|
||||
};
|
||||
|
||||
// Create the obligation for casting from T to Trait.
|
||||
push(data.principal_trait_ref_with_self_ty(tcx, source).as_predicate());
|
||||
|
||||
// We can only make objects from sized types.
|
||||
let mut builtin_bounds = data.bounds.builtin_bounds;
|
||||
builtin_bounds.insert(ty::BoundSized);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
// bounds attached to the object cast. (In other words, if the
|
||||
// object type is Foo+Send, this would create an obligation
|
||||
// for the Send check.)
|
||||
for bound in &builtin_bounds {
|
||||
if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) {
|
||||
push(tr.as_predicate());
|
||||
} else {
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
}
|
||||
|
||||
// Create obligations for the projection predicates.
|
||||
for bound in data.projection_bounds_with_self_ty(tcx, source) {
|
||||
push(bound.as_predicate());
|
||||
}
|
||||
|
||||
// If the type is `Foo+'a`, ensures that the type
|
||||
// being cast to `Foo+'a` outlives `'a`:
|
||||
let outlives = ty::OutlivesPredicate(source,
|
||||
data.bounds.region_bound);
|
||||
push(ty::Binder(outlives).as_predicate());
|
||||
}
|
||||
|
||||
// [T; n] -> [T].
|
||||
(&ty::ty_vec(a, Some(_)), &ty::ty_vec(b, None)) => {
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
if self.infcx.sub_types(false, origin, a, b).is_err() {
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
}
|
||||
|
||||
// Struct<T> -> Struct<U>.
|
||||
(&ty::ty_struct(def_id, substs_a), &ty::ty_struct(_, substs_b)) => {
|
||||
let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| {
|
||||
ty::lookup_field_type_unsubstituted(tcx, def_id, f.id)
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
// FIXME(#25351) The last field of the structure has to exist and be a
|
||||
// type parameter (for now, to avoid tracking edge cases).
|
||||
let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) {
|
||||
assert!(p.space == TypeSpace);
|
||||
p.idx as usize
|
||||
} else {
|
||||
return Err(Unimplemented);
|
||||
};
|
||||
|
||||
// Replace the type parameter chosen for unsizing with
|
||||
// ty_err and ensure it does not affect any other fields.
|
||||
// This could be checked after type collection for any struct
|
||||
// with a potentially unsized trailing field.
|
||||
let mut new_substs = substs_a.clone();
|
||||
new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err;
|
||||
for &ty in fields.init() {
|
||||
if ty::type_is_error(ty.subst(tcx, &new_substs)) {
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract T and U from Struct<T> and Struct<U>.
|
||||
let inner_source = *substs_a.types.get(TypeSpace, i);
|
||||
let inner_target = *substs_b.types.get(TypeSpace, i);
|
||||
|
||||
// Check that all the source structure with the unsized
|
||||
// type parameter is a subtype of the target.
|
||||
new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target;
|
||||
let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs));
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
if self.infcx.sub_types(false, origin, new_struct, target).is_err() {
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
|
||||
// Construct the nested T: Unsize<U> predicate.
|
||||
nested.push(util::predicate_for_trait_def(tcx,
|
||||
obligation.cause.clone(),
|
||||
obligation.predicate.def_id(),
|
||||
obligation.recursion_depth + 1,
|
||||
inner_source,
|
||||
vec![inner_target]));
|
||||
}
|
||||
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
Ok(VtableBuiltinData {
|
||||
nested: VecPerParamSpace::new(nested, vec![], vec![])
|
||||
})
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Matching
|
||||
//
|
||||
@ -2683,6 +2932,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
|
||||
ErrorCandidate => format!("ErrorCandidate"),
|
||||
BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
|
||||
BuiltinObjectCandidate => format!("BuiltinObjectCandidate"),
|
||||
BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"),
|
||||
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
||||
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
||||
DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
|
||||
@ -2756,7 +3006,8 @@ impl<'tcx> EvaluationResult<'tcx> {
|
||||
match *self {
|
||||
EvaluatedToOk |
|
||||
EvaluatedToAmbig |
|
||||
EvaluatedToErr(OutputTypeParameterMismatch(..)) =>
|
||||
EvaluatedToErr(OutputTypeParameterMismatch(..)) |
|
||||
EvaluatedToErr(TraitNotObjectSafe(_)) =>
|
||||
true,
|
||||
|
||||
EvaluatedToErr(Unimplemented) =>
|
||||
|
@ -356,13 +356,13 @@ pub fn predicate_for_trait_ref<'tcx>(
|
||||
cause: ObligationCause<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
recursion_depth: usize)
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
-> PredicateObligation<'tcx>
|
||||
{
|
||||
Ok(Obligation {
|
||||
Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
predicate: trait_ref.as_predicate(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn predicate_for_trait_def<'tcx>(
|
||||
@ -370,12 +370,13 @@ pub fn predicate_for_trait_def<'tcx>(
|
||||
cause: ObligationCause<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
recursion_depth: usize,
|
||||
param_ty: Ty<'tcx>)
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
param_ty: Ty<'tcx>,
|
||||
ty_params: Vec<Ty<'tcx>>)
|
||||
-> PredicateObligation<'tcx>
|
||||
{
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty))
|
||||
substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty))
|
||||
};
|
||||
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
|
||||
}
|
||||
@ -389,7 +390,7 @@ pub fn predicate_for_builtin_bound<'tcx>(
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
{
|
||||
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
|
||||
Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth))
|
||||
}
|
||||
|
||||
/// Cast a trait reference into a reference to one of its super
|
||||
@ -561,6 +562,10 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
|
||||
a.repr(tcx),
|
||||
b.repr(tcx),
|
||||
c.repr(tcx)),
|
||||
|
||||
super::TraitNotObjectSafe(ref tr) =>
|
||||
format!("TraitNotObjectSafe({})",
|
||||
tr.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -404,6 +404,12 @@ pub enum AutoRef<'tcx> {
|
||||
AutoUnsafe(ast::Mutability),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum CustomCoerceUnsized {
|
||||
/// Records the index of the field being coerced.
|
||||
Struct(usize)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
|
||||
pub struct param_index {
|
||||
pub space: subst::ParamSpace,
|
||||
@ -818,6 +824,9 @@ pub struct ctxt<'tcx> {
|
||||
|
||||
/// Maps Expr NodeId's to their constant qualification.
|
||||
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
|
||||
|
||||
/// Caches CoerceUnsized kinds for impls on custom types.
|
||||
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ctxt<'tcx> {
|
||||
@ -2809,6 +2818,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
||||
type_impls_copy_cache: RefCell::new(HashMap::new()),
|
||||
type_impls_sized_cache: RefCell::new(HashMap::new()),
|
||||
const_qualif_map: RefCell::new(NodeMap()),
|
||||
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4410,7 +4420,7 @@ pub fn deref<'tcx>(ty: Ty<'tcx>, explicit: bool) -> Option<mt<'tcx>> {
|
||||
pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty_uniq(ty) => ty,
|
||||
ty_rptr(_, mt) |ty_ptr(mt) => mt.ty,
|
||||
ty_rptr(_, mt) | ty_ptr(mt) => mt.ty,
|
||||
_ => ty
|
||||
}
|
||||
}
|
||||
@ -5351,6 +5361,26 @@ pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn custom_coerce_unsized_kind<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
|
||||
-> CustomCoerceUnsized {
|
||||
memoized(&cx.custom_coerce_unsized_kinds, did, |did: DefId| {
|
||||
let (kind, src) = if did.krate != ast::LOCAL_CRATE {
|
||||
(csearch::get_custom_coerce_unsized_kind(cx, did), "external")
|
||||
} else {
|
||||
(None, "local")
|
||||
};
|
||||
|
||||
match kind {
|
||||
Some(kind) => kind,
|
||||
None => {
|
||||
cx.sess.bug(&format!("custom_coerce_unsized_kind: \
|
||||
{} impl `{}` is missing its kind",
|
||||
src, item_path_str(cx, did)));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
-> ImplOrTraitItem<'tcx> {
|
||||
lookup_locally_or_in_crate_store("impl_or_trait_items",
|
||||
@ -5576,8 +5606,7 @@ impl DtorKind {
|
||||
}
|
||||
}
|
||||
|
||||
/* If struct_id names a struct with a dtor, return Some(the dtor's id).
|
||||
Otherwise return none. */
|
||||
/* If struct_id names a struct with a dtor. */
|
||||
pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind {
|
||||
match cx.destructor_for_type.borrow().get(&struct_id) {
|
||||
Some(&method_def_id) => {
|
||||
@ -6012,6 +6041,20 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
|
||||
})
|
||||
}
|
||||
|
||||
// Look up a field ID, whether or not it's local
|
||||
pub fn lookup_field_type_unsubstituted<'tcx>(tcx: &ctxt<'tcx>,
|
||||
struct_id: DefId,
|
||||
id: DefId)
|
||||
-> Ty<'tcx> {
|
||||
if id.krate == ast::LOCAL_CRATE {
|
||||
node_id_to_type(tcx, id.node)
|
||||
} else {
|
||||
let mut tcache = tcx.tcache.borrow_mut();
|
||||
tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Look up a field ID, whether or not it's local
|
||||
// Takes a list of type substs in case the struct is generic
|
||||
pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>,
|
||||
@ -6019,13 +6062,7 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>,
|
||||
id: DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
let ty = if id.krate == ast::LOCAL_CRATE {
|
||||
node_id_to_type(tcx, id.node)
|
||||
} else {
|
||||
let mut tcache = tcx.tcache.borrow_mut();
|
||||
tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty
|
||||
};
|
||||
ty.subst(tcx, substs)
|
||||
lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs)
|
||||
}
|
||||
|
||||
// Look up the list of field names and IDs for a given struct.
|
||||
|
@ -141,7 +141,8 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
||||
/// Decides how to represent a given type.
|
||||
pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
t: Ty<'tcx>) -> Rc<Repr<'tcx>> {
|
||||
t: Ty<'tcx>)
|
||||
-> Rc<Repr<'tcx>> {
|
||||
debug!("Representing: {}", ty_to_string(cx.tcx(), t));
|
||||
match cx.adt_reprs().borrow().get(&t) {
|
||||
Some(repr) => return repr.clone(),
|
||||
@ -216,7 +217,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}).collect::<Vec<_>>();
|
||||
let packed = ty::lookup_packed(cx.tcx(), def_id);
|
||||
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
||||
if dtor { ftys.push(cx.tcx().dtor_type()); }
|
||||
if dtor {
|
||||
ftys.push(cx.tcx().dtor_type());
|
||||
}
|
||||
|
||||
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
|
||||
}
|
||||
@ -517,8 +520,7 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
-> Struct<'tcx> {
|
||||
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
|
||||
let lltys : Vec<Type> = if sized {
|
||||
tys.iter()
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
} else {
|
||||
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
@ -1060,7 +1062,9 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
|
||||
/// Access the struct drop flag, if present.
|
||||
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef)
|
||||
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
r: &Repr<'tcx>,
|
||||
val: ValueRef)
|
||||
-> datum::DatumBlock<'blk, 'tcx, datum::Expr>
|
||||
{
|
||||
let tcx = bcx.tcx();
|
||||
|
@ -1058,6 +1058,7 @@ impl MetadataCreationResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MemberOffset {
|
||||
FixedMemberOffset { bytes: usize },
|
||||
// For ComputedMemberOffset, the offset is read from the llvm type definition.
|
||||
@ -1066,6 +1067,7 @@ enum MemberOffset {
|
||||
|
||||
// Description of a type member, which can either be a regular field (as in
|
||||
// structs or tuples) or an enum variant.
|
||||
#[derive(Debug)]
|
||||
struct MemberDescription {
|
||||
name: String,
|
||||
llvm_type: Type,
|
||||
@ -1163,13 +1165,13 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
span: Span)
|
||||
-> RecursiveTypeDescription<'tcx> {
|
||||
let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
|
||||
let struct_llvm_type = type_of::type_of(cx, struct_type);
|
||||
let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type);
|
||||
|
||||
let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
|
||||
|
||||
let struct_metadata_stub = create_struct_stub(cx,
|
||||
struct_llvm_type,
|
||||
&struct_name[..],
|
||||
&struct_name,
|
||||
unique_type_id,
|
||||
containing_scope);
|
||||
|
||||
@ -1299,7 +1301,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
&member_descriptions[..]);
|
||||
&member_descriptions);
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
llvm_type: variant_llvm_type,
|
||||
|
@ -56,8 +56,10 @@ use back::abi;
|
||||
use llvm::{self, ValueRef};
|
||||
use middle::check_const;
|
||||
use middle::def;
|
||||
use middle::lang_items::CoerceUnsizedTraitLangItem;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{self, Substs};
|
||||
use middle::subst::{Substs, VecPerParamSpace};
|
||||
use middle::traits;
|
||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
@ -304,7 +306,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
|
||||
source: Ty<'tcx>,
|
||||
target: Ty<'tcx>,
|
||||
old_info: Option<ValueRef>,
|
||||
param_substs: &'tcx subst::Substs<'tcx>)
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
-> ValueRef {
|
||||
let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
|
||||
match (&source.sty, &target.sty) {
|
||||
@ -390,81 +392,161 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
// (You might think there is a more elegant way to do this than a
|
||||
// skip_reborrows bool, but then you remember that the borrow checker exists).
|
||||
if skip_reborrows == 0 && adj.autoref.is_some() {
|
||||
datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum));
|
||||
if !type_is_sized(bcx.tcx(), datum.ty) {
|
||||
// Arrange cleanup
|
||||
let lval = unpack_datum!(bcx,
|
||||
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
|
||||
datum = unpack_datum!(bcx, ref_fat_ptr(bcx, lval));
|
||||
} else {
|
||||
datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(target) = adj.unsize {
|
||||
datum = unpack_datum!(bcx, unsize_pointer(bcx, datum,
|
||||
bcx.monomorphize(&target)));
|
||||
// We do not arrange cleanup ourselves; if we already are an
|
||||
// L-value, then cleanup will have already been scheduled (and
|
||||
// the `datum.to_rvalue_datum` call below will emit code to zero
|
||||
// the drop flag when moving out of the L-value). If we are an
|
||||
// R-value, then we do not need to schedule cleanup.
|
||||
let source_datum = unpack_datum!(bcx,
|
||||
datum.to_rvalue_datum(bcx, "__coerce_source"));
|
||||
|
||||
let target = bcx.monomorphize(&target);
|
||||
let llty = type_of::type_of(bcx.ccx(), target);
|
||||
|
||||
// HACK(eddyb) get around issues with lifetime intrinsics.
|
||||
let scratch = alloca_no_lifetime(bcx, llty, "__coerce_target");
|
||||
let target_datum = Datum::new(scratch, target,
|
||||
Rvalue::new(ByRef));
|
||||
bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum);
|
||||
datum = Datum::new(scratch, target,
|
||||
RvalueExpr(Rvalue::new(ByRef)));
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
|
||||
return DatumBlock::new(bcx, datum);
|
||||
DatumBlock::new(bcx, datum)
|
||||
}
|
||||
|
||||
fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<'tcx, Expr>)
|
||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
let mut bcx = bcx;
|
||||
fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
span: codemap::Span,
|
||||
source: Datum<'tcx, Rvalue>,
|
||||
target: Datum<'tcx, Rvalue>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let mut bcx = bcx;
|
||||
debug!("coerce_unsized({} -> {})",
|
||||
source.to_string(bcx.ccx()),
|
||||
target.to_string(bcx.ccx()));
|
||||
|
||||
if !type_is_sized(bcx.tcx(), datum.ty) {
|
||||
// Arrange cleanup
|
||||
let lval = unpack_datum!(bcx,
|
||||
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
|
||||
ref_fat_ptr(bcx, lval)
|
||||
} else {
|
||||
auto_ref(bcx, datum, expr)
|
||||
match (&source.ty.sty, &target.ty.sty) {
|
||||
(&ty::ty_uniq(a), &ty::ty_uniq(b)) |
|
||||
(&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_rptr(_, ty::mt { ty: b, .. })) |
|
||||
(&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) |
|
||||
(&ty::ty_ptr(ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) => {
|
||||
let (inner_source, inner_target) = (a, b);
|
||||
|
||||
let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) {
|
||||
// Normally, the source is a thin pointer and we are
|
||||
// adding extra info to make a fat pointer. The exception
|
||||
// is when we are upcasting an existing object fat pointer
|
||||
// to use a different vtable. In that case, we want to
|
||||
// load out the original data pointer so we can repackage
|
||||
// it.
|
||||
(Load(bcx, get_dataptr(bcx, source.val)),
|
||||
Some(Load(bcx, get_len(bcx, source.val))))
|
||||
} else {
|
||||
let val = if source.kind.is_by_ref() {
|
||||
load_ty(bcx, source.val, source.ty)
|
||||
} else {
|
||||
source.val
|
||||
};
|
||||
(val, None)
|
||||
};
|
||||
|
||||
let info = unsized_info(bcx.ccx(), inner_source, inner_target,
|
||||
old_info, bcx.fcx.param_substs);
|
||||
|
||||
// Compute the base pointer. This doesn't change the pointer value,
|
||||
// but merely its type.
|
||||
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to();
|
||||
let base = PointerCast(bcx, base, ptr_ty);
|
||||
|
||||
Store(bcx, base, get_dataptr(bcx, target.val));
|
||||
Store(bcx, info, get_len(bcx, target.val));
|
||||
}
|
||||
|
||||
// This can be extended to enums and tuples in the future.
|
||||
// (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) |
|
||||
(&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
|
||||
assert_eq!(def_id_a, def_id_b);
|
||||
|
||||
// The target is already by-ref because it's to be written to.
|
||||
let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
|
||||
assert!(target.kind.is_by_ref());
|
||||
|
||||
let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty],
|
||||
vec![source.ty],
|
||||
Vec::new()));
|
||||
let trait_ref = ty::Binder(ty::TraitRef {
|
||||
def_id: langcall(bcx, Some(span), "coercion",
|
||||
CoerceUnsizedTraitLangItem),
|
||||
substs: bcx.tcx().mk_substs(trait_substs)
|
||||
});
|
||||
|
||||
let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) {
|
||||
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
|
||||
ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id)
|
||||
}
|
||||
vtable => {
|
||||
bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}",
|
||||
vtable.repr(bcx.tcx())));
|
||||
}
|
||||
};
|
||||
|
||||
let repr_source = adt::represent_type(bcx.ccx(), source.ty);
|
||||
let src_fields = match &*repr_source {
|
||||
&adt::Repr::Univariant(ref s, _) => &s.fields,
|
||||
_ => bcx.sess().span_bug(span,
|
||||
&format!("Non univariant struct? (repr_source: {:?})",
|
||||
repr_source)),
|
||||
};
|
||||
let repr_target = adt::represent_type(bcx.ccx(), target.ty);
|
||||
let target_fields = match &*repr_target {
|
||||
&adt::Repr::Univariant(ref s, _) => &s.fields,
|
||||
_ => bcx.sess().span_bug(span,
|
||||
&format!("Non univariant struct? (repr_target: {:?})",
|
||||
repr_target)),
|
||||
};
|
||||
|
||||
let coerce_index = match kind {
|
||||
ty::CustomCoerceUnsized::Struct(i) => i
|
||||
};
|
||||
assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
|
||||
|
||||
let iter = src_fields.iter().zip(target_fields.iter()).enumerate();
|
||||
for (i, (src_ty, target_ty)) in iter {
|
||||
let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
|
||||
let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);
|
||||
|
||||
// If this is the field we need to coerce, recurse on it.
|
||||
if i == coerce_index {
|
||||
coerce_unsized(bcx, span,
|
||||
Datum::new(ll_source, src_ty,
|
||||
Rvalue::new(ByRef)),
|
||||
Datum::new(ll_target, target_ty,
|
||||
Rvalue::new(ByRef)));
|
||||
} else {
|
||||
// Otherwise, simply copy the data from the source.
|
||||
assert_eq!(src_ty, target_ty);
|
||||
memcpy_ty(bcx, ll_target, ll_source, src_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}",
|
||||
source.ty.repr(bcx.tcx()),
|
||||
target.ty.repr(bcx.tcx())))
|
||||
}
|
||||
|
||||
fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
datum: Datum<'tcx, Expr>,
|
||||
target: Ty<'tcx>)
|
||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
let mut bcx = bcx;
|
||||
let unsized_ty = ty::deref(target, true)
|
||||
.expect("expr::unsize got non-pointer target type").ty;
|
||||
debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx()));
|
||||
|
||||
// We do not arrange cleanup ourselves; if we already are an
|
||||
// L-value, then cleanup will have already been scheduled (and
|
||||
// the `datum.to_rvalue_datum` call below will emit code to zero
|
||||
// the drop flag when moving out of the L-value). If we are an
|
||||
// R-value, then we do not need to schedule cleanup.
|
||||
let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref"));
|
||||
|
||||
let pointee_ty = ty::deref(datum.ty, true)
|
||||
.expect("expr::unsize got non-pointer datum type").ty;
|
||||
let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) {
|
||||
// Normally, the source is a thin pointer and we are
|
||||
// adding extra info to make a fat pointer. The exception
|
||||
// is when we are upcasting an existing object fat pointer
|
||||
// to use a different vtable. In that case, we want to
|
||||
// load out the original data pointer so we can repackage
|
||||
// it.
|
||||
(Load(bcx, get_dataptr(bcx, datum.val)),
|
||||
Some(Load(bcx, get_len(bcx, datum.val))))
|
||||
} else {
|
||||
(datum.val, None)
|
||||
};
|
||||
|
||||
let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty,
|
||||
old_info, bcx.fcx.param_substs);
|
||||
|
||||
// Compute the base pointer. This doesn't change the pointer value,
|
||||
// but merely its type.
|
||||
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
|
||||
let base = PointerCast(bcx, base, ptr_ty);
|
||||
|
||||
let llty = type_of::type_of(bcx.ccx(), target);
|
||||
// HACK(eddyb) get around issues with lifetime intrinsics.
|
||||
let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr");
|
||||
Store(bcx, base, get_dataptr(bcx, scratch));
|
||||
Store(bcx, info, get_len(bcx, scratch));
|
||||
|
||||
DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef))))
|
||||
}
|
||||
bcx
|
||||
}
|
||||
|
||||
/// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory
|
||||
@ -1178,7 +1260,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ref_expr: &ast::Expr,
|
||||
def: def::Def,
|
||||
param_substs: &'tcx subst::Substs<'tcx>)
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue> {
|
||||
let _icx = push_ctxt("trans_def_datum_unadjusted");
|
||||
|
||||
@ -1937,6 +2019,7 @@ fn float_cast(bcx: Block,
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum cast_kind {
|
||||
cast_pointer,
|
||||
cast_fat_ptr,
|
||||
cast_integral,
|
||||
cast_float,
|
||||
cast_enum,
|
||||
@ -1951,7 +2034,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
|
||||
if type_is_sized(tcx, mt.ty) {
|
||||
cast_pointer
|
||||
} else {
|
||||
cast_other
|
||||
cast_fat_ptr
|
||||
}
|
||||
}
|
||||
ty::ty_bare_fn(..) => cast_pointer,
|
||||
@ -2027,10 +2110,18 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
PtrToInt(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(cast_fat_ptr, cast_integral) => {
|
||||
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||
PtrToInt(bcx, data_ptr, ll_t_out)
|
||||
}
|
||||
(cast_pointer, cast_pointer) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
PointerCast(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(cast_fat_ptr, cast_pointer) => {
|
||||
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||
PointerCast(bcx, data_ptr, ll_t_out)
|
||||
}
|
||||
(cast_enum, cast_integral) |
|
||||
(cast_enum, cast_float) => {
|
||||
let mut bcx = bcx;
|
||||
|
@ -278,18 +278,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
v0: ValueRef,
|
||||
struct_data: ValueRef,
|
||||
dtor_did: ast::DefId,
|
||||
class_did: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
|
||||
|
||||
let repr = adt::represent_type(bcx.ccx(), t);
|
||||
let struct_data = if type_is_sized(bcx.tcx(), t) {
|
||||
v0
|
||||
} else {
|
||||
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
|
||||
Load(bcx, llval)
|
||||
};
|
||||
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
||||
let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
|
||||
let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
|
||||
@ -313,9 +309,8 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
|
||||
let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
|
||||
with_cond(bcx, drop_flag_dtor_needed, |cx| {
|
||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
||||
trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
@ -392,8 +387,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
|
||||
}
|
||||
|
||||
fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
|
||||
-> (ValueRef, ValueRef) {
|
||||
pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
|
||||
-> (ValueRef, ValueRef) {
|
||||
debug!("calculate size of DST: {}; with lost info: {}",
|
||||
bcx.ty_to_string(t), bcx.val_to_string(info));
|
||||
if type_is_sized(bcx.tcx(), t) {
|
||||
|
@ -326,10 +326,31 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
}
|
||||
(_, "size_of_val") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
if !type_is_sized(tcx, tp_ty) {
|
||||
let info = Load(bcx, expr::get_len(bcx, llargs[0]));
|
||||
let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info);
|
||||
llsize
|
||||
} else {
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
}
|
||||
}
|
||||
(_, "min_align_of") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
C_uint(ccx, type_of::align_of(ccx, tp_ty))
|
||||
}
|
||||
(_, "min_align_of_val") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
if !type_is_sized(tcx, tp_ty) {
|
||||
let info = Load(bcx, expr::get_len(bcx, llargs[0]));
|
||||
let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info);
|
||||
llalign
|
||||
} else {
|
||||
C_uint(ccx, type_of::align_of(ccx, tp_ty))
|
||||
}
|
||||
}
|
||||
(_, "pref_align_of") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
@ -351,6 +372,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
bcx = src.store_to(bcx, llargs[0]);
|
||||
C_nil(ccx)
|
||||
}
|
||||
(_, "drop_in_place") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location);
|
||||
C_nil(ccx)
|
||||
}
|
||||
(_, "type_name") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
let ty_name = token::intern_and_get_ident(&ty_to_string(ccx.tcx(), tp_ty));
|
||||
|
@ -101,7 +101,8 @@ pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign {
|
||||
|
||||
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 {
|
||||
unsafe {
|
||||
return llvm::LLVMOffsetOfElement(cx.td().lltd, struct_ty.to_ref(),
|
||||
return llvm::LLVMOffsetOfElement(cx.td().lltd,
|
||||
struct_ty.to_ref(),
|
||||
element as u32);
|
||||
}
|
||||
}
|
||||
|
@ -60,28 +60,29 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
let e = &cast.expr;
|
||||
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
|
||||
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
// Check for trivial casts.
|
||||
if !ty::type_has_ty_infer(t_1) {
|
||||
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
|
||||
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
} else {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -91,14 +92,15 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
let t_e_is_scalar = ty::type_is_scalar(t_e);
|
||||
let t_e_is_integral = ty::type_is_integral(t_e);
|
||||
let t_e_is_float = ty::type_is_floating_point(t_e);
|
||||
let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
|
||||
let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e);
|
||||
|
||||
let t_1_is_scalar = ty::type_is_scalar(t_1);
|
||||
let t_1_is_integral = ty::type_is_integral(t_1);
|
||||
let t_1_is_char = ty::type_is_char(t_1);
|
||||
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
|
||||
let t_1_is_float = ty::type_is_floating_point(t_1);
|
||||
let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1);
|
||||
let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1);
|
||||
let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
|
||||
|
||||
// casts to scalars other than `char` and `bare fn` are trivial
|
||||
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
|
||||
@ -113,7 +115,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
}, t_e, None);
|
||||
}
|
||||
} else if t_1.sty == ty::ty_bool {
|
||||
span_err!(fcx.tcx().sess, span, E0054,
|
||||
span_err!(tcx.sess, span, E0054,
|
||||
"cannot cast as `bool`, compare with zero instead");
|
||||
} else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) &&
|
||||
!(t_1_is_integral || t_1_is_float) {
|
||||
@ -170,18 +172,20 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
demand::coerce(fcx, e.span, t_1, &e);
|
||||
}
|
||||
}
|
||||
} else if fcx.type_is_fat_ptr(t_e, span) != fcx.type_is_fat_ptr(t_1, span) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("illegal cast; cast to or from fat pointer: `{}` as `{}` \
|
||||
involving incompatible type.",
|
||||
actual, fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
} else if t1_is_fat_ptr {
|
||||
// FIXME This should be allowed where the lefthandside is also a fat
|
||||
// pointer and is the same kind of fat pointer, i.e., array to array,
|
||||
// trait object to trait object. That is a bit looser than the current
|
||||
// rquirement that they are pointers to the same type.
|
||||
if !(fcx.type_is_fat_ptr(t_e, span) &&
|
||||
ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("cast to fat pointer: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
}
|
||||
} else if !(t_e_is_scalar && t_1_is_trivial) {
|
||||
/*
|
||||
If more type combinations should be supported than are
|
||||
supported here, then file an enhancement issue and
|
||||
record the issue number in this comment.
|
||||
*/
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("non-scalar cast: `{}` as `{}`",
|
||||
actual,
|
||||
|
@ -61,25 +61,24 @@
|
||||
//! we may want to adjust precisely when coercions occur.
|
||||
|
||||
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
|
||||
use check::vtable;
|
||||
|
||||
use middle::infer::{self, Coercion};
|
||||
use middle::subst;
|
||||
use middle::traits;
|
||||
use middle::traits::{self, ObligationCause};
|
||||
use middle::traits::{predicate_for_trait_def, report_selection_error};
|
||||
use middle::ty::{AutoDerefRef, AdjustDerefRef};
|
||||
use middle::ty::{self, mt, Ty};
|
||||
use middle::ty_relate::RelateResult;
|
||||
use util::common::indent;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use syntax::ast;
|
||||
|
||||
struct Coerce<'a, 'tcx: 'a> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
origin: infer::TypeOrigin,
|
||||
unsizing_obligation: Cell<Option<Ty<'tcx>>>
|
||||
unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
|
||||
}
|
||||
|
||||
type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
|
||||
@ -94,15 +93,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
Ok(None) // No coercion required.
|
||||
}
|
||||
|
||||
fn outlives(&self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
a: ty::Region,
|
||||
b: ty::Region)
|
||||
-> RelateResult<'tcx, ()> {
|
||||
infer::mk_subr(self.fcx.infcx(), origin, b, a);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
|
||||
F: FnOnce(Ty<'tcx>) -> T,
|
||||
{
|
||||
@ -248,51 +238,100 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
// or &mut [T, ..n] -> &mut [T]
|
||||
// or &Concrete -> &Trait, etc.
|
||||
fn coerce_unsized(&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
source: Ty<'tcx>,
|
||||
target: Ty<'tcx>)
|
||||
-> CoerceResult<'tcx> {
|
||||
debug!("coerce_unsized(a={}, b={})",
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()));
|
||||
debug!("coerce_unsized(source={}, target={})",
|
||||
source.repr(self.tcx()),
|
||||
target.repr(self.tcx()));
|
||||
|
||||
let traits = (self.tcx().lang_items.unsize_trait(),
|
||||
self.tcx().lang_items.coerce_unsized_trait());
|
||||
let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
|
||||
(u, cu)
|
||||
} else {
|
||||
debug!("Missing Unsize or CoerceUnsized traits");
|
||||
return Err(ty::terr_mismatch);
|
||||
};
|
||||
|
||||
// Note, we want to avoid unnecessary unsizing. We don't want to coerce to
|
||||
// a DST unless we have to. This currently comes out in the wash since
|
||||
// we can't unify [T] with U. But to properly support DST, we need to allow
|
||||
// that, at which point we will need extra checks on b here.
|
||||
// that, at which point we will need extra checks on the target here.
|
||||
|
||||
let (reborrow, target) = match (&a.sty, &b.sty) {
|
||||
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
|
||||
let (source, reborrow) = match (&source.sty, &target.sty) {
|
||||
(&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => {
|
||||
if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
|
||||
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
|
||||
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
|
||||
|
||||
let coercion = Coercion(self.origin.span());
|
||||
let r_borrow = self.fcx.infcx().next_region_var(coercion);
|
||||
let region = self.tcx().mk_region(r_borrow);
|
||||
(Some(ty::AutoPtr(region, mt_b.mutbl)), target)
|
||||
} else {
|
||||
return Err(ty::terr_mismatch);
|
||||
}
|
||||
let coercion = Coercion(self.origin.span());
|
||||
let r_borrow = self.fcx.infcx().next_region_var(coercion);
|
||||
let region = self.tcx().mk_region(r_borrow);
|
||||
(mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl)))
|
||||
}
|
||||
(&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => {
|
||||
if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) {
|
||||
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
|
||||
(Some(ty::AutoUnsafe(mt_b.mutbl)), target)
|
||||
} else {
|
||||
return Err(ty::terr_mismatch);
|
||||
}
|
||||
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
|
||||
(mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl)))
|
||||
}
|
||||
(&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
|
||||
if let Some(target) = self.unsize_ty(t_a, t_b) {
|
||||
(None, ty::mk_uniq(self.tcx(), target))
|
||||
} else {
|
||||
return Err(ty::terr_mismatch);
|
||||
}
|
||||
}
|
||||
_ => return Err(ty::terr_mismatch)
|
||||
_ => (source, None)
|
||||
};
|
||||
let source = ty::adjust_ty_for_autoref(self.tcx(), source, reborrow);
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
|
||||
|
||||
// Use a FIFO queue for this custom fulfillment procedure.
|
||||
let mut queue = VecDeque::new();
|
||||
let mut leftover_predicates = vec![];
|
||||
|
||||
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
||||
let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
|
||||
queue.push_back(predicate_for_trait_def(self.tcx(),
|
||||
cause,
|
||||
coerce_unsized_did,
|
||||
0,
|
||||
source,
|
||||
vec![target]));
|
||||
|
||||
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||
// inference might unify those two inner type variables later.
|
||||
let traits = [coerce_unsized_did, unsize_did];
|
||||
while let Some(obligation) = queue.pop_front() {
|
||||
debug!("coerce_unsized resolve step: {}", obligation.repr(self.tcx()));
|
||||
let trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
|
||||
tr.clone()
|
||||
}
|
||||
_ => {
|
||||
leftover_predicates.push(obligation);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match selcx.select(&obligation.with(trait_ref)) {
|
||||
// Uncertain or unimplemented.
|
||||
Ok(None) | Err(traits::Unimplemented) => {
|
||||
debug!("coerce_unsized: early return - can't prove obligation");
|
||||
return Err(ty::terr_mismatch);
|
||||
}
|
||||
|
||||
// Object safety violations or miscellaneous.
|
||||
Err(err) => {
|
||||
report_selection_error(self.fcx.infcx(), &obligation, &err);
|
||||
// Treat this like an obligation and follow through
|
||||
// with the unsizing - the lack of a coercion should
|
||||
// be silent, as it causes a type mismatch later.
|
||||
}
|
||||
|
||||
Ok(Some(vtable)) => {
|
||||
vtable.map_move_nested(|o| queue.push_back(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut obligations = self.unsizing_obligations.borrow_mut();
|
||||
assert!(obligations.is_empty());
|
||||
*obligations = leftover_predicates;
|
||||
|
||||
let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow);
|
||||
try!(self.subtype(target, b));
|
||||
let adjustment = AutoDerefRef {
|
||||
autoderefs: if reborrow.is_some() { 1 } else { 0 },
|
||||
autoref: reborrow,
|
||||
@ -302,108 +341,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
Ok(Some(AdjustDerefRef(adjustment)))
|
||||
}
|
||||
|
||||
// Takes a type and returns an unsized version.
|
||||
// E.g., `[T, ..n]` -> `[T]`.
|
||||
fn unsize_ty(&self,
|
||||
ty_a: Ty<'tcx>,
|
||||
ty_b: Ty<'tcx>)
|
||||
-> Option<Ty<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
self.unpack_actual_value(ty_a, |a| self.unpack_actual_value(ty_b, |b| {
|
||||
debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
match (&a.sty, &b.sty) {
|
||||
(&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => {
|
||||
Some(ty::mk_vec(tcx, t_a, None))
|
||||
}
|
||||
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||
// Upcasts permit two things:
|
||||
//
|
||||
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
|
||||
//
|
||||
// Note that neither of these changes requires any
|
||||
// change at runtime. Eventually this will be
|
||||
// generalized.
|
||||
//
|
||||
// We always upcast when we can because of reason
|
||||
// #2 (region bounds).
|
||||
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
|
||||
// construct a type `a1` which is a version of
|
||||
// `a` using the upcast bounds from `b`
|
||||
let bounds_a1 = ty::ExistentialBounds {
|
||||
// From type b
|
||||
region_bound: data_b.bounds.region_bound,
|
||||
builtin_bounds: data_b.bounds.builtin_bounds,
|
||||
|
||||
// From type a
|
||||
projection_bounds: data_a.bounds.projection_bounds.clone(),
|
||||
};
|
||||
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
|
||||
|
||||
// relate `a1` to `b`
|
||||
let result = self.fcx.infcx().commit_if_ok(|_| {
|
||||
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
|
||||
try!(self.outlives(infer::RelateObjectBound(self.origin.span()),
|
||||
data_a.bounds.region_bound,
|
||||
data_b.bounds.region_bound));
|
||||
self.subtype(ty_a1, ty_b)
|
||||
});
|
||||
|
||||
// if that was successful, we have a coercion
|
||||
match result {
|
||||
Ok(_) => Some(ty_b),
|
||||
Err(_) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(_, &ty::ty_trait(_)) => {
|
||||
assert!(self.unsizing_obligation.get().is_none());
|
||||
self.unsizing_obligation.set(Some(a));
|
||||
Some(ty_b)
|
||||
}
|
||||
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
||||
if did_a == did_b => {
|
||||
debug!("unsizing a struct");
|
||||
// Try unsizing each type param in turn to see if we end up with ty_b.
|
||||
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
|
||||
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
|
||||
assert!(ty_substs_a.len() == ty_substs_b.len());
|
||||
|
||||
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
|
||||
for (i, (tp_a, tp_b)) in tps {
|
||||
if self.subtype(*tp_a, *tp_b).is_ok() {
|
||||
continue;
|
||||
}
|
||||
if let Some(new_tp) = self.unsize_ty(tp_a, tp_b) {
|
||||
// Check that the whole types match.
|
||||
let mut new_substs = substs_a.clone();
|
||||
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
|
||||
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
|
||||
if self.subtype(ty, ty_b).is_err() {
|
||||
debug!("Unsized type parameter '{}', but still \
|
||||
could not match types {} and {}",
|
||||
ppaux::ty_to_string(tcx, tp_a),
|
||||
ppaux::ty_to_string(tcx, ty),
|
||||
ppaux::ty_to_string(tcx, ty_b));
|
||||
// We can only unsize a single type parameter, so
|
||||
// if we unsize one and it doesn't give us the
|
||||
// type we want, then we won't succeed later.
|
||||
break;
|
||||
}
|
||||
|
||||
return Some(ty);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
fn coerce_from_fn_pointer(&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
|
||||
@ -496,41 +433,24 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> RelateResult<'tcx, ()> {
|
||||
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
|
||||
let (adjustment, unsizing_obligation) = try!(indent(|| {
|
||||
let mut unsizing_obligations = vec![];
|
||||
let adjustment = try!(indent(|| {
|
||||
fcx.infcx().commit_if_ok(|_| {
|
||||
let coerce = Coerce {
|
||||
fcx: fcx,
|
||||
origin: infer::ExprAssignable(expr.span),
|
||||
unsizing_obligation: Cell::new(None)
|
||||
unsizing_obligations: RefCell::new(vec![])
|
||||
};
|
||||
Ok((try!(coerce.coerce(expr, a, b)),
|
||||
coerce.unsizing_obligation.get()))
|
||||
let adjustment = try!(coerce.coerce(expr, a, b));
|
||||
unsizing_obligations = coerce.unsizing_obligations.into_inner();
|
||||
Ok(adjustment)
|
||||
})
|
||||
}));
|
||||
|
||||
if let Some(AdjustDerefRef(auto)) = adjustment {
|
||||
if let (Some(source), Some(target)) = (unsizing_obligation, auto.unsize) {
|
||||
let target = ty::deref(target, true)
|
||||
.expect("coercion: unsizing got non-pointer target type").ty;
|
||||
let target = ty::struct_tail(fcx.tcx(), target);
|
||||
if let ty::ty_trait(ref ty_trait) = target.sty {
|
||||
vtable::check_object_safety(fcx.tcx(), ty_trait, expr.span);
|
||||
|
||||
// If the type is `Foo+'a`, ensures that the type
|
||||
// being cast to `Foo+'a` implements `Foo`:
|
||||
vtable::register_object_cast_obligations(fcx,
|
||||
expr.span,
|
||||
ty_trait,
|
||||
source);
|
||||
|
||||
// If the type is `Foo+'a`, ensures that the type
|
||||
// being cast to `Foo+'a` outlives `'a`:
|
||||
let cause = traits::ObligationCause {
|
||||
span: expr.span,
|
||||
body_id: fcx.body_id,
|
||||
code: traits::ObjectCastObligation(source)
|
||||
};
|
||||
fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause);
|
||||
if auto.unsize.is_some() {
|
||||
for obligation in unsizing_obligations {
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::FnCtxt;
|
||||
use check::vtable;
|
||||
use check::vtable::select_new_fcx_obligations;
|
||||
use middle::def;
|
||||
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
|
||||
use middle::subst;
|
||||
@ -233,7 +231,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// FIXME(#18653) -- Try to resolve obligations, giving us more
|
||||
// typing information, which can sometimes be needed to avoid
|
||||
// pathological region inference failures.
|
||||
vtable::select_new_fcx_obligations(fcx);
|
||||
fcx.select_new_obligations();
|
||||
|
||||
// Insert any adjustments needed (always an autoref of some mutability).
|
||||
match self_expr {
|
||||
|
@ -93,7 +93,7 @@ use middle::pat_util::{self, pat_id_map};
|
||||
use middle::privacy::{AllPublic, LastMod};
|
||||
use middle::region::{self, CodeExtent};
|
||||
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
|
||||
use middle::traits;
|
||||
use middle::traits::{self, report_fulfillment_errors};
|
||||
use middle::ty::{FnSig, GenericPredicates, TypeScheme};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
|
||||
@ -129,7 +129,6 @@ use syntax::visit::{self, Visitor};
|
||||
mod assoc;
|
||||
pub mod dropck;
|
||||
pub mod _match;
|
||||
pub mod vtable;
|
||||
pub mod writeback;
|
||||
pub mod regionck;
|
||||
pub mod coercion;
|
||||
@ -525,9 +524,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig,
|
||||
decl, fn_id, body, &inh);
|
||||
|
||||
vtable::select_all_fcx_obligations_and_apply_defaults(&fcx);
|
||||
fcx.select_all_obligations_and_apply_defaults();
|
||||
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
|
||||
vtable::select_all_fcx_obligations_or_error(&fcx);
|
||||
fcx.select_all_obligations_or_error();
|
||||
fcx.check_casts();
|
||||
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
@ -1290,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// If not, try resolving any new fcx obligations that have cropped up.
|
||||
vtable::select_new_fcx_obligations(self);
|
||||
self.select_new_obligations();
|
||||
ty = self.infcx().resolve_type_vars_if_possible(&ty);
|
||||
if !ty::type_has_ty_infer(ty) {
|
||||
debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
|
||||
@ -1301,7 +1300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// possible. This can help substantially when there are
|
||||
// indirect dependencies that don't seem worth tracking
|
||||
// precisely.
|
||||
vtable::select_fcx_obligations_where_possible(self);
|
||||
self.select_obligations_where_possible();
|
||||
ty = self.infcx().resolve_type_vars_if_possible(&ty);
|
||||
|
||||
debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
|
||||
@ -1817,6 +1816,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
deferred_cast_checks.clear();
|
||||
}
|
||||
|
||||
fn select_all_obligations_and_apply_defaults(&self) {
|
||||
debug!("select_all_obligations_and_apply_defaults");
|
||||
|
||||
self.select_obligations_where_possible();
|
||||
self.default_type_parameters();
|
||||
self.select_obligations_where_possible();
|
||||
}
|
||||
|
||||
fn select_all_obligations_or_error(&self) {
|
||||
debug!("select_all_obligations_or_error");
|
||||
|
||||
// upvar inference should have ensured that all deferred call
|
||||
// resolutions are handled by now.
|
||||
assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
|
||||
|
||||
self.select_all_obligations_and_apply_defaults();
|
||||
let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
|
||||
match fulfillment_cx.select_all_or_error(self.infcx(), self) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Select as many obligations as we can at present.
|
||||
fn select_obligations_where_possible(&self) {
|
||||
match
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_where_possible(self.infcx(), self)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to select any fcx obligation that we haven't tried yet, in an effort
|
||||
/// to improve inference. You could just call
|
||||
/// `select_obligations_where_possible` except that it leads to repeated
|
||||
/// work.
|
||||
fn select_new_obligations(&self) {
|
||||
match
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_new_obligations(self.infcx(), self)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
|
||||
@ -1880,11 +1930,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
|
||||
let resolved_t = match unresolved_type_action {
|
||||
UnresolvedTypeAction::Error => {
|
||||
let resolved_t = structurally_resolved_type(fcx, sp, t);
|
||||
if ty::type_is_error(resolved_t) {
|
||||
return (resolved_t, autoderefs, None);
|
||||
}
|
||||
resolved_t
|
||||
structurally_resolved_type(fcx, sp, t)
|
||||
}
|
||||
UnresolvedTypeAction::Ignore => {
|
||||
// We can continue even when the type cannot be resolved
|
||||
@ -1894,6 +1940,9 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
fcx.resolve_type_vars_if_possible(t)
|
||||
}
|
||||
};
|
||||
if ty::type_is_error(resolved_t) {
|
||||
return (resolved_t, autoderefs, None);
|
||||
}
|
||||
|
||||
match should_stop(resolved_t, autoderefs) {
|
||||
Some(x) => return (resolved_t, autoderefs, Some(x)),
|
||||
@ -2263,7 +2312,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
// an "opportunistic" vtable resolution of any trait bounds on
|
||||
// the call. This helps coercions.
|
||||
if check_blocks {
|
||||
vtable::select_new_fcx_obligations(fcx);
|
||||
fcx.select_new_obligations();
|
||||
}
|
||||
|
||||
// For variadic functions, we don't have a declared type for all of
|
||||
@ -4059,7 +4108,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
||||
check_expr_with_hint(fcx, e, declty);
|
||||
demand::coerce(fcx, e.span, declty, e);
|
||||
vtable::select_all_fcx_obligations_or_error(fcx);
|
||||
fcx.select_all_obligations_or_error();
|
||||
fcx.check_casts();
|
||||
regionck::regionck_expr(fcx, e);
|
||||
writeback::resolve_type_vars_in_expr(fcx, e);
|
||||
@ -4928,6 +4977,14 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
"breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)),
|
||||
"size_of" |
|
||||
"pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize),
|
||||
"size_of_val" | "min_align_of_val" => {
|
||||
(1, vec![
|
||||
ty::mk_imm_rptr(tcx,
|
||||
tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
|
||||
ty::BrAnon(0))),
|
||||
param(ccx, 0))
|
||||
], ccx.tcx.types.usize)
|
||||
}
|
||||
"init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)),
|
||||
"uninit" => (1, Vec::new(), param(ccx, 0)),
|
||||
"forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)),
|
||||
@ -4943,6 +5000,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
|
||||
),
|
||||
ty::mk_nil(tcx))
|
||||
}
|
||||
"drop_in_place" => {
|
||||
(1, vec![ty::mk_mut_ptr(tcx, param(ccx, 0))], ty::mk_nil(tcx))
|
||||
}
|
||||
"needs_drop" => (1, Vec::new(), ccx.tcx.types.bool),
|
||||
|
||||
"type_name" => (1, Vec::new(), ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic),
|
||||
|
@ -85,7 +85,6 @@
|
||||
use astconv::AstConv;
|
||||
use check::dropck;
|
||||
use check::FnCtxt;
|
||||
use check::vtable;
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use middle::implicator;
|
||||
use middle::mem_categorization as mc;
|
||||
@ -312,7 +311,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
||||
// region checking can introduce new pending obligations
|
||||
// which, when processed, might generate new region
|
||||
// obligations. So make sure we process those.
|
||||
vtable::select_all_fcx_obligations_or_error(self.fcx);
|
||||
self.fcx.select_all_obligations_or_error();
|
||||
|
||||
// Make a copy of the region obligations vec because we'll need
|
||||
// to be able to borrow the fulfillment-cx below when projecting.
|
||||
|
@ -1,186 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use check::FnCtxt;
|
||||
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::report_fulfillment_errors;
|
||||
use middle::ty::{self, Ty, AsPredicate};
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
|
||||
// Check that a trait is 'object-safe'. This should be checked whenever a trait object
|
||||
// is created (by casting or coercion, etc.). A trait is object-safe if all its
|
||||
// methods are object-safe. A trait method is object-safe if it does not take
|
||||
// self by value, has no type parameters and does not use the `Self` type, except
|
||||
// in self position.
|
||||
pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait: &ty::TyTrait<'tcx>,
|
||||
span: Span)
|
||||
{
|
||||
let trait_def_id = object_trait.principal_def_id();
|
||||
|
||||
if traits::is_object_safe(tcx, trait_def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_err!(tcx.sess, span, E0038,
|
||||
"cannot convert to a trait object because trait `{}` is not object-safe",
|
||||
ty::item_path_str(tcx, trait_def_id));
|
||||
|
||||
let violations = traits::object_safety_violations(tcx, trait_def_id);
|
||||
for violation in violations {
|
||||
match violation {
|
||||
ObjectSafetyViolation::SizedSelf => {
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
"the trait cannot require that `Self : Sized`");
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::SupertraitSelf => {
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
"the trait cannot use `Self` as a type parameter \
|
||||
in the supertrait listing");
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
&format!("method `{}` has no receiver",
|
||||
method.name.user_string(tcx)));
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
&format!("method `{}` references the `Self` type \
|
||||
in its arguments or return type",
|
||||
method.name.user_string(tcx)));
|
||||
}
|
||||
|
||||
ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
&format!("method `{}` has generic type parameters",
|
||||
method.name.user_string(tcx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
object_trait: &ty::TyTrait<'tcx>,
|
||||
referent_ty: Ty<'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
// We can only make objects from sized types.
|
||||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
ty::BoundSized,
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));
|
||||
|
||||
// This is just for better error reporting. Kinda goofy. The object type stuff
|
||||
// needs some refactoring so there is a more convenient type to pass around.
|
||||
let object_trait_ty =
|
||||
ty::mk_trait(fcx.tcx(),
|
||||
object_trait.principal.clone(),
|
||||
object_trait.bounds.clone());
|
||||
|
||||
debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
|
||||
referent_ty.repr(fcx.tcx()),
|
||||
object_trait_ty.repr(fcx.tcx()));
|
||||
|
||||
let cause = ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty));
|
||||
|
||||
// Create the obligation for casting from T to Trait.
|
||||
let object_trait_ref =
|
||||
object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
|
||||
let object_obligation =
|
||||
Obligation::new(cause.clone(), object_trait_ref.as_predicate());
|
||||
fcx.register_predicate(object_obligation);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
// bounds attached to the object cast. (In other words, if the
|
||||
// object type is Foo+Send, this would create an obligation
|
||||
// for the Send check.)
|
||||
for builtin_bound in &object_trait.bounds.builtin_bounds {
|
||||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
builtin_bound,
|
||||
cause.clone());
|
||||
}
|
||||
|
||||
// Create obligations for the projection predicates.
|
||||
let projection_bounds =
|
||||
object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
|
||||
for projection_bound in &projection_bounds {
|
||||
let projection_obligation =
|
||||
Obligation::new(cause.clone(), projection_bound.as_predicate());
|
||||
fcx.register_predicate(projection_obligation);
|
||||
}
|
||||
|
||||
object_trait_ref
|
||||
}
|
||||
|
||||
pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
|
||||
debug!("select_all_fcx_obligations_and_apply_defaults");
|
||||
|
||||
select_fcx_obligations_where_possible(fcx);
|
||||
fcx.default_type_parameters();
|
||||
select_fcx_obligations_where_possible(fcx);
|
||||
}
|
||||
|
||||
pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
||||
debug!("select_all_fcx_obligations_or_error");
|
||||
|
||||
// upvar inference should have ensured that all deferred call
|
||||
// resolutions are handled by now.
|
||||
assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
|
||||
|
||||
select_all_fcx_obligations_and_apply_defaults(fcx);
|
||||
let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
|
||||
let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
|
||||
match r {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Select as many obligations as we can at present.
|
||||
pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
|
||||
{
|
||||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_where_possible(fcx.infcx(), fcx)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
|
||||
/// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
|
||||
/// work.
|
||||
pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
|
||||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_new_obligations(fcx.infcx(), fcx)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
|
||||
use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
|
||||
use constrained_type_params::{identify_constrained_type_params, Parameter};
|
||||
use CrateCtxt;
|
||||
use middle::region;
|
||||
@ -151,7 +151,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
let inh = Inherited::new(ccx.tcx, param_env);
|
||||
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
|
||||
f(self, &fcx);
|
||||
vtable::select_all_fcx_obligations_or_error(&fcx);
|
||||
fcx.select_all_obligations_or_error();
|
||||
regionck::regionck_item(&fcx, item);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,9 @@
|
||||
// mappings. That mapping code resides here.
|
||||
|
||||
|
||||
use middle::lang_items::UnsizeTraitLangItem;
|
||||
use middle::subst::{self, Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::RegionEscape;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
|
||||
use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
|
||||
@ -27,9 +29,9 @@ use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int};
|
||||
use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn};
|
||||
use middle::ty::ty_projection;
|
||||
use middle::ty;
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use CrateCtxt;
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::infer::new_infer_ctxt;
|
||||
use middle::infer::{self, InferCtxt, new_infer_ctxt};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{Crate, DefId};
|
||||
@ -133,6 +135,10 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
||||
|
||||
// Check to make sure implementations of `Copy` are legal.
|
||||
self.check_implementations_of_copy();
|
||||
|
||||
// Check to make sure implementations of `CoerceUnsized` are legal
|
||||
// and collect the necessary information from them.
|
||||
self.check_implementations_of_coerce_unsized();
|
||||
}
|
||||
|
||||
fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) {
|
||||
@ -419,6 +425,157 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Process implementations of the built-in trait `CoerceUnsized`.
|
||||
fn check_implementations_of_coerce_unsized(&self) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
|
||||
Some(id) => id,
|
||||
None => return,
|
||||
};
|
||||
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
|
||||
Ok(id) => id,
|
||||
Err(err) => {
|
||||
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
|
||||
}
|
||||
};
|
||||
|
||||
let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait);
|
||||
|
||||
trait_def.for_each_impl(tcx, |impl_did| {
|
||||
debug!("check_implementations_of_coerce_unsized: impl_did={}",
|
||||
impl_did.repr(tcx));
|
||||
|
||||
if impl_did.krate != ast::LOCAL_CRATE {
|
||||
debug!("check_implementations_of_coerce_unsized(): impl not \
|
||||
in this crate");
|
||||
return;
|
||||
}
|
||||
|
||||
let source = ty::lookup_item_type(tcx, impl_did).ty;
|
||||
let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx,
|
||||
impl_did.node);
|
||||
let target = *trait_ref.substs.types.get(subst::TypeSpace, 0);
|
||||
debug!("check_implementations_of_coerce_unsized: {} -> {} (bound)",
|
||||
source.repr(tcx), target.repr(tcx));
|
||||
|
||||
let span = tcx.map.span(impl_did.node);
|
||||
let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
|
||||
let source = source.subst(tcx, ¶m_env.free_substs);
|
||||
let target = target.subst(tcx, ¶m_env.free_substs);
|
||||
assert!(!source.has_escaping_regions());
|
||||
|
||||
debug!("check_implementations_of_coerce_unsized: {} -> {} (free)",
|
||||
source.repr(tcx), target.repr(tcx));
|
||||
|
||||
let infcx = new_infer_ctxt(tcx);
|
||||
|
||||
let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>,
|
||||
mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
|
||||
if (mt_a.mutbl, mt_b.mutbl) == (ast::MutImmutable, ast::MutMutable) {
|
||||
infcx.report_mismatched_types(span, mk_ptr(mt_b.ty),
|
||||
target, &ty::terr_mutability);
|
||||
}
|
||||
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
||||
};
|
||||
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
|
||||
(&ty::ty_uniq(a), &ty::ty_uniq(b)) => (a, b, unsize_trait, None),
|
||||
|
||||
(&ty::ty_rptr(r_a, mt_a), &ty::ty_rptr(r_b, mt_b)) => {
|
||||
infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a);
|
||||
check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_rptr(tcx, r_b, ty))
|
||||
}
|
||||
|
||||
(&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) |
|
||||
(&ty::ty_ptr(mt_a), &ty::ty_ptr(mt_b)) => {
|
||||
check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_ptr(tcx, ty))
|
||||
}
|
||||
|
||||
(&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => {
|
||||
if def_id_a != def_id_b {
|
||||
let source_path = ty::item_path_str(tcx, def_id_a);
|
||||
let target_path = ty::item_path_str(tcx, def_id_b);
|
||||
span_err!(tcx.sess, span, E0377,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures with the same \
|
||||
definition; expected {}, found {}",
|
||||
source_path, target_path);
|
||||
return;
|
||||
}
|
||||
|
||||
let origin = infer::Misc(span);
|
||||
let fields = ty::lookup_struct_fields(tcx, def_id_a);
|
||||
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
|
||||
let ty = ty::lookup_field_type_unsubstituted(tcx, def_id_a, f.id);
|
||||
let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b));
|
||||
if infcx.sub_types(false, origin, b, a).is_ok() {
|
||||
None
|
||||
} else {
|
||||
Some((i, a, b))
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
if diff_fields.is_empty() {
|
||||
span_err!(tcx.sess, span, E0374,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures with one field \
|
||||
being coerced, none found");
|
||||
return;
|
||||
} else if diff_fields.len() > 1 {
|
||||
span_err!(tcx.sess, span, E0375,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures with one field \
|
||||
being coerced, but {} fields need coercions: {}",
|
||||
diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| {
|
||||
let name = fields[i].name;
|
||||
format!("{} ({} to {})",
|
||||
if name == token::special_names::unnamed_field {
|
||||
i.to_string()
|
||||
} else {
|
||||
token::get_name(name).to_string()
|
||||
},
|
||||
a.repr(tcx),
|
||||
b.repr(tcx))
|
||||
}).collect::<Vec<_>>().connect(", "));
|
||||
return;
|
||||
}
|
||||
|
||||
let (i, a, b) = diff_fields[0];
|
||||
let kind = ty::CustomCoerceUnsized::Struct(i);
|
||||
(a, b, coerce_unsized_trait, Some(kind))
|
||||
}
|
||||
|
||||
_ => {
|
||||
span_err!(tcx.sess, span, E0376,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
|
||||
// Register an obligation for `A: Trait<B>`.
|
||||
let cause = traits::ObligationCause::misc(span, impl_did.node);
|
||||
let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id,
|
||||
0, source, vec![target]);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
|
||||
// Check that all transitive obligations are satisfied.
|
||||
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx, ¶m_env) {
|
||||
traits::report_fulfillment_errors(&infcx, &errors);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions.
|
||||
let mut free_regions = FreeRegionMap::new();
|
||||
free_regions.relate_free_regions_from_predicates(tcx, ¶m_env.caller_bounds);
|
||||
infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node);
|
||||
|
||||
if let Some(kind) = kind {
|
||||
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) {
|
||||
|
@ -316,12 +316,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow *all* explicit impls of `Sized` for now.
|
||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
|
||||
span_err!(self.tcx.sess, item.span, E0322,
|
||||
"explicit impls for the `Sized` trait are not permitted");
|
||||
return;
|
||||
}
|
||||
if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
|
||||
span_err!(self.tcx.sess, item.span, E0328,
|
||||
"explicit impls for the `Unsize` trait are not permitted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ast::ItemDefaultImpl(..) => {
|
||||
// "Trait" impl
|
||||
|
@ -309,7 +309,6 @@ register_diagnostics! {
|
||||
E0034, // multiple applicable methods in scope
|
||||
E0035, // does not take type parameters
|
||||
E0036, // incorrect number of type parameters given for this method
|
||||
E0038, // cannot convert to a trait object because trait is not object-safe
|
||||
E0040, // explicit use of destructor method
|
||||
E0044, // foreign items may not have type parameters
|
||||
E0045, // variadic function must have C calling convention
|
||||
@ -445,10 +444,20 @@ register_diagnostics! {
|
||||
E0325, // implemented an associated type when another trait item expected
|
||||
E0326, // associated const implemented with different type from trait
|
||||
E0327, // referred to method instead of constant in match pattern
|
||||
E0328, // cannot implement Unsize explicitly
|
||||
E0366, // dropck forbid specialization to concrete type or region
|
||||
E0367, // dropck forbid specialization to predicate not in struct/enum
|
||||
E0368, // binary operation `<op>=` cannot be applied to types
|
||||
E0369, // binary operation `<op>` cannot be applied to types
|
||||
E0371, // impl Trait for Trait is illegal
|
||||
E0372 // impl Trait for Trait where Trait is not object safe
|
||||
E0372, // impl Trait for Trait where Trait is not object safe
|
||||
E0374, // the trait `CoerceUnsized` may only be implemented for a coercion
|
||||
// between structures with one field being coerced, none found
|
||||
E0375, // the trait `CoerceUnsized` may only be implemented for a coercion
|
||||
// between structures with one field being coerced, but multiple
|
||||
// fields need coercions
|
||||
E0376, // the trait `CoerceUnsized` may only be implemented for a coercion
|
||||
// between structures
|
||||
E0377 // the trait `CoerceUnsized` may only be implemented for a coercion
|
||||
// between structures with the same definition
|
||||
}
|
||||
|
@ -531,15 +531,16 @@ mod tests {
|
||||
assert_eq!(*lock, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutex_unsized() {
|
||||
let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
|
||||
{
|
||||
let b = &mut *mutex.lock().unwrap();
|
||||
b[0] = 4;
|
||||
b[2] = 5;
|
||||
}
|
||||
let comp: &[i32] = &[4, 2, 5];
|
||||
assert_eq!(&*mutex.lock().unwrap(), comp);
|
||||
}
|
||||
// FIXME(#25351) needs deeply nested coercions of DST structs.
|
||||
// #[test]
|
||||
// fn test_mutex_unsized() {
|
||||
// let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
|
||||
// {
|
||||
// let b = &mut *mutex.lock().unwrap();
|
||||
// b[0] = 4;
|
||||
// b[2] = 5;
|
||||
// }
|
||||
// let comp: &[i32] = &[4, 2, 5];
|
||||
// assert_eq!(&*mutex.lock().unwrap(), comp);
|
||||
// }
|
||||
}
|
||||
|
@ -573,17 +573,18 @@ mod tests {
|
||||
assert_eq!(*lock, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rwlock_unsized() {
|
||||
let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
|
||||
{
|
||||
let b = &mut *rw.write().unwrap();
|
||||
b[0] = 4;
|
||||
b[2] = 5;
|
||||
}
|
||||
let comp: &[i32] = &[4, 2, 5];
|
||||
assert_eq!(&*rw.read().unwrap(), comp);
|
||||
}
|
||||
// FIXME(#25351) needs deeply nested coercions of DST structs.
|
||||
// #[test]
|
||||
// fn test_rwlock_unsized() {
|
||||
// let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
|
||||
// {
|
||||
// let b = &mut *rw.write().unwrap();
|
||||
// b[0] = 4;
|
||||
// b[2] = 5;
|
||||
// }
|
||||
// let comp: &[i32] = &[4, 2, 5];
|
||||
// assert_eq!(&*rw.read().unwrap(), comp);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_rwlock_try_write() {
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
||||
// n == m
|
||||
let &x = &1 as &T; //~ ERROR type `&T` cannot be dereferenced
|
||||
let &&x = &(&1 as &T); //~ ERROR type `&T` cannot be dereferenced
|
||||
let box x = box 1 as Box<T>; //~ ERROR type `Box<T>` cannot be dereferenced
|
||||
let box x = box 1 as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
|
||||
|
||||
// n > m
|
||||
let &&x = &1 as &T;
|
||||
|
@ -33,18 +33,4 @@ pub fn main() {
|
||||
let x: &mut T = &S; //~ ERROR mismatched types
|
||||
let x: *mut T = &S; //~ ERROR mismatched types
|
||||
let x: *mut S = &S; //~ ERROR mismatched types
|
||||
|
||||
// The below four sets of tests test that we cannot implicitly deref a *-ptr
|
||||
// during a coercion.
|
||||
let x: *const S = &S;
|
||||
let y: *const T = x; //~ ERROR mismatched types
|
||||
|
||||
let x: *mut S = &mut S;
|
||||
let y: *mut T = x; //~ ERROR mismatched types
|
||||
|
||||
let x: *const Foo<S> = &Foo {f: S};
|
||||
let y: *const Foo<T> = x; //~ ERROR mismatched types
|
||||
|
||||
let x: *mut Foo<S> = &mut Foo {f: S};
|
||||
let y: *mut Foo<T> = x; //~ ERROR mismatched types
|
||||
}
|
||||
|
@ -15,17 +15,13 @@ pub trait Trait {}
|
||||
fn main() {
|
||||
let a: &[i32] = &[1, 2, 3];
|
||||
let b: Box<[i32]> = Box::new([1, 2, 3]);
|
||||
let p = a as *const [i32];
|
||||
let q = a.as_ptr();
|
||||
|
||||
a as usize; //~ ERROR illegal cast
|
||||
b as usize; //~ ERROR illegal cast
|
||||
p as usize; //~ ERROR illegal cast
|
||||
a as usize; //~ ERROR non-scalar cast
|
||||
b as usize; //~ ERROR non-scalar cast
|
||||
|
||||
// #22955
|
||||
q as *const [i32]; //~ ERROR illegal cast
|
||||
let a: usize = 42;
|
||||
a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
|
||||
|
||||
// #21397
|
||||
let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast
|
||||
let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast
|
||||
let a: *const u8 = &42;
|
||||
a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ struct Homura;
|
||||
|
||||
fn akemi(homura: Homura) {
|
||||
let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method
|
||||
madoka.clone();
|
||||
madoka.clone(); //~ ERROR the type of this value must be known in this context
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -12,6 +12,5 @@ fn main() {
|
||||
for (ref i,) in [].iter() { //~ ERROR: type mismatch resolving
|
||||
i.clone();
|
||||
//~^ ERROR: the type of this value must be known in this context
|
||||
//~| ERROR: reached the recursion limit while auto-dereferencing
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ fn main() {
|
||||
let ptr: *mut () = 0 as *mut _;
|
||||
let _: &mut Fn() = unsafe {
|
||||
&mut *(ptr as *mut Fn())
|
||||
//~^ ERROR illegal cast
|
||||
//~^ ERROR the trait `core::ops::Fn<()>` is not implemented
|
||||
//~| ERROR the trait `core::ops::FnOnce<()>` is not implemented
|
||||
};
|
||||
}
|
||||
|
@ -9,5 +9,5 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
0 as &std::any::Any; //~ ERROR illegal cast
|
||||
0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any`
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
|
||||
// which fails to type check.
|
||||
|
||||
ss
|
||||
//~^ ERROR lifetime of the source pointer does not outlive lifetime bound
|
||||
//~^ ERROR lifetime bound not satisfied
|
||||
//~| ERROR cannot infer
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
|
||||
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
|
||||
// is illegal.
|
||||
|
||||
ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound
|
||||
ss.r //~ ERROR lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
|
||||
@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
|
||||
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
|
||||
// Here we override the lifetimes explicitly, and so naturally we get an error.
|
||||
|
||||
ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound
|
||||
ss.r = b; //~ ERROR lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
|
||||
|
||||
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
|
||||
// A outlives 'a AND 'b...but not 'c.
|
||||
box v as Box<SomeTrait+'a> //~ ERROR lifetime of the source pointer does not outlive
|
||||
box v as Box<SomeTrait+'a> //~ ERROR lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
|
||||
|
||||
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
|
||||
// Without knowing 'a:'b, we can't coerce
|
||||
x //~ ERROR lifetime of the source pointer does not outlive
|
||||
x //~ ERROR lifetime bound not satisfied
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
|
||||
|
52
src/test/run-pass/dst-coerce-custom.rs
Normal file
52
src/test/run-pass/dst-coerce-custom.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test a very simple custom DST coercion.
|
||||
|
||||
#![feature(core)]
|
||||
|
||||
use std::ops::CoerceUnsized;
|
||||
use std::marker::Unsize;
|
||||
|
||||
struct Bar<T: ?Sized> {
|
||||
x: *const T,
|
||||
}
|
||||
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Bar<U>> for Bar<T> {}
|
||||
|
||||
trait Baz {
|
||||
fn get(&self) -> i32;
|
||||
}
|
||||
|
||||
impl Baz for i32 {
|
||||
fn get(&self) -> i32 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Arrays.
|
||||
let a: Bar<[i32; 3]> = Bar { x: &[1, 2, 3] };
|
||||
// This is the actual coercion.
|
||||
let b: Bar<[i32]> = a;
|
||||
|
||||
unsafe {
|
||||
assert_eq!((*b.x)[0], 1);
|
||||
assert_eq!((*b.x)[1], 2);
|
||||
assert_eq!((*b.x)[2], 3);
|
||||
}
|
||||
|
||||
// Trait objects.
|
||||
let a: Bar<i32> = Bar { x: &42 };
|
||||
let b: Bar<Baz> = a;
|
||||
unsafe {
|
||||
assert_eq!((*b.x).get(), 42);
|
||||
}
|
||||
}
|
39
src/test/run-pass/dst-coerce-rc.rs
Normal file
39
src/test/run-pass/dst-coerce-rc.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test a very simple custom DST coercion.
|
||||
|
||||
#![feature(core)]
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
trait Baz {
|
||||
fn get(&self) -> i32;
|
||||
}
|
||||
|
||||
impl Baz for i32 {
|
||||
fn get(&self) -> i32 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a: Rc<[i32; 3]> = Rc::new([1, 2, 3]);
|
||||
let b: Rc<[i32]> = a;
|
||||
assert_eq!(b[0], 1);
|
||||
assert_eq!(b[1], 2);
|
||||
assert_eq!(b[2], 3);
|
||||
|
||||
let a: Rc<i32> = Rc::new(42);
|
||||
let b: Rc<Baz> = a.clone();
|
||||
assert_eq!(b.get(), 42);
|
||||
|
||||
let _c = b.clone();
|
||||
}
|
49
src/test/run-pass/fat-ptr-cast.rs
Normal file
49
src/test/run-pass/fat-ptr-cast.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core)]
|
||||
|
||||
use std::mem;
|
||||
use std::raw;
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for Bar {}
|
||||
|
||||
fn main() {
|
||||
// Test we can turn a fat pointer to array back into a thin pointer.
|
||||
let a: *const [i32] = &[1, 2, 3];
|
||||
let b = a as *const [i32; 2];
|
||||
unsafe {
|
||||
assert!(*b == [1, 2]);
|
||||
}
|
||||
|
||||
// Test conversion to an address (usize).
|
||||
let a: *const [i32; 3] = &[1, 2, 3];
|
||||
let b: *const [i32] = a;
|
||||
assert!(a as usize == b as usize);
|
||||
|
||||
// And conversion to a void pointer/address for trait objects too.
|
||||
let a: *mut Foo = &mut Bar;
|
||||
let b = a as *mut ();
|
||||
let c = a as usize;
|
||||
|
||||
let d = unsafe {
|
||||
let r: raw::TraitObject = mem::transmute(a);
|
||||
r.data
|
||||
};
|
||||
|
||||
assert!(b == d);
|
||||
assert!(c == d as usize);
|
||||
}
|
Loading…
Reference in New Issue
Block a user